ㅇ 프로젝트/(Toy)_project

배송로봇 모니터링 프로그램 만들기 1장 프로젝트 설계

BrainKimDu 2023. 6. 28. 22:11

프로젝트 목적

- ROS 활용능력을 키우기위함
- 소프트웨어 아키텍처 설계 능력을 기르기 위함
- C++ 객체지향 능력을 향상시키기 위함
- 기존의 코드들을 재활용하면서 접근하여 하나의 완성작을 만들어보고자 함.

 

프로젝트 기간

2023년 6월 28일부터 7월 30일까지 업무 외 별도로 진행

 

프로젝트 인원

개인 프로젝트

 

 

프로젝트 설계

요구사항

1. 시뮬레이션 상에서의 서빙로봇을 만들고 싶습니다. (로봇은 한 대만 사용합니다.)
2. 손님은 키오스크에서 주문을 진행함. (키오스크에서 객체지향의 특징이 잘 드러나게 설계할 것)
3. 그리고 손님이 자리에 앉으면 주방에서 음식이 만들어지고, 로봇이 이를 손님에게 전달함.
4. 남은 배터리 용량, 로봇의 현재위치, 로봇의 현재 명령 수행과정 등등을 모니터링할 수 있어야합니다. 
5. 배터리가 부족하면 자동으로 충전기가 있는 곳으로 움직이며 충전기와 통신을 진행합니다. 
6. 데이터베이스, 장애물 회피는 제외합니다.

추가. 키오스크의 역할이 필요함.

별도의 QT 작업은 하지 않을 예정

 

아키텍처 설계

전체적인 아키텍처 설계를 진행하고자 합니다.
현재까지 요구사항을 보았을 때 우리가 구현해야할 모듈은 총 5가지로 구분될 수 있습니다.

1. 키오스크와 모니터링에서 객체지향적인 특징을 보일 수 있으며
2. 충전기와 로봇은 ROS간의 통신을 이용한다.
3. 모니터링과 로봇의 통신또한 ROS 통신을 이용한다.

 

1. 모니터링
(C++)

로봇에 다음의 명령을 내릴 수 있어야합니다.
1. 명령 수행, 명령 취소
2. 로봇의 현재 상태 지속적으로 모니터링

모니터링은 또한 다음의 동작이 가능해야합니다.
각 테이블의 정보 (방문 시간, 체류시간, 현재 주문한 음식, 테이블당 계산해야할 금액 )
키오스크에 전달된 주문내역을 주방에 알려야합니다.
주방에 만들어진 음식을 모아 테이블에 가져다주고 와야함.

2. 로봇 
(C++, ROS2, Python)

모니터링으로부터 명령이 내려지면 이를 수행하고 복귀해야합니다.
배터리가 적어지면 충전하기 위해 충전기로 복귀해야합니다.

3. 키오스크 (객체지향적 설계 필요)
(C++)

메뉴 추가가 쉬워야함

4. 주방 

키오스크 -> 모니터링 -> 순서대로 음식을 만들고 이를 모니터링에게 알려야함

5. 충전기 (ROS2)

로봇이 일정영역에 도달하면 로봇에게 전력 1을 보내고 로봇은 ACK를 보내면서 100까지 충전시킴
로봇이 충전기 다되면 로봇에게 알려야함. 로봇에게 남은 시간을 알릴 수 있어야함. 

 

 

 

유저의 입장에서 본 UML

설계에서 명심할 것은 UML은 절대적인 것은 아니고. 언제든지 바뀔 수 있습니다.

유저의 입장에서 생각해보면 프로젝트는 위와 같이 아주 간단한 플로우로 흘러갑니다.  그러면 유저가 주문을 완료하고 테이블에 앉는과정까지를 설계해봅시다.

 

키오스크의 동작에서 본 UML

고려사항
- 키오스크는 우선 임베디드 시스템이다. 그러니 하드웨어 성능이 제한적인 상황이라는 것을 인지하고 코드를 작성해야한다.
- 주문이 완료되는 경우 테이블 번호를 줄 수 없다.  자리가 없을 경우 유저를 기다리게 해야하기 때문이다. 그러니 키오스크로 주문을 하는 초기에 키오스크는 모니터링앱과 통신을 통해 빈 테이블을 리턴해주어야한다.
- 그러면 유저의 입장에서 한 번 UML을 설계해보자. 위와 같은 Activity Diagram을 사용한다.

키오스크의 클래스 설계

클래스 설계
ㅇ  메뉴명에 대한 클래스가 존재해야한다.
-> 나중에 음식을 추가하는 경우에 손쉽게 추가가 가능하기 때문이다. 
-> 유저가 매번 메뉴를 추가할 수는 없으니 데이터베이스를 활용해야한다. 데이터베이스에서 불러온 정보를 바탕으로 객체화가 이루어져야한다. 
- 메뉴 클래스는 다음의 맴버변수를 가져야한다.  
1. 메뉴의 이름
2. 가격
3. 재고
- 메뉴 클래스는 다음의 메소드를 가져야한다. 
1. 재고를 수정할 수 있어야한다. 다음의 경우 재고를 수정한다. 유저가 주문을 하는 경우, 모니터링앱으로 재고를 늘리는 경우

ㅇ 주문에 대한 클래스가 존재해야한다.
->처음에 유저에게 보여주기 위해서 DB에서 꺼내서 메뉴명을 객체화시켰다. 그럼 문제는 주문을 하면서 메뉴명의 객체를 다시 만들어서 저장시키면 문제가 생길 수 있다.
-> 그러면 주문하기 클래스가 먼저 실행되면서 메뉴 클래스의 객체를 생성하고 DB에서 정보를 최신화한다.  그리고 메뉴 클래스에 주문량이라는 맴버변수를 추가한다. 
- 주문 클래스는 다음의 맴버변수를 가진다.
1. 메뉴 클래스의 객체와 선택량을 가지는 HashMap
2. 총 가격
- 주문 클래스는 다음의 메소드를 가진다.
1. 총 가격 계산 및 print 하는 메소드
2. 객체의 선택량을 늘리는 메소드
3. 객체의 선택량을 줄이는 메소드
4. 객체의 선택량을 삭제하는 메소드

ㅇ 결제 클래스가 존재해야한다.
-> 결제에 대한 모듈이다. 유저에게 현금, 카드, 삼성페이를 입력받게 된다. (이 부분은 생략한다.)
-> 결제에 대한 성공은 50%의 확률로 진행한다. 50%의 확률로 결제에 성공하거나 실패하거나
-> 결제가 완료되면 결제가 완료되었다는 것을 리턴해주어야한다.
다음과 같은 멤버변수를 가진다.
-> 결제 성공여부
다음과 같은 메소드를 가진다.
-> 결제가 성공하는지 여부를 가리는 메소드
-> 결제진행 메소드

여기서 궁금증이 하나 생깁니다. 주문 클래스 내의 결제하기 메소드에서 결제 클래스의 객체를 객체화시킨 후 결제를 하게 되는 경우 이를 의존성 주입이라고 부른다고 한다. 이것이 정상적인 설계과정인가? 에 대한 궁금증입니다.

ChatGPT는 의존성 주입이라는 기술을 사용해야한다고 언급합니다.

보통의 코드를 작성할 때  이런식으로 코드가 작성이 되는데

class 결제하기 {
public:
	~~
}

class 주문하기 {
private 
	결제하기 결제;
public:
	주문하기(){
    	결제 = 결제하기();
    }
}

다음의 코드 작성은 주문하기 클래스 내에서 결제하기 클래스의 객체를 생성한 모습입니다. 이렇게 코드를 설계하는 것은 좋지 못하다고 언급합니다. 다음처럼 의존성 주입이라는 기술을 사용합니다.

class 결제하기 {
public:
	~~
}

class 주문하기 {
private 
	결제하기 결제;
public:
	주문하기(결제하기 결제){
    	this->결제 = 결제;
    }
}

다음과 같은 방식으로 지정한다고 합니다.

또한 main함수가 들어가는 새로운 클래스를 설계하라고 합니다.. 이렇게 해야 프로그램의 진입점을 관리하고 필요한 클래스와 객체를 생성하며 실행하는 것이 객체지향 프로그래밍의 원칙과 가독성을 유지하는데 도움이 된다고 언급합니다.

결제하기 클래스의 경우 신용카드, 삼성페이, 현금 등을 사용하게 됨으로 추상화(interface)에 의존을 시켜야한다고 한다고 합니다.

 

그래서 결론적으로 총 4개의 클래스가 만들어진다.
main 클래스 (main 클래스가 생겼음으로 주문하기에서 결제하기의 객체를 생성할 필요가 없다.)
주문하기 클래스
결제하기 클래스
요리 클래스

 

클래스 다이어그램을 그려보면 다음과 같다.

살짝 야매인 부분도 있다.

 

주방의 동작

키오스크에서 손님이 주문을 완료하면, 모니터링에 주문내역이 전달된다. 주문내역이 전달되면 모니터링은 주방으로 주문내역을 전달할 것입니다.

모니터링은 주방에 음식을 요청할 것이고, 주방은 간단하게 일정시간이 지난 후 음식을 완성하고 모니터링에 보고합니다.

여기서 난이도를 올리면 멀티 스레딩을 도입해서 주방장이 2명 이상이 움직이는 상황으로 만들 수 있을 것입니다. 이는 난이도를 생각해보고 진행하도록 합니다

정말 간단한 동작이라 굳이 UML까지는 필요가 없을 것 같습니다. C++을 이용하거나, 아두이노를 이용하거나 둘 중하나로 우선은 생각을 해야겠다고 생각합니다.

 

로봇의 동작

로봇의 동작을 FSM(유한상태머신)으로 확인하자.

이것도 야매긴하다..

 

모니터링 설계

앞서 설명했던 키오스크, 주방 로봇 등을 모두 모니터링할 수 있는 프로그램을 제작하려합니다.

1장에서 키오스크, 로봇, 주방 등등을 설계했고 이제 모니터링에 대한 설계를 진행합니다.

모니터링은 중앙 관제센터같은 역할을 담당하기 때문에 모듈간의 통신을 설명하는 것이 중요한 것으로 보입니다. 이를 잘 설명할 수 있는  UML은 무엇이 있을까요

찾아보니 통신 다이어그램이라는 UML이 존재하는 것 같으니 이를 한 번 활용해보도록 하겠습니다.

 

모니터링의 통신 다이어그램 작성

우선 시나리오를 다시 생각해봅시다. 다이어그램을 작성하기 전에 시나리오를 먼저 작성합니다.

0. 주방이 준비가 완료되었음을 모니터링에 알립니다.
0. 로봇이 준비 완료되었음을 모니터링에게 알립니다.
0. 충전기가 준비완료되었음을 로봇에게 알립니다.
0. 로봇이 충전기가 준비완료되었음을 로봇에게 알립니다. (근데, ROS상으로 통신이라면 생략가능)


1. 키오스크가 구동이 완료되고, 모니터링에 이를 알립니다. 
(처음 설계는 키오스크가 DB에서 직접 들고오는 것으로 설계를 했는데, 아무래도 모니터링에서 직접 보내주는 방향으로 진행을 해야할 것 같습니다.)
2. 키오스크는 제대로 받았음을 모니터링에 알립니다. 
3. 모니터링은 키오스크에 메뉴데이터와 테이블 정를 보냅니다. 
4. 키오스크는 제대로 받았음을 모니터링에 알립니다.


5. 키오스크에서 주문하기 버튼이 눌린 경우 모니터링에 현재 사용가능한 테이블과 이상유무를 요청합니다.
(여기서 이상유무는 품절과 같은 것을 말합니다.)
6.  모니터링에서 이용가능한 테이블과 이상유무를 보냅니다.
7. 키오스는 이용가능한 테이블을 토대로 고객에게 주문을 받습니다. 
8. 결제가 완료되는 경우 모니터링에 이를 보고합니다.

9. 모니터링은 만들어야할 음식을 주방에 보냅니다.
10. 주방에선 음식을 조리하고 모니터링을 호출합니다.
11. 모니터링은 테이블이 요청한 만큼의 음식이 나오게되면, 로봇을 호출합니다.
12. 호출을 받은 로봇은 주방으로 이동합니다.
(이동중이건 어떤 상황이건 로봇은 상태를 모니터링에 보고합니다.)

13. 로봇에 음식을 올렸다 가정하고, 전달받은 대로 테이블을 향해 이동합니다.
14. 테이블에 이동한 로봇은 원래자리로 복귀합니다.
(생각해보니까 로봇이 다먹은 그릇도 치워야하나.. 맞네)

15. 손님이 음식을 다먹으면 이를 모니터링에 알립니다.
16. 모니터링은 로봇을 호출하고 
17. 로봇은 테이블로 이동합니다. 
18. (이런일은 없지만) 로봇이 테이블에 이동한 후 일정시간 후에 다시 복귀한다.
19 로봇이 복귀를 완료하면 이를 모니터링에 알리고 테이블은 이용가능한 상태가 됩니다.

다이어그램을 작성하면 다음과 같습니다. 서로 주고받아야할 데이터는 이렇습니다. 

이제 이를 클래스끼리 설계를 진행해야하는데.. 너무나도 많습니다.

우선 키오스크, 주방, 로봇을 먼저 구현을 한 이후에 모니터링에 대한 상세 설계를 진행하도록 하겠습니다.