======ROS 스터디 #7: 임베디드 시스템======
2021년 01월 20일 18:00\\
ZOOM 화상회의
{{youtube>xNYE07gjrds?medium}}
=====1. 개념=====
**임베디드 시스템(embedded system, 내장형 시스템)**
기계나 기타 제어가 필요한 시스템에 대해 제어를 위한 특저 기능을 수행하는 컴퓨터 시스템으로 장치 내에 존재하는 전자 시스템이다. 즉 임베디드 시스템은 전체 장치의 일부분으로 구성되며 제어가 필요한 시스템을 위한 두뇌 역할을 하는 특정 목적의 컴퓨터 시스템이라고 정의할 수 있다.
||
**임베디드 보드 종류**
^ ^8/16-bit MCU^(small) 32-bit MCU^(big) 32-bit MCU^ARM A-class^x86^
|보드 예|Atem AVR|ARM Cortex-M0|ARM Cortex-M7|Samsung Exynos|Intel Core i5|
|시스템 예|Arduino, Leonardo|Arduino M0 pro|SAM V71|ODROID|Intel NUC|
|MIPS((컴퓨터의 연산 속도의 단위. 1MIPS는 1초에 1백만 회의 명령을 실행하한다는 의미이다))|10's|100's|1000's|10000's|
|RAM|1~32KB|32KB|384KB|a few GB(off-chip)|2-16 GB (SODIMM)|
|최대 출력|10'of mW|100'of mW|100'of mW|1000'of mW|10000'of mW|
|주변 기기|UART, USB FS 등|USB FS|Ethernet,USB HS|Gigabit Ethernet|USB SS, PCle|
||
리눅스 같은 운영체제는 실시간성을 보장하지 못하기 때문에 엑추에이터나 센서등을 제어하기 위해서는 실시간 제어에 적합한 마이크로컨트롤러를 사용한다. 이런 임베디드 시스템에는 ROS를 설치할 수 없기 때문에 시스템과 (ROS가 설치된) PC 사이의 통신이 필요하다.((ROS에서는 이를 위해 rosserial이라는 패키지를 제공한다))
=====2. Open CR=====
====2.1 개념====
{{https://img.kasimov.synology.me/2020/ros/9/OpenCR.JPG?400}}
ROS를 지원하는 임베디드 보드이며 터틀봇3에서 메인 제어기로 사용된다. 회로, BOM, 거버 데이터 등의 H/W 정보 및 OpenCR의 모든 S/W가 오픈소스로 공개되어 있으며 성능이 좋고((마이크로컨트롤러에서는 최상위인 Cortex-M7 코어를 사용해 최대 216Mhz로 구동됨)) 인터페이스가 다양하다. 또한 IMU 센서를 사용하며 전원 출력이 다양((입력 전원이 7~24V일 때 12, 5V, 3.3V의 출력을 지원))하다.
||
====2.2 개발환경 구축====
[[https://emanual.robotis.com/docs/en/platform/turtlebot3/appendix_opencr1_0/|Turtlebot3 e-Manual]] 참조
=====3. rosserial=====
====3.1. 개념====
PC와 제어기 간의 메시지((메시지, 토픽, 서비스 모두 가능)) 통신을 위해 중계자 역할을 수행하는 ROS 패키지
* 예) 제어기 > 시리얼(rosserial 프로토콜) > PC(ROS 메시지로 재전송)
* 예) 제어기 < 시리얼(rosserial 프로토콜) < PC(ROS 메시지를 시리얼로 변경)
일반적으로 마이크로컨트롤러는 ROS에서 기본 통신으로 사용하는 TCP/IP 통신보다 시리얼 통신을 많이 사용하므로 rosserial과 같은 중재자 역할이 필요하다.
||
====3.2. package 구성====
rosserial은 rosserial server와 rosserial client로 구성되어있다. rosserial server는 구현된 프로그래밍 언어에 따라 3가지 노드가 있다.
* **rosserial_python**: Python 언어 기반의 rosserial server로 일반적으로 많이 사용된다.
* **rosserial_server**: C++ 언어 기반의 rosserial server로 동작 성능이 상대적으로 향상되었으나 rosserial_python에 비해 일부 기능의 제약이 있다.
* **rosserial_java**: Java 언어 기반의 rosserial server로 안드로이드 SDK를 사용할 때 함께 이용한다.
||
rosserial client는 client 역할을 하는 라이브러리에 마이크로컨트롤러에서
사용되는 플랫폼에 포팅되었다.
* **rosserial_arduino**: Arduino와 Leonardo 보드를 지원하지만 소스 수정을 통해 다른 보드에서도 사용 가능하다. 터틀봇3의 OpenCR 보드에서도 수정하여 사용하고 있다.
* **rosserial_embeddedlinux**: 임베디디용 리눅스에서 사용 가능한 라이브러리다.
* **rosserial_windows**: 윈도우 운영체제를 지원하고 윈도우의 응용프로그램과 통신을 지원한다.
* **rosserial_mbed**: ARM사의 mbed를 지원한다.
* **rosserial_tivac**: TI사의 Launchpad를 지원한다.
||
====3.3. 프로토콜====
rosserial server와 client는 시리얼 통신 시반의 패킷 형태로 데이터를 송/수신한다.
rosserial protocol은 바이트 단위로 정의되어있고 패킷의 동기화 및 데이터 검증을 위한 정보들이 포함되어있다.
**rosserial 패킷 구성**
^1st Byte^2nd Byte^3rd Byte^4th Byte^5th Byte^6th Byte^7th Byte^N Bytes^Byte N+8^
|Sync Flag|Sync Flag/ Protocol version|Message Length(N)|Message Length(N)|Checksum over message length|Topic ID|Topic ID|Serialized Message Data|Checksum over Topic ID and Message Data|
* Sync Flag: 패킷의 시작 위치를 알기 위한 헤더로 항상 0xFF 이다.
* Sync Flag / Protocol version: 프로토콜 버전으로 ROS Groovy는 0xFF이고, ROS Hydro, Indigo, Jade 그리고 Kinetic은 0xFE 이다.
* Message Length(N): 메시지의 데이터 길이 헤더이며 2 Byte로 구성된다. Low 바이트가 먼저 전송되고 이어서 High 바이트가 전송된다.
* Checksum over message length: 메시지 길이 헤더의 유효성 검증을 위한 체크섬으로 계산 방법은 아래와 같다.
Checksum = 255 - ( (Message Length Low Byte + Message Length High Byte) %256)
* Topic ID: 메시지의 형태를 구분하기 위한 ID이다. 0~100까지는 시스템 함수로 예약되어있는데 주로 사용되는 ID는 아래와 같다.
ID_PUBLISHER=0, ID_SUBSCRIBER=1, ID_SERVICE_SERVER=2, ID_SERVICE_CLIENT=4,
ID_PARAMETER_REQUEST=6, ID_LOG=7, ID_TIME=10, ID_TX_STOP=11
* Serialized Message Data: 송/수신 메시지를 시리얼 형태로 전송하기 위한 데이터이다. 예) IMU, TF, GPIO 데이터
* Checksum over Topic ID and Message Data: Topic ID와 메시지 데이터의 유효성 검증을 위한 체크섬으로 계산 방법은 아래와 같다.
Checksum = 255 - ( (Topic ID Low Byte + Topic ID High Byte + data byte values) % 256)
||
====3.4. 제약 상황====
* **메모리**: 마이크로컨트롤러는 사용할 수 있는 메모리의 용량이 작고 제한되어있기 때문에 퍼블리셔, 서브스크라이버 개수 및 송신, 수신 버퍼의 크기를 미리 정의해야 한다.
* **Float64**: 마이크로컨트롤러는 64비트 실수연산을 지원하지 않아 32비트형으로 변경된다.
* **Strings**: 문자열 데이터를 String 메시지 안에 저장하지 않고 외부에서 정의한 문자열 데이터의 포인터 값만 메시지에 저장한다. 따라서 스트링 메시지를 사용하려면 아래와 같은 절차가 필요하다.
std_msg::String str_msg;
unsigned char hello[13] = "hello world";
str_msg.data = hello;
* **Arrays**: 메모리 제약사항으로 배열 데이터에 대한 포인터를 사용해서 배열의 끝을 알 수 없다. 따라서 배열의 크기에 대한 정보를 추가해야 한다.
* **통신 속도**: UART 같은 경우((OpenCR에서는 USB를 통한 가상의 시리얼 통신을 적용하여 고속통신이 가능하다.)) 115200bps와 같은 속도로는 메시지의 개수가 많아지면 응답 및 처리속도가 느려 질 수 있다.
||
====3.5. 예제====
예제를 진행하기 전에 roscore를 먼저 실행한 후 진행해야 한다. 다음은 OpenCR에서 제공하는 기본 예제이다.
#include
#include
#include
int led_pin_user[4] = { BDPIN_LED_USER_1, BDPIN_LED_USER_2, BDPIN_LED_USER_3, BDPIN_LED_USER_4 };
ros::NodeHandle nh;
void messageCb( const std_msgs::Byte& led_msg) {
int i;
for (i=0;i<4;i++){
if (led_msg.data & (1< sub("led_out", messageCb );
void setup() {
pinMode(led_pin_user[0], OUTPUT);
pinMode(led_pin_user[1], OUTPUT);
pinMode(led_pin_user[2], OUTPUT);
pinMode(led_pin_user[3], OUTPUT);
nh.initNode();
nh.subscribe(sub);
}
void loop() {
nh.spinOnce();
}
rosserial_python을 이용해 rosserial server를 실행한다.
$ rosrun rosserial_python serial_node.py __name:=opencr _port:=/dev/ttyACM0 _baud:=115200
[INFO] [1495609829.326019]: ROS Serial Python Node
[INFO] [1495609829.336151]: Connecting to /dev/ttyACM0 at 115200 baud
[INFO] [1495609831.454144]: Note: subscribe buffer size is 1024 bytes
[INFO] [1495609831.454994]: Setup subscriber on led_out [std_msgs/Byte]
rostopic pub을 이용하여 led_out에 값을 입력하면 해당 값에 따라 LED가 동작한다.
$ rostopic pub -1 led_out std_msgs/Byte 1 // USER1 LED On
$ rostopic pub -1 led_out std_msgs/Byte 2 // USER2 LED On
$ rostopic pub -1 led_out std_msgs/Byte 4 // USER3 LED On
$ rostopic pub -1 led_out std_msgs/Byte 8 // USER4 LED On
$ rostopic pub -1 led_out std_msgs/Byte 0 // LED Off