1. ROS
1. 개념
- 로봇 소프트웨어를 개발하는데 필요한 소프트웨어의 집합체
- 각종 센서와 모터를 프로그래머가 편하게 사용할 수 있도록 지원
- 표준화된 통신 프로토콜을 따르는 이기종간의 메시지 교환이 가능
- 통신은 토픽의 발행 및 구독 기반의 메시지 교환 형식으로 진행
2. 용어
마스터
노드 사이의 통신을 총괄 관리(ROS Core)
노드(node)
실행 가능한 최소 단위의 프로세스으로서 토픽을 주고 받는 통신 주체
토픽(topic)
노드간에 통신할 수 있는 채널 (일방적이거나 지속적, 1:1과 N:N 통신 가능)
메시지(message)
통신되는 실제 데이터
발행자
토픽을 만들어 보내는 노드
구독자
토픽을 받는 노드
패키지(package)
하나 이상의 노드와 노드실행을 위한 정보 등을 묶어놓은 것
2. ROS 설치
- 설치는 http://wiki.ros.org/melodic/Installation/Ubuntu를 참고하면 된다
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' cat /etc/apt/sources.list.d/ros-latest.list sudo apt install curl # if you haven't already installed curl curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add - sudo apt update sudo apt install ros-melodic-desktop-full echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc source ~/.bashrc sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential sudo rosdep init rosdep update
- 설치 이후에
roscore
를 입력하여 정상적으로 작동하는지 확인해본다
3. 워크스페이스 생성
- 원하는 이름으로 워크스페이스를 생성 후 빌드한다
mkdir -p ~/${WORK_SPACE_NAME}/src # mkdir -p ~/ros_ws/src cd ${WORK_SPACE_NAME} # cd ~/ros_ws catkin_make # ROS 환경 설정 및 빌드 ll # build, devel 폴더 생성 확인
- .bashrc 파일에 다음의 내용을 추가해준 뒤,
source ~/.bashrc
로 설정을 업데이트한다alias cm='cd ~/ros_ws&& catkin_make' alias cs='cd ~/ros_ws/src' source /opt/ros/melodic/setup.bash source ~/ros_ws/devel/setup.bash export ROS_MASTER_URI=http://localhost:11311 export ROS_HOSTNAME=localhost
- 환경변수 목록을 확인하기 위해
printenv | grep ROS
을 입력한다
4. turtle_sim 예제 실행
- 터미널은 4개의 영역으로 나눈 뒤에, 각각 다음의 명령어를 실행한다
roscore
마스터의 실행
rosrun turtlesim turtlesim_node
turtlesim 노드 실행
rosrun turtlesim turtle_teleop_key
키보드로 turtlesim를 제어할 수 있는 노드 실행
- 다음의 명령어를 실행할 수 있다
rqt_graph
시각적으로 노드 및 토픽 흐름 확인하기
rosnode list
노드 목록 확인
rostopic list
토픽 목록 확인
rostopic list -v
토픽 목록 자세히 보기
rostopic echo /turtle1/cmd_vel
특정 토픽의 메시지 리스닝하기
rostopic type /turtle1/cmd_vel
특정 토픽의 메시지 타입 보기
rosmsg show geometry_msgs/Twist
특정 메시지의 형식 보기
rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
1회성으로 토픽을 발행해보기
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
지속적으로 토픽을 발행해보기
5. 커스텀 패키지 제작
1. 패키지 생성
- 아래의 명령어로 새로운 패키지를 생성한다
cd ~/${WORK_SPACE_NAME}/src # cd ~/ros_ws/src catkin_create_pkg ${PACKGE_NAME} std_msgs rospy # catkin_create_pkg init_pkg std_msgs rospy cd ~/${WORK_SPACE_NAME} # cd ~/ros_ws catkin_make
- 아래의 명령어로 패키지가 제대로 생성되었는지 확인한다
rospack list | grep init_pkg
rospack find init_pkg
rospack depends1 init_pkg
2. 파일 작성
~/ros_ws/src/init_pkg/src
폴더 하위에talker.py
와listener.py
작성#!/usr/bin/env python # license removed for brevity import rospy from std_msgs.msg import String from geometry_msgs.msg import Twist def talker(): pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10) rospy.init_node('talker', anonymous=True) rate = rospy.Rate(10) # 10hz msg = Twist() msg.linear.x = 2.0 msg.linear.y = 0.0 msg.linear.z = 0.0 msg.angular.x = 0.0 msg.angular.y = 0.0 msg.angular.z = 1.8 while not rospy.is_shutdown(): rospy.loginfo(msg) pub.publish(msg) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass
#!/usr/bin/env python import rospy from std_msgs.msg import String from turtlesim.msg import Pose def callback(data): rospy.loginfo(rospy.get_caller_id() + ":: %.2f %.2f", data.x, data.y) def listener(): rospy.init_node('listener', anonymous=True) rospy.Subscriber("/turtle1/pose", Pose, callback) rospy.spin() if __name__ == '__main__': listener()
- cpp 관련 코드는 다음과 같이 작성하면 된다
#include "ros/ros.h" #include "std_msgs/String.h" #include "geometry_msgs/Twist.h" #include <sstream> int main(int argc, char **argv) { ros::init(argc, argv, "talker"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1); ros::Rate loop_rate(1); while (ros::ok()) { geometry_msgs::Twist msg; msg.linear.x = 2.0; msg.linear.y = 2.0; msg.linear.z = 2.0; msg.angular.x = 0.0; msg.angular.y = 0.0; msg.angular.z = 1.8; chatter_pub.publish(msg); loop_rate.sleep(); } return 0; }
#include "ros/ros.h" #include "std_msgs/String.h" #include "turtlesim/Pose.h" #include <iostream> void chatterCallback(turtlesim::Pose msg) { ROS_INFO("[L] %.4f, %.4f", msg.x, msg.y); } int main(int argc, char **argv) { ros::init(argc, argv, "listener"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe<turtlesim::Pose>("/turtle1/pose", 1000, chatterCallback); ros::spin(); return 0; }
- 스크립트를 실행해서 정상적으로 진행하는지 확인한다
python talker.py
python listener.py
6. 실행
1. rosrun를 통한 실행
chmod +x *.py
로 해당 파일에 실행권한을 추가한 후,ll
명령어로 확인한다
- 위에 한 것과 같이, 터미널을 4개 영역으로 나누어 실행한 뒤 각각 명령어를 입력한다.
roscore
마스터의 실행
rosrun turtlesim turtlesim_node
turtlesim 노드 실행
rosrun init_pkg talker.py
거북이를 회전하게 만드는 노드 실행행
rosrun init_pkg listener.py
/turtle1/pose 정보를 받아오는 노드 실행행
2. roslaunch를 통한 실행
~/ros_ws/src/init_pkg/launch
폴더 생성 후talk-listen.launch
작성<launch> <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node"/> <node pkg="init_pkg" type="talker.py" name="talk_node"/> <node pkg="init_pkg" type="listener.py" name="listen_node" output="screen"/> </launch>
roslaunch init_pkg talk-listen.launch
로 실행
3. param를 적용한 roslaunch 실행
~/ros_ws/src/init_pkg/launch
폴더 하위에talk-listen-param.launch
작성<launch> <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node"/> <node pkg="init_pkg" type="talk_param.py" name="node_param"> <param name="circle_size" value="5" /> </node> <node pkg="init_pkg" type="listener.py" name="listen_node" output="screen"/> </launch>
~/ros_ws/src/init_pkg/src
폴더 하위에talk_param.py
작성#!/usr/bin/env python # license removed for brevity import rospy from std_msgs.msg import String from geometry_msgs.msg import Twist def talker(): pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10) rospy.init_node('talker', anonymous=True) rate = rospy.Rate(10) # 10hz msg = Twist() # msg.linear.x = 2.0 linear_X = rospy.get_param('~circle_size') msg.linear.x = linear_X msg.linear.y = 0.0 msg.linear.z = 0.0 msg.angular.x = 0.0 msg.angular.y = 0.0 msg.angular.z = 1.8 while not rospy.is_shutdown(): rospy.loginfo(msg) pub.publish(msg) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass
chmod +x talk_param.py
로 실행 권한 주기
roslaunch init_pkg talk-listen-param.launch
로 실행