현재 상황
다음과 같이 매번 여러개의 rosrun을 실행시키기 너무 귀찮고
Parameter 세팅 또한 터미널에서 해결하고자 roslaunch 파일을 만들고자 한다
roslaunch - ROS Wiki
melodic noetic Show EOL distros: EOL distros: electric fuerte groovy hydro indigo jade kinetic lunar diamondback: Only showing information from the released package extracted on Unknown. No API documentation available. Please see this page for in
wiki.ros.org
XML
roslaunch를 사용하고 싶으면 XML문법이 조금 들어가는데
가볍게 Element(요소), Tag(태그), Attribute(속성), Argument(변수) 정도만 살펴보자
Element(요소)
Tag(태그)
Attribute(속성)
Argument(변수)
태그(Tag)
태그(Tag)는 < >로 표현되는 부분이고 시작 태그는 <p> 끝 태그는 </p>로 나타낸다
단 줄바꿈 같은 <br> 와 같이 종료 태그가 없을 수도 있다 (이걸로 Github Readme.md 파일 작성)
요소(Element)
요소(Element) 시작 태그 ~ 끝 태그 안에 들어가는 명령어들
속성(Attribute)
속성(Attribute) 시작 태그 안에 사용되는 구체적인 명령
ex) <p align="center"> : 여기에 사용되는 align이 속성이다 (가운데 정렬 태그임)
변수(Argument)
그러면 "center"는 뭐라고 할까??? -> 이게 Argument(변수)이다
roslaunch
패키지 파라미터, 노드 이름을 변경시킬 수 있거나, 노드 네임스페이스 설정, ROS_ROOT 및 ROSPACKAGE_PATH 설정, 환경 변수 설정 등 옵션을 줄 수 있다
태그별 옵션을 제공하는 XML기반의 .launch파일을 통한다. 해당 파일은 패키지 폴더 내 launch 폴더 안에 있어야 한다.
roslaunch [패키지 이름] [roslaunch 파일명]
먼저 작업을 하기 전에 알아야 할 개념을 정리하자
namespace (네임스페이스)
일종의 그룹(소속)을 정해준다고 볼 수 있고 변수 등이 정의 되어있다
다른 namespace라면 같은 이름의 변수라도 다르게 취급을 한다
예시코드
roslaunch의 예시를 보자 (darknet_ros.launch)
<?xml version="1.0" encoding="utf-8"?>
<launch>
<!-- Console launch prefix -->
<arg name="launch_prefix" default=""/>
<arg name="image" default="/camera/rgb/image_raw" />
<!-- Config and weights folder. -->
<arg name="yolo_weights_path" default="$(find darknet_ros)/yolo_network_config/weights"/>
<arg name="yolo_config_path" default="$(find darknet_ros)/yolo_network_config/cfg"/>
<!-- ROS and network parameter files -->
<arg name="ros_param_file" default="$(find darknet_ros)/config/ros.yaml"/>
<arg name="network_param_file" default="$(find darknet_ros)/config/yolov2-tiny.yaml"/>
<!-- Load parameters -->
<rosparam command="load" ns="darknet_ros" file="$(arg ros_param_file)"/>
<rosparam command="load" ns="darknet_ros" file="$(arg network_param_file)"/>
<!-- Start darknet and ros wrapper -->
<node pkg="darknet_ros" type="darknet_ros" name="darknet_ros" output="screen" launch-prefix="$(arg launch_prefix)">
<param name="weights_path" value="$(arg yolo_weights_path)" />
<param name="config_path" value="$(arg yolo_config_path)" />
<remap from="camera/rgb/image_raw" to="$(arg image)" />
</node>
</launch>
<?xml version="1.0" encoding="utf-8"?>
XML으로 작성하겠다고 선언을 하는 부분이다 (encoding을 진행할 떄 사용)
주석표현
주석은 다음과 같이 표현한다
<!-- 주석의 내용 -->
<launch 태그>
파일 내용 전체를 감싸는 태그라고 생각하면 쉽다
시작과 끝을 다음과 같이 작성한다
<launch>
...
</launch>
launch 내용의 시작과 끝을 알려줌
<Node> 태그
실행해야할 Node를 작성한다
태그의 속성은 다음과 같다
위에 대한 예시는 다음과 같다
<node name="listener1" pkg="rospy_tutorials" type="listener.py" args="--test" respawn="true" />
<!-- listener1이라는 이름의 노드를 실행함. -->
<!-- rospy_toturials 패키지에서 listner.py라는 실행파일을 이용함. -->
<!-- command-line 인자로 test를 추가함. 노드가 중단되었을 때 바로 재시작함 -->
<node pkg="darknet_ros" type="darknet_ros" name="darknet_ros" output="screen" launch-prefix="$(arg launch_prefix)">
<!-- darknet_ros 패키지에서 darknet_ros이라는 이름의 노드를 실행함. -->
<!-- 터미널 창에 출력을 표시하고 -->
<!-- 다른 곳에 정의한 launch_prefix arg를 launch-prefix로 함 -->
이걸 제일 단순하게 사용하고 싶으면 다음과 같이 요약을 할 수 있다
<node> ~ </node>
혹은
<node "작성할 내용" />
기본형태
<node pkg = "소스코드가 들어있는 패키지 명" type= "실행 시키고 싶은 파일" name ="rqt_graph등에서 표현될 이름"/>
여기서 제일 고민이 되었던 부분은 rosserial을 roslaunch로 어떻게 묶을까 라는 것이다
rosserial을 roslaunch로 묶기
rosserial 의 rosrun 명령어는 다음과 같다
rosrun rosserial_python serial_node.py _name:=opencr _port:=/dev/ttyACM0 _baud:57600
이를 분석을 해보면
패키지 명 : rosserial_python
파일 명 : serial_node.py
인자 1(arguments) : name = opencr
인자 2(arguments) : port = /dev/ttyACM0
인자 3(arguments) : baud = 57600
와 같이 분석을 할 수 있다
이 arguments를 전달 하기 위해서는 <param> ~ </param> 와 같은 방법 <param>태그를 사용하면 된다
<param> 태그
<node> 태그 내부에서 사용 시에 해당 파라미터는 private parameter로 사용된다
value 값을 지정하거나 파일(textfile, binfile)나 명령(command)를 사용할 수 있게 해준다
이를 위에 rosserial부분을 참고해서 작성해보면
<node pkg="rosserial_python" type="serial_node.py" name="opencr">
<param name="port" value="/dev/ttyACM0"/>
<param name="baud" value="57600"/>
</node>
내 생각에는
<param name="name" value="opencr"/>
도 추가해야한다고 보는데 찾아보니 다들 저렇게 쓰고 실제 이 부분을 빼고 실행시켜도 실행이 되긴 했다
이정도만 이용해서 가볍게 rosrun을 roslaunch로 묶는 XML 정도는 빠르게 만들 수 있다
기본 예시
<launch>
<node pkg= "collabot_ver1" type="ac_pub_az_sub.py" name="ac_converter"/>
<node pkg="rosserial_python" type="serial_node.py" name="opencr">
<param name="port" value="/dev/ttyACM0"/>
<param name="baud" value="57600"/>
</node>
<node pkg= "collabot_ver1" type="sceinaro_make.py" name="sceinaro"/>
</launch>
만드는 방법
launch 파일은 패키지 디렉토리 바로 밑에 만든다
먼저 패키지 디렉토리에 들어간다
cd ~/catkin_ws/src/my_pkg/
그 다음에 launch 파일을 만든다
nano collabot_ver1.launch
이렇게만 해도 충분히 roslaunch를 이용할 수 있지만 좀 더 다양한 기능을 추가할 수도 있다
(위에 예시 만 봐도 rosparam 부터 arg 까지 엄청 많은 것들이 내포 되어 있다)
roslaunch 추가기능
<launch> 태그 내부에는 다음과 같은 태그 들을 포함할 수 있다
<node>
<param>
<remap>
<machine>
<rosparam>
<include>
<env>
<test>
<arg>
<group>
<rosparam> 태그
<param> 태그와 비슷하게 사용 (파라미터의 이름, 타입, 값을 설정)
rosparam.yaml 파일을 이용하여서 ROS param server로 부터 parameter를 로드하거나 덤핑, 삭제 등을 한다
<include> 태그
다른 roslaunch XML파일을 사용할 때 사용
<include file="$(find ublox_gps)/launch/ublox_device.launch"/>
<!-- ublox_gps 패키지에서 ublox_device.launch 파일을 불러와 함께 실행하라 -->
<remap> 태그
이미 사용 중인 ROS 변수를 바꿀 때 사용 (node/ topic 등)
from : 원래의 이름
to : 바꾸고 싶은 이름
<env> 태그
노드의 환경 변수(경로, IP)등을 설정
name, value를 사용
<arg> 태그
command를 통해 전달되는 값을 미리 지정 가능
global 변수가 아닌 실행되는 launch파일에만 영향
<!-- 전달할 인수들을 선언해놓고 -->
<arg name="hoge" value="fuga" />
<arg name="image" default="/camera/rgb/image_raw" />
<!-- 정의해 놓은 인수를 읽어다 사용함 -->
<param name="param" value="$(arg hoge)"/>
<!-- param이라는 이름의 파라미터에 인수 hoge의 값으로 지정해놓은 fuga를 할당함 -->
<remap from="camera/rgb/image_raw" to="$(arg image)" />
응용 예시 코드
위에 언급되었던 명령어
<launch>
<node pkg= "collabot_ver1" type="ac_pub_az_sub.py" name="ac_converter"/>
<node pkg="rosserial_python" type="serial_node.py" name="opencr">
<param name="port" value="/dev/ttyACM0"/>
<param name="baud" value="57600"/>
</node>
<node pkg= "collabot_ver1" type="sceinaro_make.py" name="sceinaro"/>
</launch>
여기에서 adult / child 를 판단하는 기준값
class height:
def __init__(self):
self.data = None #전역변수로 선언을 해주고
self.height_threshold = 1500
self.ac = None
rospy.init_node('az_sub_ac_pub_node', anonymous=True)
self.subscriber = rospy.Subscriber(
name="length", data_class=Float32, callback=self.callbackFunction)
self.publisher = rospy.Publisher('ac_information', String, queue_size=10)
self.rate = rospy.Rate(30) # 0.5hz
이 height_threshold 값을 launch를 실행할 때 바꾸는 코드를 작성해보자
타겟이 되는 파일은 ac_pub_az_sub.py 가 될 것이다
가장 쉽게 생각할 수 있는 것이 (밑에는 잘 못된 명령어 입니다)
<launch>
<node pkg= "collabot_ver1" type="ac_pub_az_sub.py" name="ac_converter"/>
<param name="height_threshold" type= "int" value="400"/>
<node pkg="rosserial_python" type="serial_node.py" name="opencr">
<param name="port" value="/dev/ttyACM0"/>
<param name="baud" value="57600"/>
</node>
<node pkg= "collabot_ver1" type="sceinaro_make.py" name="sceinaro"/>
</launch>
일 것이다
하지만 위아래의 명령어를 비교 해보면 node가 닫힌 곳에서 작성이 되었기 때문에 다음과 같이 바꿔줘야 한다
<launch>
<node pkg= "collabot_ver1" type="ac_pub_az_sub.py" name="ac_converter">
<param name="height_threshold" type= "int" value="400"/>
</node>
<node pkg="rosserial_python" type="serial_node.py" name="opencr">
<param name="port" value="/dev/ttyACM0"/>
<param name="baud" value="57600"/>
</node>
<node pkg= "collabot_ver1" type="sceinaro_make.py" name="sceinaro"/>
</launch>
또한 직감했듯이 이렇게 XML 만 바꾼다고 해서 적용이 되지는 않고 소스코드 또한 바꿔줘야 한다
rospy.get_param('~<param name>')
다음과 같이 parameter를 받을 수 있고
그러면 코드가 다음과 같이 바뀐다
class height:
def __init__(self):
self.data = None #전역변수로 선언을 해주고
self.height_threshold = rospy.get_param('~height_threshold')
self.ac = None
rospy.init_node('az_sub_ac_pub_node', anonymous=True)
self.subscriber = rospy.Subscriber(
name="length", data_class=Float32, callback=self.callbackFunction)
self.publisher = rospy.Publisher('ac_information', String, queue_size=10)
self.rate = rospy.Rate(30) # 0.5hz
이걸 실행해보면
File "/opt/ros/melodic/lib/python2.7/dist-packages/rospy/msproxy.py", line 123, in __getitem__
raise KeyError(key)
KeyError: '~height_threshold'
keyError 가 난다
이는 순서 때문인데 rospy.get_param 또한 rospy.init_node 다음에 나와야하는 코드이다
그래서 순서를 이렇게 바꾸면
class height:
def __init__(self):
rospy.init_node('az_sub_ac_pub_node', anonymous=True)
self.data = None #전역변수로 선언을 해주고
self.height_threshold = rospy.get_param('~height_threshold')
self.ac = None
self.subscriber = rospy.Subscriber(
name="length", data_class=Float32, callback=self.callbackFunction)
self.publisher = rospy.Publisher('ac_information', String, queue_size=10)
self.rate = rospy.Rate(30) # 0.5hz
정상적으로 작동한다
참고자료
https://velog.io/@717lumos/roslaunch%EC%9D%98-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%B0%8F-XML
[ROS] roslaunch의 사용법 및 XML
ROS roslaunch 사용법 및 XML 작성법
velog.io
http://wiki.ros.org/rosserial_python
rosserial_python - ROS Wiki
melodic noetic Show EOL distros: EOL distros: electric fuerte groovy hydro indigo jade kinetic lunar diamondback: Only showing information from the released package extracted on Unknown. No API documentation available. Please see this page for in
wiki.ros.org
'Robotics > Collabot_proj' 카테고리의 다른 글
[Robotics] Collabot 현업(16) Print 문 커스텀 (0) | 2023.05.25 |
---|---|
[Robotics] Collabot 현업(15) Raspberry pi CLI 환경 고정IP (0) | 2023.05.23 |
[Robotics] Collabot 현업(13) [노트북과 OpenCR연결 & 통신] (1) | 2023.05.15 |
[Robotics] Collabot 현업(12) [우분투 & 핸드폰 블루투스로 통신] (0) | 2023.05.11 |
[Robotics] Collabot 현업(11) [라즈베리파이3에 ROS 설치 (Kinetic)] (0) | 2023.05.10 |