AUTOSAR
*ECU (Electronic Control Unit) : 차량 내 특정 기능을 제어하고 관리하는 작은 컴퓨터 -> 간단하게 말하자면, ST 칩이나 intel 칩 등의 하나의 MCU와 주변 회로 및 소프트웨어를 합쳐서 부르는 시스템 단
dawon-project.tistory.com
자율 주행 레이싱은 AUTOSAR를 기반으로한 PopcornSar를 DeepRacer에 적용해서 AI를 적용해서 자율 주행하게 만드는 종목이다.
필자는 이 프로젝트에서 Adaptive AUTOSAR 설계 및 구현, 전체 구동 시스템 설계 , Motor AA에서의 통신 코드 구현을 맡았다.
위의 그림처럼 DeepRacer는 ROS2를 이용해서 구동하는 Open Source 기반의 로봇이다.
이 DeepRacer에 우리가 직접 만든 AI를 적용하고 추가로 이 공모전에서는 AUTOSAR까지 적용해야 한다.
우선 해당 DeepRacer의 경우 단일 ECU라서 AUTOSAR를 적용하기에 부적합하다 생각할 수 있지만 이 DeepRacer가 아니라 실제 자동차처럼 더 커질 경우 그 환경에서는 하나의 ECU만으로 제어가 불가능할 것이고, 그럼 불가피하게 ECU의 개수가 많이 늘어나게 될 것이다.
그렇게 되더라도 AUTOSAR를 적용해서 새롭게 탄생시킨다면 DeepRacer가 더 커져 하드웨어의 스펙이 더 커지더라도 하드웨어적인 부분만 교체를 하면되고, 코드적인 부분에서는 유지보수하기 편해지고, 어떠한 상황에서도 구동시킬 수 있게되어서 의미가 있는 개발이라고 생각한다. 그래서 어떠한 환경에서도 무리없이 적용할 수 있도록 아래의 그림처럼 다시 재설계를 해보았다.
<AA를 적용해서 재설계한 관계도>
-> AUTOSAR와 각 개발자들이 담당한 부분의 알고리즘의 적용 후에 최종적으로 내보내는 DATA가 정의된 AA 간의 보내는 데이터 타입 형식만 맞춘다면 전체 시스템 상에 문제가 없도록 재구성
-> 내부 Classic AUTOSAR (DeepRacer 하드웨어 구조) 가 더 세분화되어 여러 개의 ECU 환경이 되더라도 문제가 없도록 구성
그리고 실제로 DeepRacer의 경우 단일 ECU 환경이기 때문에 다수의 ECU와 같은 환경을 조성해주기 위해 WebSocket 방식으로 msg를 전달할 수 있도록 아래의 그림처럼 설계하였다.
(실제로 다수의 ECU로 구성되어 있는 환경이라면 이 방식을 사용해도 되지만 각각의 ECU의 고유 ip를 사용해서 데이터를 주고 받는 방식으로 재설계하면 효율적일거라 생각한다.)
-> IP는 DeepRacer 구조상 하나의 ECU라서 같지만 포트를 다르게 할당해줌으로써 서로 통신을 주고 받을때 다른 데이터끼리 간섭되지 않도록 데이터가 구분되어 해당 AA에 잘 전달되도록 구성
-> 최종 목적지의 ECU인 Servo AA 부터는 기존의 ROS2 의 Subscribe와 Publish 통신 방식이 유지될 수 있도록 구성
이제 이렇게 설계된 것을 가지고 "PopcornSAR.io" 를 통해서 AUTOSAR를 구체적으로 설계했다.
<AUTOSAR 개발 방법>
- 센서 및 기능별 서로 다른 ECU에서 가공된 데이터들이 최종적으로 AA에게 전달되고 Port들을 통해 다른 AA로 전달해서 다른 ECU 간의 데이터 통신을 원활하게 하여 전체적인 시스템이 구동될 수 있도록 설계하였다.
- 각각의 AA -> 하나의 ECU에서 다른 ECU로 데이터를 원활하게 보내기 위해 데이터를 재가공하는 역할
- 각각의 Port -> AA를 통해 다른 ECU로 데이터를 전달하기 위한 통로
- 각 ECU에서 실행되는 노드가 AA로 전송한 데이터는 다른 ECU 간 데이터 송수신이 원활하도록 PARA 데이터 타입의 각기 정의된 구조체로 가공하기 편리하도록 데이터 타입을 설계하였다.
-> 이를 통해, 각 ECU가 주고 받는 데이터 형식이 표준화되어, ECU 간 통신 효율과 데이터 처리의 일관성을 높일 수 있도록 설계하였다.
-> 단일 ECU 환경 뿐만 아니라 다수의 ECU 환경에서도 적용할 수 있도록 설계하였다.
- 각각의 AA 끼리 통신할 때 Field 방식을 이용해서 Set 함수를 통해서 다음 AA로 보낼 Field 값을 세팅한 후에 Notifier를 통해 주기적으로 해당 필드 값을 보낼 수 있도록 구성하였다.
-> 만약 데이터 길이가 길어서 손실이 나거나 해당 AA에서 처리해야 하는 값이 잘못 입력되었을 경우 Consumer AA가 Provider에게 재요청을 할 수 있도록 구성하였다.
- AA 간의 통신 Service가 서로 방해되지 않도록 서로 다른 포트로 Mapping하였다.
- 데이터를 전송하는 PPort와 데이터를 수신 받는 RPort가 어떤 AA에 할당되어 있는지 알기 쉽도록 PortPrototype 명칭을 설계하였다.
- 각각의 AA가 초기 세팅될때 호출되는 Initialize 함수 안에 해당 ECU에서 실행해야 하 는 알고리즘 또는 데이터 가공 코드가 실행되도록 설정해 놓은 노드가 실행되도록 설계
->이유 : 모든 PKG가 EM에 의해 실행 되도록 구성되어 있다.

< DeepRacer 내부 ROS2 개발 방법 및 구현 >
- WebSocket 통신 방식으로 ROS2 Node가 AA의 해당 Service를 통해 데이터 송수신
- 모든 AA -> Server
- Ros2 노드-> Client로 설정
- 이유
- AA 간의 통신이 Some-Ip로 이루어지고 있기 때문에 Deepracer 패키지와 AA 간 의 통신 또한 Some-Ip로 구현하고자 하였다. 그러나 some/ip는 C++ 코드 이외에는 구현이 불가능하여, Python으로 이루어진 패키지(예: Navigation, model-optimizer 등)에서는 C++로 노드를 만들고 Python 코드와 연결한 후에 C++에서 Some-Ip를 구현해야 한다.
이로 인해 완전한 Some-Ip라고 보기 어려워 다른 통신방식인 WebSocket이란 통신방법을 찾게 되었다. WebSocket의 경우, 클라이언트를 종료하면 서버는 계속 동작하지만, 서버를 종료하면 클 라이언트도 종료되기 때문에, EM 실행 파일을 종료하면 나머지 모든 WebSocket이 종료된다. 따라서 AA와 ROS 2 노드의 통신을 WebSocket으로 구현하기로 하였다. - AA를 설계한 후에 Code Generate를 하면 각각의 AA 명으로 된 cpp 파일에 정의된 함수 들을 기반으로 main.cpp 실
- 기본적으로 Port 폴더에 있는 PortPrototype 명으로 만들어진 cpp 파일에서 AA끼리 데 이터를 원활하게 송수신할 수 있도록 기본 함수들이 정의되어 있다.
- AA 간의 통신이 Some-Ip로 이루어지고 있기 때문에 Deepracer 패키지와 AA 간 의 통신 또한 Some-Ip로 구현하고자 하였다. 그러나 some/ip는 C++ 코드 이외에는 구현이 불가능하여, Python으로 이루어진 패키지(예: Navigation, model-optimizer 등)에서는 C++로 노드를 만들고 Python 코드와 연결한 후에 C++에서 Some-Ip를 구현해야 한다.
- 이유
- Pport 를 통해 데이터를 보내는 방법 예시
- Client 가 WebSocket 을 통해 전달한 데이터들을 WriteValueCField 의 파라미터 값으로 설정 시 그 파라미터 값이 UpdateCField 함수에 파라미터 값으로 전달되면서 Field 값을 세팅한다
- 1초마다 NotifyFieldCFieldCyclic 함수 안의 NotifyCField 함수를 통해 세팅한 Field 값이 내부의 update 함수를 통해 payload 에 담겨 SendEvent 처리가 되어 다음 AA 로 보내진다.
-> 기본적으로 NotifyFieldCFieldCyclic 이 Async 되어 있어 1 초마다 Field 값이 다음 AA 로 전달한다.
-> 함수 처리순서: WriteValueCField -> UpdateCField -> NotifyFieldCFieldCyclic -> NotifyCField --> update -> 최종적으로 SendEvent 처리한다
- RPort를 통해 데이터를 보내는 방법 예시
- 다른 AA 가 SOME/IP 를 통해 전달한 데이터를 ReceiveFieldSFieldCyclic 함수를 통해 수신한다.
- ReadValueSField 함수 내의 get 함수 통해 해당 Field 값을 받은 후에 그 값을 해당 AA 와 연결된 Client 로 WebSocket 을 통해 전달한다.
-> 기본적으로 ReceiveFieldSFieldCyclic 이 Async 되어 있어 1 초마다 Field 값을 받아온다.
-> 함수 처리 순서 : ReceiveFieldSFieldCyclic -> ReadValueSField -> get
< 개발 중 발생한 장애요인과 해결 방안>
- AA 간의 서비스 방식 선택 문제
처음에 설계하였을 때 생각한 것은 Lidar, Camera, Inference, Navigation, Servo와 같 은 AA의 경우 하나의 RPort를 통해 데이터들을 수신하고, 가공한 후, 하나의 PPort로 값을 내보낸다. -> Field
반면 SensorFusion AA의 경우, Lidar AA와 Camera AA로부터 데이터들을 각각의 RPort를 통해 받고, 가공한 후 하나의 PPort로 값을 내보내야 한다고 생각했다. 그래서 SvSensorfusion의 경우 Method형식으로 만들어 Lidar Data(LidarD)와 Image Data(ImageD)를 INPUT으로 받아 가공한 후 OUTPUT으로 그 결과 데이터인 Fusion Data(FusionD)를 Inference AA로 반환 할 수 있도록 설계하였다. -> Method
그러나 Method이 Consumer가 요청해야 하지만 이루어지는 방식이라는 것을 깨닫고, 각각의 AA끼리 통신할 때 Field 방식을 이용해서 Set 함수를 통해서 다음 AA로 보낼 Field 값을 세팅한 후에 Notifier를 통해 주기적으로 해당 필드 값을 보낼 수 있도록 재구성하였다.
더불어, 만약 데이터 길이가 많아서 손실이 나거나 해당 AA에서 처리해야 하는데 값이 잘못 들어왔을 경우 Consumer AA가 Provider에게 재요청을 할 수 있도록 구성하였다.
'대규모 프로젝트(팀) > 자율주행 레이싱 (5명)' 카테고리의 다른 글
AUTOSAR (0) | 2025.01.14 |
---|