0. 들어가기전
나는 자율주행 시스템을 만들어본적 없는 군인 개발자이다. 위의 이유로 자율주행을 만들기 시작하긴 했는데, 내가 아는거라고는 쥐뿔도 없었다. 여러가지 서칭을 하면서 알게 된 건 A to Z 로 개발해야한다는것이다. 정성적인 매뉴얼따위는 없다. 각각의 영역에서는 레퍼런스들이 꽤 있지만 자율주행을 하기 위해서 뭐부터 해라, 뭘 해라, 어디까지 해라 이런건 없는것임.. 그래서 상상력을 동원해 코드를 작성하기 시작했다. ROS 라는게 자율주행 시스템에 사용되어야 함은 알고 있었지만 ROS 가 뭔지. 왜 사용해야하는지, 어떻게 사용해야하는지 따위는 걱정할게 아니었던것이다. 우선 기능단위로 코드를 작성해야했고, 지금 기능단위로 코드작성이 거의 마무리 되었다.
위의 저장소에 우리 코드들이 담겨있는데, 대회가 마무리 되는대로 저장소 정리를 해야겠다. 어쨌든, 지금 상황은 기능별로 코드작성이 완료되었고, ROS 를 사용해야한다는건데, 뭘 어떻게 써야할지를 모르는 것이다. 나와 비슷한 상황의 사람에게 이 자료가 도움이 되었으면 한다.
1. ROS 란 ?
ROS 공식 문서에 나와 있는 ROS 설명이다.
The Robot Operating System (ROS) is a set of software libraries and tools that help you build robot applications. From drivers to state-of-the-art algorithms, and with powerful developer tools, ROS has what you need for your next robotics project. And it's all open source.
로봇프로그램을 위한 라이브러리들과 툴들의 모음인데, 공감도 안되고 무슨말인지도 모르겠다. 게다가 R-OS(Operation System) 이라고는 하지만, 잠깐 만져봤던 사람들은 여기서 이상함을 느꼈을 것이다. OS 가 아니고 그냥 라이브러리 혹은 프레임워크이다.
즉 ROS 는 로봇 프로그래밍을 위한 라이브러리와 툴을 제공해주는 플랫폼이다.
2. ROS 작동 형태
위 사진은 ROS 에서 중요하게 생각하는, Node 를 그래프로 표현한 것이다.
Node 는 어떤 지점들을 의미한다.
즉 ROS 는 Node 들의 집합관계이며, 이들간 Message 를 주고받는 형태이다.
3. ROS 프로그래밍
ROS 는 노드들간의 집합이며, 노드는 메시지로 각 노드들간 동신을 한다.
그렇다면 ROS 프로그래밍은 노드들이 통신할수 있도록 코딩하는것을 의미할 것 이다.
자율주행의 기본적인 로직은 아래와 같다.
1. N개의 센서로부터 데이터를 수신받는다.
2. 받은 데이터를 가공해서 주변환경과 자신(로봇)의 상태를 인지한다. - Perception
3. Perception 기반의 데이터를 활용하여 어떻게 움직여야 할지 판단한다. - Decision
4. Decision 의 데이터를 바탕으로 실제 동작(주행)을 한다. - Control
이것을 코딩한다면 대강 이런 의사코드로 짜여질것이다.
def _sensorData(sensor1,sensor2,sensor3...):
--- 여러가지 센서를 통해 데이터를 반환한다. ----
return sensorData
def _pathPlanning(sensordata):
return _path
def _motionPlanning(path):
return motionPlan
def contorlCar(motionPlan):
return
thread1 = thread.Threading(target=_sensorData)
thread1.start()
while True:
motionPlan = _motionPlanning(_pathplanning(_sensorData)))
controlCar(motionPlan)
Python
복사
센서들로 데이터를 수신하여, 주변의 환경을 인식하고 이를 통해 최적의 경로를 생산해낸다.
경로를 바탕으로 실제 차량이 어떻게 움직여야하는지 MotionPlanning 을 실시하고, 이를 차량 모터제어에 활용한다. 쓰레드를 활용한다면 충분히 작동가능하고 별로 어렵지 않다.
하지만, 만약에 쓰레딩 방법으로 프로그램을 빌드한다면 문제점이 발생한다. 전체적인 데이터 파이프라인에서 무언가 하나 오류가 발생하거나 제대로 작동하지 않는다면 전체가 멈춘다. 또한 쓰레드는 하나의 프로세스에서 작동하기 때문에 스케쥴링에도 무언가 문제가 발생할 수 있다. 물론 이를 예방하여 코드를 작성할 수 있지만 ROS 는 쓰레드로 차량을 움직이는것보다 훨씬 더 간단하게 예상되는 문제들을 해결할 수 있다.
마스터 노드에서 나머지 노드들( 프로세스 ) 를 관리한다. 스케쥴링 또한 ROS 자체적으로 해주기 때문에 무언가 문제가 생겨도 차량이 멈추는 경우는 발생하지 않는다.
물론 예외처리나 데이터가 없는경우 어떻게 처리할지는 코드 상 작성을 해주어야 한다.
이런 데이터 파이프라인에 대한 구조를 발행자(Publisher) 와 수신자 ( Subscriber) 로 표현한다. 센서에서 오는 데이터를 추가적으로 활용하기 원한다면 이를 위해서 새로운 쓰레드를 만드는것이 아니라, Subscriber 를 추가하면 될 일이다.
결론적으로 확장성과 프로그램 안정성에 있어 쓰레드로 직접 처리하는것보다 훨씬 편해진다는 것이다.
발행자와 수신자는 ROS 에서 가장 중요한 개념중 하나이므로 다음 챕터에서 더 자세하게 다루도록 하겠다.