先学python还是ros_ROS入门学习
ROS學習筆記
ROS主要包含包括功能包、節點、話題、消息類型和服務;
ROS功能包/軟件包(Packages)
ROS軟件包是一組用于實現特定功能的相關文件的集合,包括可執行文件和其他支持文件。
所有的 ROS 軟件都是一個軟件包或其他軟件包的一部分。
每個程序包由一個清單文件(文件名為 package.xml)定義。
該文件定義關于包的一些細節,包括其名稱、版本、維護者和依賴關系。
包含 package.xml 文件的目錄被稱為軟件包目錄。
使用catkin編譯構建系統的功能包, 編譯產生的可執行文件存放在一個單獨的標準化目錄層次結構中。
功能包集(stack): 功能包集是緊密相關的功能包的集合,從groovy開始慢慢地被淘汰, 取而代之的是元功能包(metapackages)。
節點管理器(The Master)
接單(node)是幾乎相對獨立的小程序,這些節點必須能夠通信, 通信的關鍵部分是ROS節點管理器。
啟動節點管理器的命令 -- roscore。
大多數 ROS 節點在啟動時連接到節點管理器上,如果運行中連接中斷,則不會嘗試重新連接。
因此,如果 roscore被終止,當前運行的其他節點將無法建立新的連接,即使稍后重啟 roscore 也無濟于事。
roslaunch 的工具,其目的是一次性啟動多個節點。
節點(Nodes)
一旦啟動roscore后,便可以運行ROS程序了, ROS程序的運行實例被稱為節點(node)。
“運行實例”(running instance)很重要。
如果我們同時執行相同程序的多個副本——注意確保每個副本使用不同的節點名——則每個副本都被當做一個單獨的節點。
啟動節點:
利用命令rosrun: rosrun package-name executable-name;
rosrun 沒有什么“神奇”的:它只不過是一個 shell 腳本,能夠理解 ROS 的文件組織結構,知道到哪里能找到與給定包名稱對應的可執行文件。
通過節點管理器注冊成為 ROS 節點發生在程序的內部,而不是通過 rosrun 命令。
查看節點列表:
利用命令: rosnode list;
rosout 節點是一個特殊的節點,通過 roscore 自動啟動,其作用類似于標準輸出(即std::cout)。
節點名不一定與對應可執行文件名稱相同。
獲得特定節點的信息: rosmode info node-name;
終止節點: rosnode kill node-name;
終止和重啟節點通常不會對其他節點有較大影響。
即使節點間正在相互交換消息(message),這些連接也會在節點終止時斷開,在節點重啟時重新連接。
將節點從列表中刪除: rosnode cleanup。
話題和消息
ROS節點之間進行通信所利用的最重要的機制就是消息傳遞。
在ROS中,消息有組織地存放在話題里。
消息傳遞的理念:
當一個節點想要分享信息時,它就會發布(publish)消息到對應的一個或者多個話題;
當一個節點想要接收信息時, 它就會訂閱(subscribe)它所需要的一個或多個話題;
ROS節點管理器負責確保發布節點和訂閱節點能找到對方;
消息是直接地從發布節點傳遞到訂閱節點,中間并不經過節點管理器轉交;
查看節點構成的計算圖:
查看節點之間的發布-訂閱關系的最簡單方式就是在終端輸入rqt_graph命令。
r代表ROS, qt指的是Qt圖形界面(GUI)工具包;
在默認情況下,rqt_graph 隱藏了其認為只在調試過程中使用的節點。
的名稱/rosout 既指節點又指話題。但 ROS 并不會因這種重復的名字而混淆,因為 ROS 會根據上下文來推測我們討論的是/rosout 節點還是/rosout 話題。
ROS 節點通常設計成了只管發布它們有用的信息,而不需要擔心是否有其他節點來訂閱這些消息。這樣有助于減少各個節點之間的耦合度。
,/teleop_turtle 節點會以消息的形式將這些運動控制命令發布到 話 題 /turtle1/cmd_vel; 與此同時,因為turtlesim_node 訂閱了該話題,因此它會接收到這個些消息,控制海龜按照該預定的速度移動。
話題列表
通過rostopic list獲取當前活躍的話題;
打印消息內容rostopic echo topic-name;
測試發布頻率rostopic hz topic-name(每秒發布消息的數量) 和 rostopic bw topic-name(每秒發布消息所占的帶寬);
Type在文本輸出中表示數據類型;
查看消息類型: rosmsg show message-type-name。
一個復合域是由簡單的一個或者多個子域組合而成,其中的每一個子域可能是另一個復合域或者獨立的域,而且它們一般也都由基本數據類型組成。
用命令行發布消息
利用rostopic命令工具: rostopic pub -r rate-in-hz topic-name message-type message-content(按照指定的頻率給指定的話題發布指定的消息);
該命令最后的參數 message-content 應該按順序提供消息類型中所有域的參數值。
rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 3]'命令中利用了-r來指定話題以頻率模式發布消息;
鎖存模式只是發布一條消息,但鎖存模式是默認的模式。
-f是從文件中讀取,輸入應該 符合rostopic echo的輸出格式。
編寫一種腳本將 rostopic echo 和 rostopic pub 結合起來作為“記錄”和“回放”消息的方式;rosbag工具。
理解消息類型的命名
每條消息類型都屬于一個特定的包,消息類型名總會包含一個斜桿,斜桿錢面的名字是包含它的包: package-name/type-name;
turtlesim/Color中的turtlesim是功能包名, Color是類型名稱;
ROS 節點管理器不允許多個節點擁有相同的名稱。
話題通信的多對多機制
基于話題和消息的通信機制是多對多的,即多個發布者和多個訂閱者可以共享同一個話題。
節點之間的松耦合關系:
每個節點都不需要顯式知道其他節點的存在與否;它們的唯一交互方式是間接地發生在基于話題和消息的通信層。
節點之間的獨立性,以及其支持的任務可分解特性(即復雜任務分解成可重用的小模塊),是 ROS 最關鍵的設計特性之一。
“生產”消息的程序(例如 turtle_teleop_key)只管發布該消息,而不用關心該消息是如何被“消費”的。
“消費”消息的程序(例如 turtlesim_node)只管訂閱該話題或者它所需要消息的所有話題,而不用關心這些消息數據是如何“生產”的。
ROS為更加直接的一對一通信提供了一種稱為服務(services)的機制。
ROS 利用roswtf進行問題的查找。
roswtf 將會檢測在安裝過程中 rosdep 初始化是否完成,任何節點是否出現了意外的掛起或者終止,以及活躍的節點是否正確地和其他節點相連接等。
roswtf 檢測的完整列表只能在 Python 源碼中才能找到。
編寫ROS程序
學習編寫能夠發布和訂閱消息的 ROS 程序。
創建工作區和功能包
創建工作區,我們創建的包,應該全部放到一個叫做工作區的目錄中。
工作區就是包含自己所有包的一個工作區目錄。
ROS的catkin編譯系統試圖一次性編譯同一個工作區中的所有功能包,如果設計到幾個相互獨立的項目,則應該維護數個獨立的工作區。
每個工作區必須創建一個src的子目錄,這個子目錄講用于存放功能包的源碼。
catkin_create_pkg package-name是創建一個功能包。
一個配置文件 -- package.xml這是一個清單文件。
CMakeLists.txt是一個Cmake的腳本文件, 其實catkin在內部使用了Cmake。
ROS 包的命名遵循一個命名規范,只允許使用小寫字母、數字和下劃線,而且首字符必須是一個小寫字母。一些 ROS工具,包括 catkin,不支持那些不遵循此命名規范的包。
本著保持文檔與實際功能同步的精神,至少在package.xml中填寫description 和 maintainer 兩部分可能是比較合理的
包含消息的聲明: 每一個話題都與一個消息類型相關聯,每一個消息類型都有一個相對應C++頭文件。
#include 頭文件, 像#include 表示名為 geometry_msgs 的包所擁有的類型為 Twist 的消息。
編寫回調函數
發布和訂閱消息的一個重要的區別是訂閱者節點無法知道消息什么時候才能到達, 為了對應這一事實, 我們必須把響應收到消息事件的代碼放到回調函數里, ROS每接收到一個新的消息將調用一次這個函數。
日志消息
學習如何生成和查看日志消息。
ROS中分為5個不同的嚴重級別,按嚴重性程度遞增為: DEBUG、INFO、WARN、ERROR、FATAL。
DEBUG: reading header from buffer.
INFO: Waiting for all connections to establish.
WARN: Less than 5GB of space free on disk.
ERROR: Publisher header did not have required element: type.
FATAL: You must call ros::init() before creating the first NodeHandle.
為日志系統本身就是面向行的, 沒有必要使用std::endl或者其他的行終止符。
檢查和清除日志文件:
這些日志文件將隨著時間積累;
rosrun和roslaunch運行時會檢查和檢測已經存在的日志的大小,并會在日志文件大小超過1GB時提醒,但是不會采取任何措施來減小日志文件的大小。
查看當前用戶使用的日志文件的當前大小: rosclean check。
刪除所有已經存在的日志: rosclean purge。
嘗試生成DEBUG級別的消息將會被忽略。
設置日志級別類似于 rqt_consolt 中的日志級別過濾選項。
ROS_INFO_STREAM 等構建方式是宏而不是函數調用。這些宏對應的展開代碼會檢查消息是否被啟用,并且只會評估那些被啟用消息的表達式。
通過命令行設置日志級別:
rosservice call /node-name/set_logger_level ros.package-name level;
這條命令調用 set_logger_level 服務,該服務由各個節點自動提供。
roservice 的參數 ros.package-name 是必需的,用來指明我們期望配置的日志記錄器(logger)的名稱。
rqt_logger_level通過圖形界面設置日志級別;
通過C++代碼設置日志級別,最直接的方式是調用ROS來實現日志功能的log4cxx提供的代碼接口
#include
. . .
log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->setLevel(
ros::console::g_level_lookup[ros::console::levels::Debug]
);
ros::console::notifyLoggerLevelsChanged();
調用 ros::console::notifyLoggerLevelsChanged()是有必要的,因為每個日志的啟用或者禁用是緩存了的。
計算圖源命名
ROS的計算圖資源(節點、話題、參數、和服務等)的命名和解析。
全局名稱
節點、話題、服務和參數統稱為計算圖源,而每個計算圖源由一個叫計算圖源名稱(graph resource name)的短字符串標識。
前斜桿"/"表明這個名稱為全局名稱, 由斜桿分開的一系列命名空間(namespace), 每個斜桿代表一級命名空間。
描述資源本身的基本名稱(base name)。
相對名稱
一個主要替代方案是讓 ROS為計算圖源提供一個默認的命名空間,具有此特征的名稱叫做相對計算圖源名稱(ralative graph resource name),或簡稱為相對名稱(relative name)。
設置默認命名空間:
默認的命名空間是單獨地為每個節點設置的,而不是在系統范圍進行。
大部分 ROS 程序,包括調用 ros::init 的所有 C++程序,接受叫做__ns 的命令行參數,此參數將為程序指定一個默認命名空間。_ _ns:=default-namespace;
還可以利用環境變量為在 shell 內執行的 ROS 程序設置默認命名空間。Export ROS_NAMESPACE=default-namespace
私有名稱
私有名稱,以一個波浪字符(~)開始,是第三類也是最后一類計算圖源名稱。
私有名稱并不能完全確定它們自身所在的命名空間,而是需要 ROS 客戶端庫將這個名稱解析為一個全局名稱。
與相對名稱的主要差別在于,私有名稱不是用當前默認命名空間,而是用的它們節點名稱作為命名空間。
匿名名稱(Anonymous names)
匿名名稱的目的是使節點的命名更容易遵守唯一性的規則。其思路是,當節點調用 ros::init 方法時可以請求一個自動分配的唯一名稱。
為了請求一個匿名名稱,節點需要將ros::init_options::Anonymous-Name 作為第四個參數傳遞給ros::init 方法:ros::init(argc, argv, base_name, ros::init_options::AnonymousName);
啟動文件
利用啟動文件一次性配置和運行多個節點,ROS提供了一個同時啟動節點管理器(master)和多個節點的途徑,即啟動文件(launch file)。
啟動文件需要roslaunch工具來進行啟動。
使用啟動文件
roslaunch的基本思想是在一個XML格式的文件內將需要同時啟動的一組節點羅列出來。
在命名空間內啟動節點
對一個節點設置默認命名空間,這個過程通常叫做壓人(pushing down)命名空間--的通常方法是使用一個啟動文件,并對其節點元素配置命名空間(ns,ns = namesapce)屬性。
事實上 roslaunch 要求啟動文件中的節點名稱是基名稱,即不涉及任何命名空間的相對名稱。如果節點元素的名稱屬性中出現了全局名稱,roslaunch 將會報錯。
名稱重映射(Remapping names)
除了相對名稱和私有名稱, ROS節點還支持重映射(remapping), 它可以從更精細的層面控制對所用節點名稱的修改。
重映射是基于替換的思想: 每個重映射包含一個原始名稱和一個新名稱。
每當節點使用重映射中的原始名稱時, ROS客戶端庫就會將它默默地替換成其對應的名稱。
啟動參數(launch arguments)
為了使啟動文件便于配置, roslaunch還支持啟動參數,其功能有點像可執行程序中的局部變量;
這樣的有點是通過設置參數來描述節點在不同ROS會話中運行時可能需要改變.
向包括的啟動文件中發送參數值,參數僅定義在對其進行聲明的啟動文件中,而不能被包含的啟動文件繼承;
將arg元素作為一個包含元素的子元素。
…
創建組(Creating groups)
組元素(group)是啟動文件的最后一個特征,它提供了一種在大型啟動文件內管理節點的便捷方式。
組可以把若干個節點放入同一個命名空間內:
…
組內的每個節點都從給定的默認命名空間啟動。
如果一個組元素內的某個節點有它自己的命名空間屬性,并且其名稱是(原則上也應該是)相對名稱,那么該節點將會在一個默認命名空間內啟動,這個默認的命名空間是將此節點命名空間嵌入到組元素命名空間的結果。這個規則和前面講到的名稱解析是相符的,并且這個規則也適用于組元素的嵌套。
組可以有條件地使能或禁止一個節點:
只有 0 和 1 才是 if 和 unless 屬性的合法取值。特別需要提醒的是,讀者熟悉的布爾型運算符 AND 和 OR 在這里不能直接使用。
使用組可以減少代碼重復——命名空間和條件設置僅出現一次——并且使啟動文件的結構更加清晰。
參數
ROS還提供另一種參 數(parameters)機制用于獲取節點的信息。
使用集中參數服務器(parameter server)維護一個變量集的值, 包括整數,浮點數,字符串以及其他數據類型,每個變量用一個較短的字符串標識。
通過命令行獲取參數
查看參數列表: rosparam list。
參數服務器是節點管理器的一部分,因此,它總是通過 roscore 或者 roslaunch 自動啟動。
需要銘記的是,所有的參數都屬于參數服務器而不是任何特定的節點。
查詢參數:
rosparam get parameter_name, 查詢某個參數的值。
rosparam get namespace, 通過查詢全局命名空間,我們可以一次性看到所有參數的值。
設置參數:
rosparam set parameter_name parameter_value, 修改一個已有參數或者創建一個新的參。
以YAML字典的形式表示參數和對應值的映射關系。
冒號后的空格是非常重要的,以確保 rosparam 將其作為一個/duck_colors 命名空間內的參數集,而不是全局命名空間中的單個字符串參數 duck_colors。
創建和加載參數文件:
rosparam dump filename namespace, 了以 YAML 文件的形式存儲命名空間中的所有參數。
rosparam load filename namespace, 從一個文件中讀取參數,并將它們添加到參數服務器。
一個好的策略是演示真正的ROS節點如何工作得更好案例,是turtle首先測試這些參數是否存在,當且僅當這些參數不存在時, 才至指定默認的藍色。
rosparam get 命令是獲取背景參數的值。
如果節點關心它的一些或者所有參數是否改變,必須明確向參數服務器請求這些參數的值。
使用C++獲取參數
ROS參數的C++接口是相當簡單的: void ros::param::set(parameter_name, input_value);和bool ros::param::get(parameter_name, output_value);
在啟動文件中設置參數
設置參數:
可以使用param元素請求roslaunch設置參數值, 。
設置私有參數:
作為節點元素的子集時,param元素中給出的參數名總是被當做私有名稱解析,無論它們是否以~或者/開始。
. . .
// 啟動文件中設置
pkg="turtlesim "
type="turtlesim_node"
name="turtlesim "
/>
pkg="agitr "
type="pubvel_with_max"
name="publish_velocity "
>
pkg="agitr "
type="set_bg_color"
name="set_bg_color"
/>
在文件中讀取參數: 啟動文件也支持與rosparam load等價的命令, 可以一次性從文件中加載多個參數: 。
這里的參數文件通常是通過rosparam dump命令創建的。
command="load"
file="$(find package-name)/param-file"
/>
參數的思想雖然簡單, 但是可以大大提高ROS節點的靈活性和可配置性。
服務
消息傳遞是ROS中節點通信的主要方法, 但確實受到了一定的限制,服務調用(service calls)是另一種通信的方法。
服務調用和消息的區別在兩個方面:
服務調用是雙向的, 一個節點給另一個節點發送信息并等待響應,因此信息流是雙向的。消息發布后并沒有響應的概念,甚至不能保證系統內有節點訂閱了這些消息。
服務調用實現的是一對一通信, 每一個服務有一個節點發起,這對這個服務的響應返回同一個節點。另一方面,每一個消息都和一個話題相關,這個話題可能有很多的發布者和訂閱者。
消息和服務十分相似。
服務的專用術語
一個客戶端(client)節點發送一些稱為請求(request)的數據到一個服務器(server)節點,并等待回應。
服務器節點接收到請求后, 采取一些行動(計算、配置軟件和硬件、改變自身行為等),然后發送一些稱為響應(response)的數據給客戶端節點。
請求和響應數據攜帶的特定內容由服務數據類型(service data type)來決定,它與決定消息內容的消息類型是類似的,服務數據類型也是由一系列域構成;
唯一區別是,服務數據類型分為兩部分,分別表示請求(客戶端節點提供服務器節點)和響應(服務其節點反饋給客戶端節點)。
從命令行查看和調用服務
服務通常由節點內部的代碼調用;
列出所有服務: ros service list; 服務名是計算圖源名稱,同其他資源名稱一樣,可以劃分為全局的、相對的或者私有的名稱。rosservice list命令的輸出是所有服務的全局名稱。
服務通常將節點名用作命名空間來防止命名沖突,并且允許節點通過私有名稱來提供服務。
查看某個節點的服務類型,查看一個特定節點提供的服務,使用rosnode info命令。
查找提供服務的節點: rosservice node service-name;
查看服務數據類型: 當服務的數據類型已知時, 我們可以使用rossrv指令來獲得此服務數據類型的詳情 -- rossrv show service-data-type-name。
服務數據類型中的請求或響應字段可以為空,甚至兩個字段可以同時為空。
從命令行調用服務: rosservice call service-name request-content
客戶端程序
聲明請求和響應的類型,必須包含相關的頭文件: #include 。
創建一個客戶端對象, ros::ServiceClient client = node_handle.serviceClient(service_name);。
service_name是一個字符串,應當是一個相對名稱。
與創建類似的 ros::Publisher 對象相比,創建 ros::ServiceClient 對象不需要隊列大小。
調用服務: 一旦擁有了一個ServiceClient, 一個完整的Request以及Response, 我們就可以調用服務了: bool success = service_client.call(request, reponse);
這個方法實際上完成了定位服務器節點、傳輸請求數據、等待響應和存儲響應數據等一系列工作。
聲明依賴: 需要編輯CMakeLists.txt和清單文件packag.xml。
必須保證CMakeLists.txt中的find_package行涉及了turtlesim功能包: find_package(catkin REQUIRED COMPONENTS roscpp turtlesim)。
在package.xml中, 我們應當確保build_depend和run_depend元素中存在相同名稱的包,turtlesim, turtlesim 或 turtlesim。
服務器程序
必須創建一個ros::ServiceServer來代替ros::Subscriber, 唯一的區別在于服務端可以通過一個響應對象和一個表明成功與否的不二比昂兩給客戶端回傳數據。
節點每次接收到一個服務請求,ROS就執行一次回調函數,參數Request中包含了來自客戶端的數據,回調函數的工作是給Response對象的數據成員賦值。
創建服務器對象: ros::ServiceServer server = node_handle.advertiseService(service_name,pointer_to_callback_function);
私有名稱以~開始。
可以使用兩個分開的線程:一個發布消息,一個處理服務回調。 盡管 ROS沒有明確指出程序要使用多個線程,但如果可以的話,這是非常便于合作的。
可以用ros::spin來代替sleep/ros::spinOnce循環,并且利用計數器回調函數(timer callback)來發布消息。
消息錄制與回放
ROS 系統的一個重要特征便是系統中信息的消費者不應該關心信息的生產者。
這種體系架構最明顯的體現是ROS主要使用的消息發布-訂閱模型。
不論什么時刻,只要有消息被發布,其訂閱節點就應該正常工作,而不管是哪個或是那些節點正在發布這些消息。
rosbag工具,能夠發布在一個或這多個話題上的消息錄制到一個包文件中,然后可以回放這些消息,重現像是的運行過程。
錄制與回放包文件
術語包文件(bag files)是指用于存儲帶時間戳的ROS消息的特殊格式文件,rosbag命令行工具可以用來錄制和回放包文件。
錄制包文件: rosbag record -O filename.bag topic-names。
如果不指定文件名,rosbag 將基于當前的日期和時間自動生成一個。
用rosbag record -a 記錄當前發布的所有話題的消息。
用 rosbag record -j 啟用包文件的壓縮。
回放包文件: rosbag info filename.bag。
持續時間、消息計數以及話題列表三個字段似乎很有趣。
錄制正方形軌跡的包文件,rosbag record -O square.bag /turtle1/cmd_vel /turtle1/pose。
啟動文件里面的包文件
通過這兩個可執行文件可以很容易地將包文件作為啟動文件的一部分,方法是包含適當的節點元素。
// 錄制節點
pkg="rosbag"
name="record"
type="record"
args="-O filename.bag topic-names"
/>
// 回放節點
pkg="rosbag"
name="play"
type="play"
args="filename.bag"
/>
在網絡環境中運行ROS, ROS的一大優勢是支持分布式機器人控制模式,即諸多程序運行在不同的計算機上,通過互相交互來完成指定任務。
需要在網絡層和ROS層進行配置,網絡層確保計算機之間能夠互相通信, 而ROS層的配置是確保所有節點都能與節點管理器通信。
編寫更規范的程序, 程序一定要注重可擴展性和可維護性;
用ros::Timer的回調函數來替代ros::Rate對象。
使用rviz使數據可視化,機器人傳感器獲得的數據不僅復雜而且通常帶有噪聲, ROS提供了一個叫做rviz的非常強大的圖形界面工具,它可以通過訂閱用戶選擇的話題來顯示機器人內部的各種信息,便于機器人的開發和調試。
創建消息和服務類型。
使用tf工具來管理多個坐標系,用不同的坐標系來描述機器人不同部件的位置,包括機器人要避開或交互的目標。
需要知道將某個坐標從一個坐標系到另一個坐標系的變換矩陣(Transforation),ROS提供了一個標準功能包,來幫助節點來完成坐標轉換。
tf具有很強的魯棒性,既能夠處理來自不同節點的數據,也能應對坐標系的實時變換。
使用Gazebo仿真, ROS系統最大的優勢之一就是能夠實現軟件的模塊化設計,基于這個框架可以輕易地替換系統中的各種軟件模塊,從而節約系統的開發時間,也使得測試變得簡單方便。
Gazebo是一個高保真的機器人仿真器。
在Gazebo中,我們可以建立機器人和相應場景的仿真模型,然后為仿真機器人定義與實體機器人相同的通信接口。
總結
以上是生活随笔為你收集整理的先学python还是ros_ROS入门学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python入门之函数调用-python
- 下一篇: 【LeetCode笔记】剑指 Offer