零蝕
這應該也會很困擾一些沒有過ros開發,又想直接ros2開始的人吧
開啟第一個ros2程式
-
從環境搭建開始
- 如果沒有經曆過ros的開發,在macos上開發ros2你可能會很淩亂,這些都是啥,到底該怎麼開發,用什麼ide,怎麼做才能讓開發變得簡潔。當有ros開發經驗後,你會發現其實我們要做的内容和之前大緻一樣(官網上啥都沒說,隻是說你打開你喜歡的編輯文本,現在能用文本編輯c++和python代碼)。
- 如果沒有ros開發和安裝經驗的話,可以先去看一下我的關于ros安裝和第一個程式
[ 🔗 NO.1 Ros 安裝&介紹 ]
[ 🔗 NO.2 Ros 第一個程式(cpp & py)]。
~/ros2/install/setup.bash ~/ros2/ros2-osx/setup.bash
- 然後我們建立我們包,在src的路徑下,這裡和ros就大不同了,ros感覺比較雜揉,它裡面是cpp和python在一起開發(我之前用的是clion),項目裡有個頂層CmakeLists來管理項目,c++可能需要用到catkin cmake來重新建構項目,但是如果在裡面編輯python代碼,完全是不必要的,是以這就很亂,而且,python和c++可以編輯相同的功能,就會顯得沒必要在一起混合開發,用某一個語言不就可以了?,當然ros2網上還闡述了很多優點(對标ros)。然後ros2 就被拆開了,python做python項目,c++做c++項目,這裡的build-type就是限定做的項目類型,但不能将兩個項目類型放在一起。
是将目前的運作環境設定為ros的專屬環境。. install/local_setup.bash
cd ~/ws/src #cpp ros2 pkg create --build-type ament_cmake <package_name> ros2 pkg create --build-type ament_cmake --node-name my_node my_package #python ros2 pkg create --build-type ament_python <package_name> ros2 pkg create --build-type ament_python --node-name my_node my_package # 建構 cd ~/ws colcon build colcon build --packages-select my_package # 将軟體包添加到目前路徑的環境中 . install/local_setup.bash
- 然後就是如何編輯代碼,如果你是沒有開發過ros,大機率是輕按兩下clion或者pycharm,但是打開你會發現,clion不能解析CmakeLists檔案,pycharm也不能
(這個等同于ros中的rospy,ros的python庫)。項目在建構的時候就找不到ros2的運作庫,哪怕你将python位址改成ros2安裝的[email protected]也不行。import rclpy
- 回想ros不難發現,ros開發(基于ubuntu的linux)它是将項目在ros的運作環境下打開的,比如
,它是在ros的運作環境中打開了軟體的shell運作腳本,是以ros2必然也是這樣,在尋找中我發現了如下兩個執行檔案,在合理的猜測下解決了編譯器的問題sh clion.sh
# cpp 和ros一樣是打開CmakeLists檔案 /Applications/Clion.app/Contents/MacOS/clion # python /Applications/PyCharm.app/Contents/MacOS/pycharm
- 然後我們先看一下clion,運作後是這樣當我們打開了clion之後open項目,選擇我們cpp項目的頂層CMakelists之後,我們可以看到Cmake (Debug)建構完成,表示項目已經建構成功。反之如果出現報錯,則是不是ros環境中打開,導緻找不到調用的庫。
- 然後我們看一下python,python開發就簡單許多了,因為完全用不到頂層CMakeLists是以我們不需要以項目的形式打開某個檔案,直接用PyCharm正常打開項目就行,如果導入rclpy沒有報錯,說明打開成功,反之沒有在環境中打開項目。
- 項目建立就到這,這些都是官網甚至外網都沒解決的問題,其實也就是舉一反三的事,并沒什麼,但沒必要在這方面浪費時間,最後來看一下運作項目,作為一個有折騰過ros經驗的人,能清楚的知道,我們不能在IDE圖示上點選運作,因為這樣是錯的,很多東西不會在環境中生效,是以老規矩,指令行(以python項目為例):
小知識點
-
launch
- launch的功能是為了一次性開啟多個node,因為我們可能編輯了很多node,為了友善同時開啟,ros是加入了launch這個啟動項,ros中launch 是在項目下的 launch檔案夾中進行編寫,而ros2項目進行了拆分,是以launch是在項目之外建立的。這裡我是在ros_ws目錄下建構的。然後重點是我運作官網的案例報錯了,經過認真比對錯誤日志,我發現,官網的寫法在我這是有問題的,如果想運作多個node的正确寫法應該如下:
rom launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( package='turtlesim', node_executable='turtlesim_node', name='sim1' ), Node( package='turtlesim', node_executable='turtlesim_node', name='sim2' ) ])
ros2 launch turtlesim_minic_test_launch.py
- 為了更好了解節點之間的關系,我們可以使用rqt_graph
- 檢視ros2的日志消息使用rqt_console
ros2 run rqt_console rqt_console
- 展示所有的topic
,如果想知道topic所攜帶message的類型可使用ros2 topic list
ros2 topic list -t
ROS2 開發
-
topic開發(Python)
- topic就是一個消息池,功能和UDP類似。代碼如下:
# publish import rclpy from rclpy.node import Node from std_msgs.msg import String import time def main(args=None): rclpy.init(args=args) # 建構一個node node = Node("my_demo_publish") # 建構一個publish publish = node.create_publisher(String, 'my_topic', 100) for i in range(0, 9): content = String() content.data = "消息的index:"+str(i) publish.publish(content) node.get_logger().info('Publishing: "%s"' % content.data) time.sleep(1) rclpy.spin(node) if __name__ == '__main__': main() # Subscribe import rclpy from rclpy.node import Node from std_msgs.msg import String node = None # 監聽的回調函數 def call_bask(msg): node.get_logger().info('Publishing: "%s"' % msg.data) def main(args=None): rclpy.init(args=args) # 建構一個node global node node = Node("my_demo_subscribe") # 建構一個subscribe subscribe = node.create_subscription(String, 'my_topic', call_bask, 100) rclpy.spin(node) if __name__ == '__main__': main()
- 檔案名分别對應publish–>py_my_demo,subscribe–>py_my_demo1,然後我們将其建構到我們的build裡面去。首先我們要在setup.py中添加我們node,
entry_points={ 'console_scripts': [ 'py_my_demo = py_demo.py_my_demo:main', 'py_my_demo1 = py_demo.py_my_demo1:main' ], },
- 然後建構項目
colcon build --packages-select py_demo ros2 run py_demo py_my_demo1 ros2 run py_demo py_my_demo
- 輸出内容👌
# publish [INFO] [my_demo_publish]: Publishing: "消息的index:0" [INFO] [my_demo_publish]: Publishing: "消息的index:1" [INFO] [my_demo_publish]: Publishing: "消息的index:2" [INFO] [my_demo_publish]: Publishing: "消息的index:3" [INFO] [my_demo_publish]: Publishing: "消息的index:4" [INFO] [my_demo_publish]: Publishing: "消息的index:5" [INFO] [my_demo_publish]: Publishing: "消息的index:6" [INFO] [my_demo_publish]: Publishing: "消息的index:7" [INFO] [my_demo_publish]: Publishing: "消息的index:8" # subscribe [INFO] [my_demo_subscribe]: Publishing: "消息的index:0" [INFO] [my_demo_subscribe]: Publishing: "消息的index:1" [INFO] [my_demo_subscribe]: Publishing: "消息的index:2" [INFO] [my_demo_subscribe]: Publishing: "消息的index:3" [INFO] [my_demo_subscribe]: Publishing: "消息的index:4" [INFO] [my_demo_subscribe]: Publishing: "消息的index:5" [INFO] [my_demo_subscribe]: Publishing: "消息的index:6" [INFO] [my_demo_subscribe]: Publishing: "消息的index:7" [INFO] [my_demo_subscribe]: Publishing: "消息的index:8"
-
topic開發(Cpp)
- 在開發c++的功能時候需要先在CMakeLists中導入對應的庫
- 然後我們看一下cpp的代碼實作。官網上都是以類的形式,我覺得沒必要,我這都簡化了。
// publish #include <cstdio> #include <chrono> #include <memory> #include <iostream> #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp" using namespace std; int main(int argc, char **argv) { rclcpp::init(argc,argv); //建立一個publish auto node = rclcpp::Node::make_shared("cpp_demo_publisher"); //建構推送 auto publisher=node->create_publisher<std_msgs::msg::String>("my_topic",10); auto message = std_msgs::msg::String(); //1s内執行的速度 rclcpp::WallRate rate(1); for (int i = 0; i < 10; ++i) { message.data="這index值是:"+std::to_string(i); RCLCPP_INFO(node->get_logger(),"cpp publisher:%s",message.data.c_str()); publisher->publish(message); rclcpp::spin_some(node); rate.sleep(); } rclcpp::shutdown(); return 0; } // subscribe #include <memory> #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp" using std::placeholders::_1; int main(int argc, char * argv[]){ rclcpp::init(argc, argv); auto node = rclcpp::Node::make_shared("cpp_demo_subscribe"); rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscriber = node->create_subscription<std_msgs::msg::String>("my_topic",10,[node](std_msgs::msg::String::SharedPtr msg){ RCLCPP_INFO(node->get_logger(), "I heard: '%s'", msg->data.c_str()); }); rclcpp::spin(node); rclcpp::shutdown(); return 0; }
- 後面的功能開發不再送出,後面筆記會再次從 攝像頭 生成點雲圖開始,主要内容是ROS2+kinect2驅動開發。
🔗 前言
🔗 Robot ROS 作業系統清單
🔗 NO.1 Ros 安裝&介紹
🔗 NO.2 Ros 第一個程式(cpp & py)
🔗 NO.3 Ros Topic 通訊
🔗 NO.4 Ros 消息補充&小烏龜
🔗 NO.5 Ros Turtle &日志開發
🔗 NO.6 Ros Service 簡單通訊
🔗 NO.7 Ros Service 複雜通訊
🔗 NO.8 Ros PID算法案例
🔗 NO.9 PID原理&曲線計算原理
🔗 NO.10 Action 通訊 上
🔗 NO.11 Action 通訊 下
🔗 NO.12 Param & Launch & TF 案例
🔗 NO.13 ROS 2 Foxy安裝(Mac OS)