ROS機器人操做系統在機器人應用領域很流行,依託代碼開源和模塊間協做等特性,給機器人開發者帶來了很大的方便。咱們的機器人「miiboo」中的大部分程序也採用ROS進行開發,因此本文就重點對ROS基礎知識進行詳細的講解,給不熟悉ROS的朋友起到一個拋磚引玉的做用。本章節主要內容:html
1.ROS是什麼node
2.ROS系統總體架構python
3.在ubuntu16.04中安裝ROS kineticios
4.如何編寫ROS的第一個程序hello_worldnginx
6.編寫簡單的service和clientdjango
7.理解tf的原理ubuntu
8.理解roslaunch在大型項目中的做用centos
9.熟練使用rvizbash
上一節介紹了兩個ros節點經過發佈與訂閱消息的通訊方式,如今就介紹ros節點間通訊的另一種方式服務。咱們將學到:如何自定義服務類型、server端節點編寫、client端節點編寫等。我就以實現兩個整數求和爲例,client端節點向server端節點發送a、b的請求,server端節點返回響應sum=a+b給client端節點,通訊網絡結構如圖20。
(圖20)服務請求與響應ROS通訊網絡結構圖
(1)功能包的建立
在catkin_ws/src/目錄下新建功能包service_example,並在建立時顯式的指明依賴roscpp和std_msgs,依賴std_msgs將做爲基本數據類型用於定義咱們的服務類型。打開命令行終端,輸入命令:
cd ~/catkin_ws/src/
#建立功能包service_example時,顯式的指明依賴roscpp和std_msgs,
#依賴會被默認寫到功能包的CMakeLists.txt和package.xml中
catkin_create_pkg service_example roscpp std_msgs
(2)在功能包中建立自定義服務類型
經過前面的學習,咱們知道服務通訊過程當中服務的數據類型須要用戶本身定義,與消息不一樣,節點並不提供標準服務類型。服務類型的定義文件都是以*.srv爲擴展名,而且被放在功能包的srv/文件夾下。
服務類型定義:
首先,在功能包service_example目錄下新建srv目錄,而後在service_example/srv/目錄中建立AddTwoInts.srv文件,文件內容以下:
int64 a int64 b --- int64 sum
服務類型編譯配置:
定義好咱們的服務類型後,要想讓該服務類型能在c++、python等代碼中被使用,必需要作相應的編譯與運行配置。編譯依賴message_generation,運行依賴message_runtime。
打開功能包中的CMakeLists.txt文件,找到下面這段代碼:
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
將message_generation添加進去,添加後的代碼以下:
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
message_generation
)
繼續,找到這段代碼:
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
去掉這段代碼的#註釋,將本身的服務類型定義文件AddTwoInts.srv填入,修改好後的代碼以下:
add_service_files(
FILES
AddTwoInts.srv
)
繼續,找到這段代碼:
# generate_messages(
# DEPENDENCIES
# std_msgs
# )
去掉這段代碼的#註釋,generate_messages的做用是自動建立咱們自定義的消息類型*.msg與服務類型*.srv相對應的*.h,因爲咱們定義的服務類型使用了std_msgs中的int64基本類型,因此必須向generate_messages指明該依賴,修改好後的代碼以下:
generate_messages(
DEPENDENCIES
std_msgs
)
而後打開功能包中的package.xml文件,填入下面三句依賴:
<build_depend>message_generation</build_depend> <build_export_depend>message_generation</build_export_depend> <exec_depend>message_runtime</exec_depend>
檢查ROS是否識別新建的服務類型:
咱們經過<功能包名/服務類型名>找到該服務,打開命令行終端,輸入命令:
source ~/catkin_ws/devel/setup.bash
rossrv show service_example/AddTwoInts
看到下面的輸出,如圖21,就說明新建服務類型能被ROS識別,新建服務類型成功了。
(圖21)新建服務類型能被ROS識別
(3)功能包的源代碼編寫
功能包中須要編寫兩個獨立可執行的節點,一個節點用來做爲client端發起請求,另外一個節點用來做爲server端響應請求,因此須要在新建的功能包service_example/src/目錄下新建兩個文件server_node.cpp和client_node.cpp,並將下面的代碼分別填入。
首先,介紹server節點server_node.cpp,代碼內容以下:
1 #include "ros/ros.h" 2 #include "service_example/AddTwoInts.h" 3 4 bool add_execute(service_example::AddTwoInts::Request &req, 5 service_example::AddTwoInts::Response &res) 6 { 7 res.sum = req.a + req.b; 8 ROS_INFO("recieve request: a=%ld,b=%ld",(long int)req.a,(long int)req.b); 9 ROS_INFO("send response: sum=%ld",(long int)res.sum); 10 return true; 11 } 12 13 int main(int argc,char **argv) 14 { 15 ros::init(argc,argv,"server_node"); 16 ros::NodeHandle nh; 17 18 ros::ServiceServer service = nh.advertiseService("add_two_ints",add_execute); 19 ROS_INFO("service is ready!!!"); 20 ros::spin(); 21 22 return 0; 23 }
對server節點代碼進行解析。
#include 「ros/ros.h」
#include 「service_example/AddTwoInts.h」
包含頭文件ros/ros.h,這是ROS提供的C++客戶端庫,是必須包含的頭文件,就很少說了。service_example/AddTwoInts.h是由編譯系統自動根據咱們的功能包和在功能包下建立的*.srv文件生成的對應的頭文件,包含這個頭文件,程序中就可使用咱們自定義服務的數據類型了。
bool add_execute(...)
這個函數實現兩個int64整數求和的服務,兩個int64值從request獲取,返回求和結果裝入response裏,request與response的具體數據類型都在前面建立的*.srv文件中被定義,這個函數返回值爲bool型。
ros::init(argc,argv,」server_node」);
ros::NodeHandle nh;
初始化ros節點並指明節點的名稱,聲明一個ros節點的句柄,,就很少說了。
ros::ServiceServer service = nh.advertiseService(「add_two_ints」,add_execute);
這一句是建立服務,並將服務加入到ROS網絡中,而且這個服務在ROS網絡中以名稱add_two_ints惟一標識,以便於其餘節點經過服務名稱進行請求。
ros::spin();
這一句話讓程序進入自循環的掛起狀態,從而讓程序以最好的效率接收客戶端的請求並調用回調函數,就很少說了。
接着,介紹client節點client_node.cpp,代碼內容以下:
1 #include "ros/ros.h" 2 #include "service_example/AddTwoInts.h" 3 4 #include <iostream> 5 6 int main(int argc,char **argv) 7 { 8 ros::init(argc,argv,"client_node"); 9 ros::NodeHandle nh; 10 11 ros::ServiceClient client = 12 nh.serviceClient<service_example::AddTwoInts>("add_two_ints"); 13 service_example::AddTwoInts srv; 14 15 while(ros::ok()) 16 { 17 long int a_in,b_in; 18 std::cout<<"please input a and b:"; 19 std::cin>>a_in>>b_in; 20 21 srv.request.a = a_in; 22 srv.request.b = b_in; 23 if(client.call(srv)) 24 { 25 ROS_INFO("sum=%ld",(long int)srv.response.sum); 26 } 27 else 28 { 29 ROS_INFO("failed to call service add_two_ints"); 30 } 31 } 32 return 0; 33 }
對client節點代碼進行解析。
以前解釋過的相似的代碼就不作過多的解釋了,這裏重點解釋一下前面沒遇到過的代碼。
ros::ServiceClient client =
nh.serviceClient<service_example::AddTwoInts>("add_two_ints");
這一句建立client對象,用來向ROS網絡中名稱叫add_two_ints的service發起請求。
service_example::AddTwoInts srv;
定義了一個service_example::AddTwoInts服務類型的對象,該對象中的成員正是咱們在*.srv文件中定義的a、b、sum,咱們將待請求的數據填充到數據成員a、b,請求成功後返回結果會被自動填充到數據成員sum中。
if(client.call(srv)){...}
這一句即是經過client的方法call來向service發起請求,請求傳入的參數srv在上面已經介紹過了。
(4)功能包的編譯配置及編譯
建立功能包service_example時,顯式的指明依賴roscpp和std_msgs,依賴會被默認寫到功能包的CMakeLists.txt和package.xml中,而且在功能包中建立*.srv服務類型時已經對服務的編譯與運行作了相關配置,因此只須要在CMakeLists.txt文件的末尾行加入如下幾句用於聲明可執行文件就能夠了:
add_executable(server_node src/server_node.cpp) target_link_libraries(server_node ${catkin_LIBRARIES}) add_dependencies(server_node service_example_gencpp) add_executable(client_node src/client_node.cpp) target_link_libraries(client_node ${catkin_LIBRARIES}) add_dependencies(client_node service_example_gencpp)
這裏面的add_executable用於聲明可執行文件。target_link_libraries用於聲明可執行文件建立時須要連接的庫。add_dependencies用於聲明可執行文件的依賴項,因爲咱們自定義了*.srv,service_example_gencpp的做用是讓編譯系統自動根據咱們的功能包和在功能包下建立的*.srv文件生成的對應的頭文件和庫文件,service_example_gencpp這個名稱是由功能包名稱service_example加上_gencpp後綴而來的,後綴很好理解:生成c++文件就是_gencpp,
生成python文件就是_genpy。
接下來,就能夠用下面的命令對功能包進行編譯了:
cd ~/catkin_ws/ catkin_make -DCATKIN_WHITELIST_PACKAGES="service_example"
(5)功能包的啓動運行
首先,須要用roscore命令來啓動ROS節點管理器,ROS節點管理器是全部節點運行的基礎。
打開命令行終端,輸入命令:
roscore
而後,用source devel/setup.bash激活catkin_ws工做空間,用rosrun <package_name> <node_name>啓動功能包中的server節點。
再打開一個命令行終端,分別輸入命令:
cd ~/catkin_ws/ source devel/setup.bash rosrun service_example server_node
看到有輸出「servive is ready!!!」,就說明server節點已經正常啓動並開始等待client節點向本身發起請求了,如圖22。
(圖22)server節點已經正常啓動
最後,用source devel/setup.bash激活catkin_ws工做空間,用rosrun <package_name> <node_name>啓動功能包中的client節點。
再打開一個命令行終端,分別輸入命令:
cd ~/catkin_ws/ source devel/setup.bash rosrun service_example client_node
看到有輸出提示信息「please input a and b:」後,鍵盤鍵入兩個整數,以空格分割,輸入完畢後回車。若是看到輸出信息「sum=xxx」,就說明client節點向server端發起的請求獲得了響應,打印出來的sum就是響應結果,這樣就完成了一次服務請求的通訊過程,如圖23。
(圖23)client節點已經正常啓動
到這裏,咱們編寫的server和client就大功告成了,爲了加深對整個程序工做流程的理解,我再把server與client的ROS通訊網絡結構圖拿出來,加深一下理解。
(圖24)服務請求與響應ROS通訊網絡結構圖
------SLAM+語音機器人DIY系列【目錄】快速導覽------
第1章:Linux基礎
第2章:ROS入門
第3章:感知與大腦
第4章:差分底盤設計
第5章:樹莓派3開發環境搭建
第6章:SLAM建圖與自主避障導航
2.google-cartographer機器人SLAM建圖
第7章:語音交互與天然語言處理
第8章:高階拓展
2.centos7下部署Django(nginx+uwsgi+django+python3)
----------------文章將持續更新,敬請關注-----------------
若是你們對博文的相關類容感興趣,或有什麼技術疑問,歡迎加入下面的《SLAM+語音機器人DIY》QQ技術交流羣,一塊兒討論學習^_^
關於咱們:
視頻教程: