<!-- .slides text-align: left; --> # ROS / ROS2 教學 <br> <br> ### NDHUEE &nbsp;&nbsp;&nbsp; ISP ### 611023011 何明叡 --- ## 歷史介紹 + ROS 1 最初是史丹佛大學的人工智慧實驗室與機器人公司 Willow Garage 合作的一個機器人專案,名稱為 Personal Robots Program。這項專案研發的機器人 PR2 在使用 ROS 1 的基上,能夠完成打撞球、做早餐、疊衣服等接近人類的動作,因此引起了全世界的關注。 + 2008 年後,ROS 1 便交由 Willow Garage 維護,並在 2010 年時正式以開放原始碼的方式,向世界發佈了 ROS 1 的框架。 + 最後在 2013 年時轉交給開源機器人基金會 OSRF(Open Source Robotics Foundation) 繼續維護。 + 大約一年發布一次更新 --- ## 什麼是ROS? + Robot Operating System ![](https://i.imgur.com/eQHHvQN.png) --- ## Solution + A framework that provides: + 軟硬整合: + navigation -> ( laser scanner, data process, algorithm) + 系統整合+模組化系統: + Nodes + Message passing + Topics: publish / subscribe + Services: call / provide + visualization, monitoring + System structure, message flow, tf, data + 或是...把以上所有自己寫code來完成?? --- ## WHY ROS? + 跨語言,跨平台 + 聯機操作 Remote communication and control + 眾多第三方工具 + 被廣泛使用,且持續成長中 ![](https://i.imgur.com/eZVDoEi.png =x300) ![](https://i.imgur.com/rMNJ4cd.png =x300) --- ## 教學進度安排 + ROS 介紹 + ROS 環境建置 + ROS Nodes + ROS Topics + ROS Services + ROS Msg & Srv --- ## ROS1 ROS2 版本 + PC系統? | ROS1 | ROS2 | |:------:|:------:| | http://wiki.ros.org/Distributions | https://docs.ros.org/en/foxy/Releases.html| |![](https://i.imgur.com/FKh3h77.png)|![](https://i.imgur.com/7c6W5r2.png)| |![](https://i.imgur.com/oxBICsA.png)|![](https://i.imgur.com/qL8ckpi.png =x90) | + Ubuntu 20.04 + img: https://www.ubuntu-tw.org/modules/tinyd0/index.php?id=7 + USB製作: https://www.balena.io/etcher/ + 教學: https://ubuntu.com/tutorials/install-ubuntu-desktop#1-overview + 開始漫長的安裝~~~ --- ## 安裝ROS 開始安裝前,這堂課需要準備什麼? + 電腦 ( PC, LAPTOP, Nvidia Jetson nano...) + USB 灌ubuntu 基礎知識 + Python + Linux - Ubuntu --- ## 安裝ROS 開機後: + sudo apt update + sudo apt upgrade 1.2 Setup your sources.list ``` sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' ``` 1.3 Set up your keys ``` 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 - ``` 1.4 Installation ``` sudo apt update sudo apt install ros-noetic-desktop-full ``` --- ## 安裝ROS 1.5 Environment setup + 在 ~/.bashrc 最後一行加上 ``` source /opt/ros/noetic/setup.bash ``` + ![](https://i.imgur.com/vwNz3QB.png =x100) + 使 ~/.bashrc 生效 ``` source ~/.bashrc ``` 1.6 Dependencies for building packages ``` sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential sudo apt install python3-rosdep sudo rosdep init rosdep update ``` --- ## 測試ROS是否安裝成功 ``` roscore ``` ![](https://i.imgur.com/c5TOOOG.png) --- ## ROS node/topic 實做 ### 前情提要 + ubuntu 基本操作 + ctrl + alt + T -----開啟terminal + ctrl + shift + T -----在terminal開新分頁 + ls -----列出所有檔案 + cd -----前往 + cp -----複製 + rm -----移除(無法復原) + cat -----讀取 + mkdir -----建立資料夾 + ~/ 使用者根目錄 + / 系統根目錄 + sudo +command 以系统管理者身份執行 --- ## ROS node/topic 實做 ### 前情提要 + vim基本操作 + vim file_name + i -----insert + u -----復原 + ctrl + r -----還原復原 + esc -----完成編輯 + :w -----儲存 + :q -----離開 + :wq -----儲存並離開 --- ## ROS Graph ![](https://i.imgur.com/kVS6GGD.png =x550) [p.17 node](#16) -- [p.21 topic](#20) -- [p.44 service](#43) -- [p.51 msg/srv](#50) -- [lunch](#14) -- [parm](#13) --- ## ROS的第一個專案:小烏龜 + 安裝小烏龜package ``` sudo apt-get install ros-noetic-turtlesim ``` + 啟動master ``` roscore ``` + 啟動小烏龜 ``` rosrun turtlesim turtlesim_node ``` + 開啟鍵盤控制 ``` rosrun turtlesim turtle_teleop_key ``` ![](https://i.imgur.com/mG3dH02.png =x200) ![](https://i.imgur.com/XXX3Z9F.png =x80) --- ## 認識ROS指令格式 + roscore, roscd <br> + rosrun, roslaunch + {command} &nbsp;&nbsp; {pakage_name} &nbsp;&nbsp; {target_name} <br> + rosnode, rostopic, rosservice, rosmsg, rosparam + {command} &nbsp;&nbsp; {tool} &nbsp;&nbsp; (target_name) --- ## 認識Node + 啟動node ``` rosrun pakage_name node_name ``` + **rosnode** ``` rosnode ↹↹ ``` ![](https://i.imgur.com/xLqjm6a.png =x70) + 指令說明 ![](https://i.imgur.com/Wpn41Lh.png) --- ## rosnode command (在運行小烏龜的情況下) + rosnode list ![](https://i.imgur.com/ptoK4VR.png =x100) + rosnode info {node_name} ![](https://i.imgur.com/EE6kx0E.png) --- ## rosnode command (在運行小烏龜的情況下) + rosnode ping ![](https://i.imgur.com/0W60WyK.png) + rosnode machine (machine_name) ![](https://i.imgur.com/3O0Zfvh.png) --- ## rosnode command (在運行小烏龜的情況下) + rosnode kill {node_name} ![](https://i.imgur.com/eSr4PgA.png =x200) ![](https://i.imgur.com/yeYGpFm.png =x130) [ROS_graph](#13) --- ## 認識 Topic + **topic** ``` rostopic ↹↹ ``` ![](https://i.imgur.com/6xii2Re.png =x70) + 指令說明 ![](https://i.imgur.com/pWyCkQd.png) --- ## rostopic command (在運行小烏龜的情況下) + rostopic list ![](https://i.imgur.com/Oz5ecPh.png =x150) + rostopic info ![](https://i.imgur.com/rABEj9U.png) --- ## rostopic command (在運行小烏龜的情況下) + rostopic echo ![](https://i.imgur.com/AKd2Xjo.png) ![](https://i.imgur.com/BMOeXg1.png) (同時用key控制你的小烏龜~) --- ## rostopic command (在運行小烏龜的情況下) + rostopic hz /turtle1/pose + rostopic bw /turtle1/pose ![](https://i.imgur.com/siwyHEh.png) [ROS_graph](#13) --- ## 認識rqt + ROS視覺化工具 ``` rqt ``` ![](https://i.imgur.com/SC6jniU.png) --- ## ROS node 實做 ![](https://i.imgur.com/ZmrehUJ.png) --- ## ROS node 實做 ### 建立你的ROS workspace + 建立workspace folder ``` ~/$ mkdir my_ws ``` + 進入workspace folder ``` ~/$ cd my_ws ``` + 建立src folder ``` ~/my_ws$ mkdir src ``` + 用catkin建立環境 ``` ~/my_ws$ catkin_make ``` ![](https://i.imgur.com/qR6N3fe.png =x70) --- ## ROS node 實做 ### 建立你的ROS workspace + 將workspace加入環境並建立捷徑 + 確認setup.bash位置 (善用tab↹) ``` cat ~/Desktop/my_ws/devel/setup.bash ``` + 編輯 ~/.bashrc ``` vim ~/.bashrc ``` + 加入環境path ``` source ~/Desktop/my_ws/devel/setup.bash ``` ![](https://i.imgur.com/soIDn7P.png) + 使 ~/.bashrc 生效 ``` source ~/.bashrc ``` --- ## ROS node 實做 ### 建立你的ROS project + 進入src folder ``` ~/my_ws$ cd src ``` + 創建project catkin_create_pkg <package_name> [depend1] [depend2]... ``` ~/my_ws/src$ catkin_create_pkg my_first_project std_msgs rospy roscpp ``` ![](https://i.imgur.com/FkkJktB.png =100%x) --- ## ROS node 實做 ### 建立你的ROS project + 回到workspace目錄後build ``` ~/my_ws/src$ cd .. ~/my_ws$ catkin_make ``` ![](https://i.imgur.com/pYsCoZs.png) --- ## ROS node/topic 實做 ### 建立你的ROS project + 進入project folder ``` ~/my_ws$ cd src/my_first_project/ ~/my_ws/src/my_first_project$ ls ``` + package.xml 定義文件 ``` ~/my_ws/src/my_first_project$ vim package.xml ``` + + description ------功能描述 + maintainer ------作者資料 + license ------授權條款 + dependencies + CMakeLists.txt build用 ``` ~/my_ws/src/my_first_project$ vim CMakeLists.txt ``` --- ## ROS node 實做 + 前往你的project/src ``` ~/my_ws/src/my_first_project$ cd src ``` + 建立檔案 first_node.py ``` ~/my_ws/src/my_first_project/src$ vim first_node.py ``` + 建立node: init_node ( 'node名稱' , anonymous=True/False名稱是否加上隨機數) ```python= import rospy rospy.init_node('first_node') #same as file name i=0 while not rospy.is_shutdown(): print("node working",i) i=i+1 rospy.sleep(1) ``` --- ## ROS node 實做 + 直接啟動node(記得先開roscore) ![](https://i.imgur.com/H1u9WIU.png) + 查看node list ![](https://i.imgur.com/FySvzxn.png) --- ## ROS node 實做 + 改用rosrun啟動node + 在程式碼第一行加上Hashbang ```= #!/usr/bin/env python3 ... ``` + 將檔案設為執行檔 chmod +x file_name ``` ~/my_ws/src/my_first_project/src$ chmod +x first_node.py ``` ![](https://i.imgur.com/aRnCmCJ.png) + 用rosrun啟動node (善用tab↹) ( rosrun project_name file_name ) ![](https://i.imgur.com/m5AEBky.png) --- ## ROS node 實做 + log種類(層級) ```python= rospy.init_node('first_node', log_level=rospy.DEBUG) #same as file name print("node working",i) rospy.logdebug("node \"first_node\" sending message") rospy.loginfo("log info: 1+1=2") rospy.logwarn("log warn: battery low") rospy.logerr("log err: camera is dead") rospy.logfatal("log fatle: battery catch fire") ``` ![](https://i.imgur.com/Zyifc3i.png =x150) --- ## ROS topic 實做 ### 由node建立topic並發布消息 + import topic 要用的msg格式 ```python from std_msgs.msg import String ``` + 建立發布器: Publisher( 'topic名稱' , msg_type , queue_size=10) ```python pub = rospy.Publisher('chatter', String, queue_size=10) ``` + 用發布器發布消息 ```python publish_data = "node working "+str(i) pub.publish(publish_data) ``` --- ## ROS topic 實做 ### 由node建立topic並發布消息 ![](https://i.imgur.com/cbqVbOW.png) ![](https://i.imgur.com/eNx3g1A.png) --- ## ROS topic 實做 ### 由node建立topic並發布消息 + 正規msg寫法 ```python #publish_data = "node working "+str(i) msg = String() msg.data = str pub.publish(msg) ``` + ![](https://i.imgur.com/MYMoPy5.png =x150) + 若msg包含多個數值,須以此方式給值 --- ## ROS topic 實做 ### 利用rospy.Rate控制發布頻率 + 設定發布頻率 ```python rate = rospy.Rate(10) ``` + 更改sleep寫法 ```python #rospy.sleep(0.1) rate.sleep() ``` ![](https://i.imgur.com/o8g9Whx.png) --- ## ROS topic 實做 ### 利用rospy.Rate控制發布頻率 + rospy.sleep(0.1) 發布頻率受運算時間影響 + rospy.Rate(10) 頻率較準確 + ![](https://i.imgur.com/Xkaf1DT.png =x150) --- ## ROS topic 實做 ### 新增node接收topic消息 + 建立接收器: Subscriber( 'topic名稱' , msg_type , Callback_Function ) ```python #!/usr/bin/env python3 import rospy from std_msgs.msg import String def callback(data): print("I heard something: ", data.data) rospy.init_node('listener') rospy.Subscriber("chatter", String, callback) rospy.spin() ``` + ![](https://i.imgur.com/E3XkGdX.png) --- ## ROS topic 實做 ### 新增node接收topic消息 ![](https://i.imgur.com/jGt9raM.png) --- ## ROS topic 實做 ### Subscriber特性介紹 + Subscriber : ROS will call the chatterCallback() function whenever a new message arrives. ----> 有點像interrupt概念 + rospy.spin() : simply keeps your node from exiting until the node has been shutdown. ----> 等同於 while not rospy.is_shutdown() ```python while not rospy.is_shutdown(): for i in range(10): print("waiting for msg",i) rospy.sleep(0.3) #rospy.spin() ``` + ![](https://i.imgur.com/D3RSDr7.png =x150) [ROS_graph](#13) --- ## 認識 Service and Client + 啟動小烏龜+開啟鍵盤控制 ```text rosrun turtlesim turtlesim_node rosrun turtlesim turtle_teleop_key ``` + 指令說明 ![](https://i.imgur.com/PLMQ7SH.png =x250) --- ## 認識 Service and Client + rosservice info ![](https://i.imgur.com/98WWpam.png) + rosservice call ![](https://i.imgur.com/Q4IunO4.png) ![](https://i.imgur.com/c8nKolE.png =x150) ![](https://i.imgur.com/RBquCci.png =x90) --- ## 認識 Service and Client + rosservice info + rosservice call ![](https://i.imgur.com/ImPFYLJ.png) ![](https://i.imgur.com/s6qOozx.png =x300) --- ## ROS Service/Client 實做 service做加法後回傳client + 建立service node(記得用chmod改權限) ``` ~/my_ws/src/my_first_project/src$ vim service.py ``` ```python= #!/usr/bin/env python3 from rospy_tutorials.srv import AddTwoInts,AddTwoIntsResponse import rospy def handle_add_two_ints(req): print(req) print("Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))) response = AddTwoIntsResponse() response.sum = req.a + req.b return response rospy.init_node('add_two_ints_server') rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints) print("Ready to add two ints.") rospy.spin() ``` ![](https://i.imgur.com/wAd3VNh.png) --- ## ROS Service/Client 實做 service做加法後回傳client + 啟動service node(記得先開roscore) ``` rosrun project service.py ``` + 用rosservice call指令發送request ``` rosservice call /add_two_ints 1 1 ``` ![](https://i.imgur.com/IkODvXY.png =600x) ![](https://i.imgur.com/3Ddot0m.png =600x) --- ## ROS Service/Client 實做 service做加法後回傳client + 建立client (記得用chmod改權限) ``` ~/my_ws/src/my_first_project/src$ vim client.py ``` ```python= #!/usr/bin/env python3 import rospy from rospy_tutorials.srv import AddTwoInts,AddTwoIntsRequest print("waiting for service: add two ints") rospy.wait_for_service('add_two_ints') add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts) while not rospy.is_shutdown(): print("Input the value of a & b") a, b = map(int, input().split()) try: request = AddTwoIntsRequest() request.a = a request.b = b resp = add_two_ints(request) print("%s + %s = %s"%(a,b,resp.sum)) except rospy.ServiceException as e: print("Service call failed: %s"%e) ``` + ( 不用init node?? ) --- ## ROS Service/Client 實做 service做加法後回傳client + 啟動client(記得先開roscore 跟service) ![](https://i.imgur.com/qsGMd3X.png) [ROS_graph](#13) --- ## ROS msg/srv 介紹 ![](https://i.imgur.com/7my2WJx.png) wiki: md5sum是一種電腦程式,用於計算與校驗RFC 1321所描述的128位元MD5雜湊值,此處MD5雜湊值(或校驗和)作一個檔案的數字指紋使用。 --- ## ROS msg/srv 介紹 ![](https://i.imgur.com/11cCVer.png) ![](https://i.imgur.com/9QgkGYS.png) --- ## ROS 自定義 msg/srv http://wiki.ros.org/msg + 回到project資料夾並建立msg資料夾 + 建立你自己的msg file ```text= /my_ws/src/my_first_project/src$ cd .. /my_ws/src/my_first_project$ mkdir msg /my_ws/src/my_first_project$ cd msg /my_ws/src/my_first_project/msg$ vim my_control.msg ``` ```text= geometry_msgs/Twist twist int8 speed string color ``` --- ## ROS 自定義 msg/srv http://wiki.ros.org/msg 在package.xml加上兩行 ```text <build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend> ``` 編輯CMakeLists.txt 1. find_package ![](https://i.imgur.com/tmYj50x.png) --- ## ROS 自定義 msg/srv 2. add_message_files ![](https://i.imgur.com/xEm5ywV.png) 3. generate_messages ![](https://i.imgur.com/F16WQYh.png) 4. catkin_package ![](https://i.imgur.com/hbS0aPg.png) --- ## ROS 自定義 msg/srv + 在workspace資料夾build ``` /my_ws$ catkin_make ``` ![](https://i.imgur.com/dsXeO6x.png) --- ## ROS 自定義 msg/srv + 建立一鍵盤cmd publisher ```python= #!/usr/bin/env python3 import rospy from project.msg import my_control from pynput.keyboard import Listener,Key def on_press(key): global my_control_msg try: value = key.char except: print(key,end='\r') return flag=False if value=='w': my_control_msg.twist.linear.x = 1.0 flag=True if value=='1': my_control_msg.speed = 1 flag=True if value=='g': my_control_msg.color = 'green' flag=True if value=='o': my_control_msg = my_control() flag=True if flag: pub.publish(my_control_msg) print('\r ',end='\r') keyboard = Listener(on_press=on_press) rospy.init_node('pub_my_msg') pub = rospy.Publisher('my_cmd', my_control, queue_size=10) my_control_msg = my_control() keyboard.start() rospy.spin() keyboard.stop() ``` --- ## ROS 自定義 msg/srv + 回到project資料夾並建立srv資料夾 + 建立你自己的srv file ```text= /my_ws/src/my_first_project/src$ cd .. /my_ws/src/my_first_project$ mkdir srv /my_ws/src/my_first_project$ cd srv /my_ws/src/my_first_project/srv$ vim my_add_two_int.srv ``` ```text= int64 a int64 b --- int64 sum int64 mul float64 div string copm ``` --- ## ROS 自定義 msg/srv + 編輯CMakeLists.txt ![](https://i.imgur.com/37Sul9v.png) + 在workspace資料夾build ``` /my_ws$ catkin_make ``` ![](https://i.imgur.com/3tT9xeA.png) --- ## ROS 自定義 msg/srv + 建立自己的 add two int ```python= #!/usr/bin/env python3 from project.srv import my_add_two_int,my_add_two_intResponse import rospy def handle_add_two_ints(req): print(req) response = my_add_two_intResponse() response.sum = req.a + req.b response.mul = req.a * req.b response.div = req.a / req.b if req.a > req.b : response.copm = '>' elif req.a < req.b : response.copm = '<' elif req.a == req.b : response.copm = '=' return response rospy.init_node('my_add_two_int') rospy.Service('add_two_ints', my_add_two_int, handle_add_two_ints) print("Ready to add two ints.") rospy.spin() ``` --- ## ROS 自定義 msg/srv + 建立自己的 add two int ![](https://i.imgur.com/3vGcBD7.png) ![](https://i.imgur.com/SCrU5Jr.png) <style> .reveal { font-size: 24px; line-height: 110px; } .reveal .slides { text-align: left; } </style>
{"metaMigratedAt":"2023-06-17T14:49:11.951Z","metaMigratedFrom":"YAML","title":"ROS / ROS2 教學","breaks":true,"contributors":"[{\"id\":\"df131c7b-c358-40e5-ac23-6743dd1002f9\",\"add\":21065,\"del\":5057}]"}
    2137 views
   Owned this note