ROS學習


隨着機器人領域的快速發展和復雜化,代碼的復用性和模塊化的需求原來越強烈,而已有的開源機器人系統又不能很好的適應需求。2010年Willow Garage公司發布了開源機器人操作系統ROS(robot operating system),很快在機器人研究領域展開了學習和使用ROS的熱潮。 
 
機器人操作系統ROS(Robot Operating System)是一個用於編寫機器人軟件的靈活框架,它集成了大量的工具、庫、協議,提供類似操作系統所提供的功能,包括硬件抽象描述、底層驅動程序管理、共用功能的執行、程序間的消息傳遞、程序發行包管理,可以極大簡化繁雜多樣的機器人平台下的復雜任務創建與穩定行為控制。 
1. ROS的核心是一個分布式、低耦合的通訊機制; 
2. ROS提供多種機器人開發工具,可以快速實現數據可視化、機器人仿真等功能; 
3. ROS開源社區中包含大量機器人應用功能,可以幫助我們快速開發功能原型; 
4. ROS已經成為一個龐大的生態系統,包含機器人領域的方方面面,同時也得到了越來越多第三方工具的支持,為機器人開發提供了系統化的解決方案。

二、設計目標

ROS是開源的,是用於機器人的一種后操作系統,或者說次級操作系統。它提供類似操作系統所提供的功能,包含硬件抽象描述、底層驅動程序管理、共用功能的執行、程序間的消息傳遞、程序發行包管理,它也提供一些工具程序和庫用於獲取、建立、編寫和運行多機整合的程序。 
 
ROS的首要設計目標是在機器人研發領域提高代碼復用率。ROS是一種分布式處理框架(又名Nodes)。這使可執行文件能被單獨設計,並且在運行時松散耦合。這些過程可以封裝到數據包(Packages)和堆棧(Stacks)中,以便於共享和分發。ROS還支持代碼庫的聯合系統。使得協作亦能被分發。這種從文件系統級別到社區一級的設計讓獨立地決定發展和實施工作成為可能。上述所有功能都能由ROS的基礎工具實現。

三、主要特點

ROS的運行架構是一種使用ROS通信模塊實現模塊間P2P的松耦合的網絡連接的處理架構,它執行若干種類型的通訊,包括基於服務的同步RPC(遠程過程調用)通訊、基於Topic的異步數據流通訊,還有參數服務器上的數據存儲。但是ROS本身並沒有實時性。 
ROS的主要特點可以歸納為以下幾條:

(1)點對點設計 
這里寫圖片描述

一個使用ROS的系統包括一系列進程,這些進程存在於多個不同的主機並且在運行過程中通過端對端的拓撲結構進行聯系。雖然基於中心服務器的那些軟件框架也可以實現多進程和多主機的優勢,但是在這些框架中,當各電腦通過不同的網絡進行連接時,中心數據服務器就會發生問題。 
ROS的點對點設計以及服務和節點管理器等機制可以分散由計算機視覺和語音識別等功能帶來的實時計算壓力,能夠適應多機器人遇到的挑戰。

(2)多語言支持

在寫代碼的時候,許多編程者會比較偏向某一些編程語言。這些偏好是個人在每種語言的編程時間、調試效果、語法、執行效率以及各種技術和文化的原因導致的結果。為了解決這些問題,我們將ROS設計成了語言中立性的框架結構。ROS現在支持許多種不同的語言,例如C++、Python、Octave和LISP,也包含其他語言的多種接口實現。 
 
ROS的特殊性主要體現在消息通訊層,而不是更深的層次。端對端的連接和配置利用XML-RPC機制進行實現,XML-RPC也包含了大多數主要語言的合理實現描述。我們希望ROS能夠利用各種語言實現的更加自然,更符合各種語言的語法約定,而不是基於C語言給各種其他語言提供實現接口。然而,在某些情況下利用已經存在的庫封裝后支持更多新的語言是很方便的,比如Octave的客戶端就是通過C++的封裝庫進行實現的。 
為了支持交叉語言,ROS利用了簡單的、語言無關的接口定義語言去描述模塊之間的消息傳送。接口定義語言使用了簡短的文本去描述每條消息的結構,也允許消息的合成,例如下圖就是利用接口定義語言描述的一個點的消息: 
這里寫圖片描述

每種語言的代碼產生器就會產生類似本種語言目標文件,在消息傳遞和接收的過程中通過ROS自動連續並行的實現。這就節省了重要的編程時間,也避免了錯誤:之前3行的接口定義文件自動的擴展成137行的C++代碼,96行的Python代碼,81行的Lisp代碼和99行的Octave代碼。因為消息是從各種簡單的文本文件中自動生成的,所以很容易列舉出新的消息類型。在編寫的時候,已知的基於ROS的代碼庫包含超過四百種消息類型,這些消息從傳感器傳送數據,使得物體檢測到了周圍的環境。

最后的結果就是一種語言無關的消息處理,讓多種語言可以自由的混合和匹配使用。

(3)精簡與集成

大多數已經存在的機器人軟件工程都包含了可以在工程外重復使用的驅動和算法,不幸的是,由於多方面的原因,大部分代碼的中間層都過於混亂,以至於很困難提取出它的功能,也很難把它們從原型中提取出來應用到其他方面。 
為了應對這種趨勢,我們鼓勵將所有的驅動和算法逐漸發展成為和ROS沒有依賴性單獨的庫。ROS建立的系統具有模塊化的特點,各模塊中的代碼可以單獨編譯,而且編譯使用的CMake工具使它很容易的就實現精簡的理念。ROS基本將復雜的代碼封裝在庫里,只是創建了一些小的應用程序為ROS顯示庫的功能,就允許了對簡單的代碼超越原型進行移植和重新使用。作為一種新加入的有優勢,單元測試當代碼在庫中分散后也變得非常的容易,一個單獨的測試程序可以測試庫中很多的特點。 
ROS利用了很多現在已經存在的開源項目的代碼,比如說從Player項目中借鑒了驅動、運動控制和仿真方面的代碼,從OpenCV中借鑒了視覺算法方面的代碼,從OpenRAVE借鑒了規划算法的內容,還有很多其他的項目。在每一個實例中,ROS都用來顯示多種多樣的配置選項以及和各軟件之間進行數據通信,也同時對它們進行微小的包裝和改動。ROS可以不斷的從社區維護中進行升級,包括從其他的軟件庫、應用補丁中升級ROS的源代碼。

(4)工具包豐富

為了管理復雜的ROS軟件框架,我們利用了大量的小工具去編譯和運行多種多樣的ROS組建,從而設計成了內核,而不是構建一個龐大的開發和運行環境。 
 
這些工具擔任了各種各樣的任務,例如,組織源代碼的結構,獲取和設置配置參數,形象化端對端的拓撲連接,測量頻帶使用寬度,生動的描繪信息數據,自動生成文檔等等。盡管我們已經測試通過像全局時鍾和控制器模塊的記錄器的核心服務,但是我們還是希望能把所有的代碼模塊化。我們相信在效率上的損失遠遠是穩定性和管理的復雜性上無法彌補的。

(5)免費並且開源

ROS所有的源代碼都是公開發布的。我們相信這將必定促進ROS軟件各層次的調試,不斷的改正錯誤。雖然像Microsoft Robotics Studio和Webots這樣的非開源軟件也有很多值得贊美的屬性,但是我們認為一個開源的平台也是無可為替代的。當硬件和各層次的軟件同時設計和調試的時候這一點是尤其真實的。 
 
ROS以分布式的關系遵循這BSD許可,也就是說允許各種商業和非商業的工程進行開發。ROS通過內部處理的通訊系統進行數據的傳遞,不要求各模塊在同樣的可執行功能上連接在一起。如此,利用ROS構建的系統可以很好的使用他們豐富的組件:個別的模塊可以包含被各種協議保護的軟件,這些協議從GPL到BSD,但是許可的一些“污染物”將在模塊的分解上就完全消滅掉。 
參考資料: 
(1)《開源機器人操作系統——ROS》 張建偉等著 
(2)《an open-source Robot Operating System》 paper 
(3) willowgarage公司網站:http://www.willowgarage.com/ 
(4) ROS官方wiki:http://www.ros.org

 

添加軟件庫到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'

設置秘鑰

sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116

安裝ROS

更新軟件

sudo apt-get update

桌面完整安裝

sudo apt-get install ros-indigo-desktop-full

初始化rosdep

sudo rosdep init rosdep update
  • 配置環境
  • 如果ROS環境變量在每次啟動新shell時自動添加到bash會話中,這會很方便:
echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc source ~/.bashrc
  • 如果您安裝了多個ROS分發版,~/.bashrc只能為當前使用的版本提供setup.bash。
  • 如果只想更改當前shell的環境,則可以鍵入:
source /opt/ros/indigo/setup.bash

安裝rosinstall

rosinstall是ROS中經常使用的命令行工具,可單獨分發。 它可以使用一個命令輕松下載ROS軟件包的許多源代碼樹。

sudo apt-get install python-rosinstall

驗證是否安裝成功

打開終端,輸入以下命令:

$ roscore

更多內容:--------------http://wiki.ros.org/cn/ROS/Tutorials


ros使用時的注意事項&技巧

1.rosrun package-name executable-name 比如 rosrun turtlesim turtlesim_node

2.一旦啟動roscore后,便可以運行ROS程序了。ROS程序的運行實例被稱為節點(node),roscore叫做節點管理器

3.查看節點列表rosnode list

4.需要注意節點名並不一定與對應可執行文件名稱相同

5.可以使用 rosrun 命令顯式設置節點的名稱rosrun package-name executable-name __name:=node-name這種方法將使用 node-name 參數給出的名稱覆蓋節點的默
認名。

6.查看節點信息rosnode info node-name 終止節點 rosnode kill node-name

7.用 Ctrl-C 命令終止節點。但使用這種方法時可能不會在節點管理器中注銷該節點,因此會導致已終止的節點仍然在 rosnode 列表中。這雖然沒有什么壞處,但可能會讓用戶對當前系統的行為感到困擾。此時可以使用下面的命令將節點從列表中刪除:rosnode cleanup

8.ROS節點之間進行通信所利用的最重要的機制就是消息傳遞。在ROS中,消息有組織地存放在話題里。消息傳遞的理念是:當一個節點想要分享信息時,它就會發布(publish)消息到對應的一個或者多個話題;當一個節點想要接收信息時,它就會訂閱(subscribe)它所需要的一個或者多個話題。ROS節點管理器負責確保發布節點和訂閱節點能找到對方;而且消息是直接地從發布節點傳遞到訂閱節點,中間並不經過節點管理器轉交

9.在 ROS 系統中查看節點之間的發布-訂閱關系的最簡單方式就是在終端輸入如下命令:rqt_graph

10.所有的節點發布都向話題/rosout 發布消息,該話題由同名的/rosout 節點訂閱。這個話題的作用是用來生成各個節點的文本日志消息。

11.ROS 節點通常設計成了只管發布它們有用的信息,而不需要擔心是否有其他節點來訂閱這些消息。這樣有助於減少各個節點之間的耦合度。

12.獲得話題列表 rostopic list這個列表列舉的話題和 rqt_graph 中展示的話題應該是一樣的。

13.打印消息內容 rostopic echo topic-name

14.測量發布頻率rostopic hz topic-name,帶寬rostopic bw topic-name

15.查看話題rostopic info topic-name,可以獲得消息類型等信息

16.查看消息類型rosmsg show message-type-name

17.用命令發布消息rostopic pub –r rate-in-hz topic-name message-type message-content,如rostopic pub –r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[2,0,0]’ ’[0,0,0]’

18.問題檢查:roswtf

19.創建工作區caktin_ws並創建src子目錄用於存放功能包代碼,mkdir -p ~/catkin_ws/src

20.src目錄下創建功能包catkin_create_pkg package-name,會產生兩個文件package.xml和CMakeLists.txt

21.頭文件 ros/ros.h 包含了標准 ROS 類的聲明,你將會在每一個你寫的 ROS 程序中包含它。下面是一個ros helloworld程序

// This is a ROS version of the standard "hello , world" // program. // This header defines the standard ROS classes . #include <ros / ros.h> int main ( int argc , char ** argv ) { // Initialize the ROS system . ros::init ( argc , argv , " hello _ros " ) ; // Establ ish this program as a ROS node . ros::NodeHandle nh ; // Send some output as a log message . ROS_INFO_STREAM( " Hello , ␣ ROS! " ) ; }

22.編譯hello程序
(1)聲明依賴庫
在CmakeList.txt中修改 find_package(catkin REQUIRED COMPONENTS package-names)
在package.xml中修改<build_depend>package-name,<run_depend>package-name例如這里的package-name應該是roscpp
(2)聲明可執行文件
在CmakeList.txt中add_executable(executable-name source-files),target_link_libraries(executable-name ${catkin_LIBRARIES})
(3)編譯工作區catkin_make
(4)Sourcing setup.bash source devel/setup.bash

23.執行hello程序,rosrun 包名 可執行文件名


編寫一個發布者程序

#include <ros/ros.h> #include <geometry_msgs/Twist.h> // For geometry_msgs:: Twist #include <stdlib.h> // For rand() and RAND_MAX int main (int argc, char** argv) { // Initialize the ROS system and become a node . ros::init(argc, argv, "publish_velocity"); ros::NodeHandle nh; // Create a publisher obj ect . ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("turtle1/cmd_vel", 1000) ; // Seed the random number generator . srand(time(0)); // Loop at 2Hz until the node is shut down. ros::Rate rate(2); while(ros::ok()) { // Create and fill in the message. The other four // fields, which are ignored by turtlesim, default to 0. geometry_msgs::Twist msg; msg.linear.x = double(rand()) / double(RAND_MAX); msg.angular.z = 2 * double(rand()) / double(RAND_MAX) - 1; // Publish the message . pub.publish(msg); // Send a message to rosout with the details . ROS_INFO_STREAM("Sending random velocity command : "<<" linear=" << msg.linear.x<< " angular=" << msg.angular.z); // Wait untilit's time for another iteration . rate.sleep(); } } 

上面程序用來給turtlesim仿真器中的海龜發布隨機生成的指令,在添加完依賴后,執行結果如下圖
1


編寫一個訂閱者程序
我們繼續使用 turtlesim 作為測試平台,訂閱 turtlesim_node發布的/turtle1/pose 話題。這一話題的消息描述了海龜的位姿(位置和朝向)。
這里有三點需要注意:
1)編寫回調函數
發布和訂閱消息的一個重要的區別是訂閱者節點無法知道消息什么時候到達。為了應對這一事實,我們必須把響應收到消息事件的代碼放到回調函數里,ROS 每接收到一個新的消息將調用一次這個函數。訂閱者的回調函數類似於:

void function_name(const package_name::type_name &msg) { }

其中參數 package_name 和 type_name 和發布消息時的相同,它們指明了我們想訂閱的話題的消息類。回調函數的主體有權限訪問接收到消息的所有域,並以它認為合適的方式存儲、使用或丟棄接收到的數據。與往常一樣,我們必須包含定義該類的頭文件。

2)創建訂閱者對象
為了訂閱一個話題,我們需要創建一個ros::Subscriber對象 :
ros::Subscriber sub = node_handle.subscribe(topic_name,queue_size, pointer_to_callback_function);
這個構造函數有三個形參,其中大部分與 ros::Publisher 聲明中的類似,最后一個參數是回調函數的指針

3)給ROS控制權
最后的復雜之處在於只有當我們明確給ROS許可時,它才會執行我們的回調函數 。實際上有兩個略微不同的方式來做到這一點,其中一個版本如下所示:

ros::spinOnce();

這個代碼要求 ROS 去執行所有掛起的回調函數,然后將控制權限返回給我們。另一個方法如下所示:

ros::spin();

這個方法要求 ROS 等待並且執行回調函數,直到這個節點關機。換句話說,ros::spin()大體等於這樣一個循環:

while(ros::ok( )) { ros::spinOnce(); }

使用 ros::spinOnce()還是使用 ros::spin()的建議如下:你的程序除了響應回調函數,還有其他重復性工作要做嗎?如果答案是“否”,那么使用 ros::spin();否則,合理的選擇是寫一個循環,做其他需要做的事情,並且周期性地調用 ros::spinOnce()來處理回調。
訂閱者代碼

// This program subscribes to turtle1/pose and shows its // messages on the screen . #include <ros/ros.h> #include <std_msgs/String.h> #include <turtlesim/Pose.h> #include <iomanip> // for std::setprecision and std::fixed // A callback function . Executed each time a new pose // message arrives . void poseMessageReceived ( const turtlesim::Pose& msg ) { ROS_INFO_STREAM( std::setprecision(2) << std::fixed << " position =(" << msg.x << " , " << msg.y << " ) " << " *direction=" << msg.theta) ; } int main(int argc, char** argv) { // Initialize the ROS system and become a node . ros::init(argc, argv,"subscribe_to_pose"); ros::NodeHandle nh; // Create a subscri ber obj ect . ros::Subscriber sub = nh.subscribe("turtle1/pose", 1000, &poseMessageReceived); // Let ROS take over. ros::spin(); }

注意在CmakeList.txt添加turtlesim依賴后還會出現找不到turtlesim/Pose.h的情況,這時看看CmakeList中build中的include_directories塊有沒有被注釋掉,如果注釋掉就要打開
試驗結果:
123
左邊是訂閱者收到的消息,右邊是隨機發送的指令
---

24.通過 rosparam get /run_id 查看 run_id通過runid來查看日志消息

25.清除日志rosclean check ,rosclean purge

26.roslanch啟動多個節點的。其基本思想是在一個XML格式的文件內將需要同時啟動的一組節點羅列出來


一個launch文件例子

<launch>
<node name="turtlesim_node" pkg="turtlesim" type="turtlesim_node" ns="sim1" respawn="true" /> <node pkg="learn_ros" type="sub" name="sub_pose" output="screen" /> <node pkg="learn_ros" type="pub" required="true" launch-prefix="xterm -e" ns="sim1" name="pub"/> <node name="turtlesim_node" pkg="turtlesim" type="turtlesim_node" ns="sim2" respawn="true" /> <node pkg="turtlesim" type="turtle_teleop_key" required="true" launch-prefix="xterm -e" ns="sim2" name="pub2"/> </launch>

說明:respawn參數為真代表如果節點崩了過一會會自動重啟節點  
output="screen"將結果輸出到屏幕
type的參數是可執行的文件名
pkg的參數是功能包名
required為真代表如果這個節點崩了,那么整個launch結束
launch-prefix="xterm -e"表示新開個終端顯示數據
ns是命名空間,用於分開控制兩只烏龜
上面launch執行后的結果如下:
12312

launch中的重映射
重映射是基於替換的思想:每個重映射包含一個原始名稱和一個新名稱。每當節點使用重映射中的原始名稱時,ROS客戶端庫就會將它默默地替換成其對應的新名稱。

<remap from="turtle1 /cmd_vel" to="turtle1 /cmd_vel_reversed" />

這樣原來訂閱turtle1 /cmd_vel的節點就會訂閱turtle1 /cmd_vel_reversed的消息了

下面是一個包含其他launch文件的示例

<launch> <include file ="$(find learn_ros)/doublesim.launch" /> <arg name="use_sim3" default="0" /> <group ns="sim3" if="$(arg use_sim3)" > <node name="turtlesim_node" pkg="turtlesim " type="turtlesim_node" /> <node pkg="turtlesim " type="turtle_teleop_key" name="teleop_key" required="true " launch-prefix="xterm -e"/> </group> </launch>

其中use_sim3是參數,可以通過roslaunch learn_ros example.launch use_sim3:=1 來賦值
group可以將一些節點分組到同一個命名空間 sim3
用來查找learn_ros功能包中的doublesim文件,並添加進來

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM