注:已從RoboMaster退隊,懶得更新
第一章 ros2介紹
1.1 ros為什麼會出現
做一個機器人是非常複雜的一件事情,因為一個機器人需要涉及到多個部分,而且這些部分之間還要進行通訊。
例如設計一個像下圖一樣的輪式移動機器人,我們對其進行拆解。可以分為感知、決策、控制三個部分
- 感知部分有:鐳射雷達、深度相機、IMU、里程計、碰撞感知、建圖
- 決策部分有:路徑規劃(navigation)演算法、定位演算法
- 控制部分有:輪子驅動
1.2 ros與ros2對比
上節課說到ROS的設計目標是簡化機器人的開發,如何簡化呢?ROS為此設計了一整套通訊機制(話題、服務、引數、動作)。
透過這些通訊機制,ROS實現了將機器人的各個元件給的連線起來,在設計這套通訊機制的時候就設計了一個叫做Ros Master
的東西,所有節點(可以理解為某一個元件,比如:鐳射雷達)的通訊建立必須經過這個主節點。
一旦Ros Master
主節點掛掉後,就會造成整個系統通訊的異常,此時避障策略將會失效,如果機器人正在執行,碰到障礙物會徑直裝上去,機毀人亡!
除了不穩定這個問題,ROS還有很多其他地方存在著問題:
- 通訊基於TCP實現,實時性差、系統開銷大
- 對Python3支援不友好,需要重新編譯
- 訊息機制不相容
- 沒有加密機制、安全性不高
中間層:去中心化Ros Master,各個節點採用DDS通訊,使得ROS2的實時性、可靠性和連續性上都有了增強。
第二章 準備環境與安裝ROS2
2.1 安裝虛擬機器和Ubuntu
略
2.2安裝ros
- Ubuntu20.04->foxy
- Ubuntu22.04->humble
- 魚香肉絲一鍵安裝ros2:
wget http://fishros.com/install -O fishros && bash fishros
2.3 VsCode編輯器安裝與配置
- 下載:https://code.visualstudio.com/docs/?dv=linux64_deb
- 安裝
sudo dpkg -i code_1.58.0-1625728071_amd64.deb
第三章 ROS2基礎
3.1 節點介紹
節點與節點之間必須要通訊,那他們之間該如何通訊呢?ROS2早已為你準備好了一共四種通訊方式:
- 話題-topics
- 服務-services
- 動作-Action
- 引數-parameters
啟動節點ros2 run <package_name> <executable_name>
(指令意義:啟動 包下的 中的節點。)
檢視節點列表ros2 node list
檢視節點資訊ros2 node info <node_name>
3.2 ROS2工作空間與功能包
一個工作空間下可以有多個功能包,一個功能包可以有多個節點存在。
- 工作空間:工作空間是包含若干個功能包的目錄,一開始大家把工作空間理解成一個資料夾就行了。
- 功能包:功能包可以理解為存放節點的地方,ROS2中功能包根據編譯方式的不同分為三種型別。
- ament_python,適用於python程式
- cmake,適用於C++
- ament_cmake,適用於C++程式,是cmake的增強版
功能包的獲取
- 安裝獲取:
sudo apt install ros-<version>-package_name
(安裝獲取會自動放置到系統目錄,不用再次手動source。) - 手動編譯獲取:手動編譯相對麻煩一些,需要下載原始碼然後進行編譯生成相關檔案。(手動編譯之後,需要手動source工作空間的install目錄。)
功能包的相關指令
- 建立功能包
ros2 pkg create <package-name> --build-type {cmake,ament_cmake,ament_python} --dependencies <依賴名字>Copy to clipboard
- 列出可執行檔案
ros2 pkg executables
- 列出某個功能包
ros2 pkg executables turtlesim
- 列出所有包
ros2 pkg list
- 列出某個包所在路徑的字首
ros2 pkg prefix <package-name>
- 列出包的清單描述檔案(每一個功能包都有一個標配的manifest.xml檔案,用於記錄這個包的名字,構建工具,編譯資訊,擁有者,幹啥用的等資訊。)
ros2 pkg xml turtlesim
3.3 ROS2的編譯器Colcon
##小練習
#建立工作空間
mkdir -p turtle_ws/src
cd turtle_ws/src
#下載原始碼功能包到工作空間的src檔案下
git clone https://github.com/fishros/turtle_battle.git
#進入工作空間上一級編譯
cd ..
colcon build
#source空間
source install/setup.bash
#啟動遊戲節點
##開啟一個新終端,進入turtle_ws工作空間,啟動以下節點:
ros2 run turtle_battle turtle_spawner
#啟動烏龜模擬器
##開啟一個新終端,進入turtle_ws工作空間,啟動以下節點:
ros2 run turtlesim turtlesim_node
#開啟遙控器節點
##開啟一個新終端,進入turtle_ws工作空間,啟動以下節點:
ros2 run turtlesim turtle_teleop_key
建立工作空間和功能包
#建立工作空間
mkdir -p town_ws/src
cd town_ws/src
#建立一個功能包
ros2 pkg create village_li --build-type ament_python --dependencies rclpy
#建立節點檔案
##在__init__.py同級別目錄下建立一個叫做li4.py的檔案
使用POP(程序導向程式設計)方法編寫一個節點
#開啟lib4.py
import rclpy
from rclpy.node import Node
def main(args=None):
"""
ros2執行該節點的入口函式
編寫ROS2節點的一般步驟
1. 匯入庫檔案
2. 初始化客戶端庫
3. 新建節點物件
4. spin迴圈節點
5. 關閉客戶端庫
"""
rclpy.init(args=args) # 初始化rclpy
node = Node("li4") # 新建一個節點
node.get_logger().info("大家好,我是作家li4.")
rclpy.spin(node) # 保持節點執行,檢測是否收到退出指令(Ctrl+C)
rclpy.shutdown() # 關閉rclpy
#修改setup.py
##增加一句話,告訴ros2村莊來了一位新村民李四,要找這位村民去village_li.li4:main路徑下尋找。
entry_points={
'console_scripts': [
"li4_node = village_li.li4:main"
],
},
)
#編譯,source
#執行節點
ros2 run village_li li4_node
物件 = 屬性+行為
如果只需要實現一個很簡單的功能,比如只是做一個鍵盤控制器,實現控制小車前進後退,直接採用程序導向的設計思想即可。但如果是做一個稍大的工程,且後續要考慮功能的擴充性,這個時候就需要採用物件導向的思路來了。
使用OOP(物件導向程式設計)方法編寫一個節點
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
class WriterNode(Node):
"""
建立一個作家節點,並在初始化時輸出一個話
"""
def __init__(self,name):
super().__init__(name)
self.get_logger().info("大家好,我是%s,我是一名作家!" % name)
def main(args=None):
"""
ros2執行該節點的入口函式
1. 匯入庫檔案
2. 初始化客戶端庫
3. 新建節點
4. spin迴圈節點
5. 關閉客戶端庫
"""
rclpy.init(args=args) # 初始化rclpy
node = WriterNode("li4") # 新建一個節點
rclpy.spin(node) # 保持節點執行,檢測是否收到退出指令(Ctrl+C)
rclpy.shutdown() # 關閉rclpy
#修改setup.py
##增加一句話,告訴ros2村莊來了一位新村民李四,要找這位村民去village_li.li4:main路徑下尋找。
entry_points={
'console_scripts': [
"li4_node = village_li.li4:main"
],
},
)
#編譯,source
#執行節點
ros2 run village_li li4_node
POP使用C++編寫節點並測試
#建立一個C++功能包
ros2 pkg create village_wang --build-type ament_cmake --dependencies rclcpp
#建立一個節點
##接著我們在village_wang/src下建立一個wang2.cpp檔案
//POP
#include "rclcpp/rclcpp.hpp"
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
/*產生一個Wang2的節點*/
auto node = std::make_shared<rclcpp::Node>("wang2");
// 列印一句自我介紹
RCLCPP_INFO(node->get_logger(), "大家好,我是單身狗wang2.");
/* 執行節點,並檢測退出訊號*/
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
//OOP
#include "rclcpp/rclcpp.hpp"
/*建立一個類節點,名字叫做SingleDogNode,繼承自Node.*/
class SingleDogNode : public rclcpp::Node
{
public:
// 建構函式,有一個引數為節點名稱
SingleDogNode(std::string name) : Node(name)
{
// 列印一句自我介紹
RCLCPP_INFO(this->get_logger(), "大家好,我是單身狗%s.",name.c_str());
}
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
/*產生一個Wang2的節點*/
auto node = std::make_shared<SingleDogNode>("wang2");
/* 執行節點,並檢測退出訊號*/
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
#新增到CmakeLists
##在CmakeLists.txt最後一行加入下面兩行程式碼。(新增這兩行程式碼的目的是讓編譯器編譯wang2.cpp這個檔案,不然不會主動編譯。)
add_executable(wang2_node src/wang2.cpp)
ament_target_dependencies(wang2_node rclcpp)
#接著在上面兩行程式碼下面新增下面的程式碼。(這個是C++比Python要麻煩的地方,需要手動將編譯好的檔案安裝到install/village_wang/lib/village_wang下)
install(TARGETS
wang2_node
DESTINATION lib/${PROJECT_NAME}
)
第四章 通訊機制-話題與服務
我們讓王二(Node)透過訂閱(Subscribe)李四(Node)釋出(Publish)的《豔娘傳奇》(Topic)來欣賞小說的。
4.1 話題
需要滿足以下規則:
- 話題名字是關鍵,釋出訂閱介面型別要相同,釋出的是字串,接受也要用字串來接收;
- 同一個人(節點)可以訂閱多個話題,同時也可以釋出多個話題,就像一本書的作者也可以是另外一本書的讀者;
- 同一個小說不能有多個作者(版權問題),但跟小說不一樣,同一個話題可以有多個釋出者。
工具RQT之rqt_graph
ros2 run demo_nodes_py listener
ros2 run demo_nodes_cpp talker
rqt_graph
- ROS2作為一個強大的工具,在執行過程中,我們是可以透過命令來看到節點和節點之間的資料關係的。
ROS2話題相關命令列介面(CLI)
ros2 topic -h
返回系統中當前活動的所有主題的列表:ros2 topic list
接著上一條,增加訊息型別:ros2 topic list -t
列印實時話題內容:ros2 topic echo /chatter
檢視主題內容:ros2 topic info /chatter