文章只是個人學習過程中學習筆記,主要參考ROS教程123。
[ROS](01)創建ROS工作空間
[ROS](02)創建&編譯ROS軟件包Package
msg
(消息)文件就是文本文件,用於描述ROS消息的字段。它們用於為不同編程語言編寫的消息生成源代碼。msg
文件存放在軟件包的msg目錄下。
msg4文件就是簡單的文本文件,每行都有一個字段類型和字段名稱。它的結構為:fieldtype
+ fieldname
可以使用的類型為:
# 特殊的Header類型,它含有時間戳和ROS中廣泛使用的坐標幀信息
# 在msg文件的第一行經常可以看到Header header。
std_msgs/Header header
uint8 is_true
uint32 height
uint32 width
string child_frame_id
time stamp
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
uint8[] data
rosmsg
顯示有關ROS消息類型的信息。
rosmsg show
顯示消息的描述(詳細信息)rosmsg info
rosmsg show
的別名,功能一樣rosmsg list
列出所有消息rosmsg md5
顯示md5加密的消息rosmsg package
列出某個軟件包(package)的消息rosmsg packages
列出包含消息的軟件包(packages) 還是在原來創建的軟件包 beginner_tutorials
中定義一個新的消息。
# 切換到軟件包的目錄路徑
roscd beginner_tutorials
# 創建msg文件夾目錄
mkdir msg
# 創建名為Num.msg的文件,並添加一個消息字段
echo "int64 num" > msg/Num.msg
1. 為已經存在裡面的find_package調用添加message_generation
依賴項(),這樣就能生成消息了。(添加 message_generation
依賴項,必須有 std_msgs
。)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
2. 添加自定義的消息文件。將你msg
文件夾中自定義的*.msg
文件添加在這裡。
add_message_files(
FILES
Num.msg
)
3. 用於生成所有定義的message文件,需要添加本文件需要依賴的packages。其實就是告訴編譯器,編譯 *.msg
文件時,需要依賴的庫或package。
generate_messages(
DEPENDENCIES
std_msgs
)
4. 導出消息的運行時依賴關系。
catkin_package(
...
CATKIN_DEPENDS message_runtime ...
...)
添加編譯依賴與執行依賴。
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
Node
:在構建時,其實只需要message_generation
,而在運行時,我們只需要message_runtime
。
已經創建了一些新消息,所以需要重新make一下軟件包:
cd
cd catkin_ws
catkin_make
msg目錄中的任何.msg文件都將生成所有支持語言的代碼。
~/catkin_ws/devel/include/beginner_tutorials/
~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg
rosmsg list
列出ROS中的所有消息(msg)。
rosmsg packages [options]
列出包含消息的軟件包。
# 列出包含消息的軟件包,每行顯示一個軟件包名
rosmsg packages
# 在一行中列出包含消息的軟件包
rosmsg packages -s
rosmsg package [package-name]
列出某個軟件包(package)的消息。
rosmsg show [message type]
顯示消息的詳細信息。
rosmsg md5[message type]
顯示md5加密的消息。如果編譯的版本不匹配,這也會發出警告。
Node
:md5 命令僅供專家用戶使用。(??)
功能:基於話題通信,發布者以一定頻率發布自定義消息並打印輸出消息,訂閱者訂閱自定義消息並打印輸出消息。
實現:
1. 創建發布者(talker
)節點,該節點不斷廣播自定義消息。
2. 創建訂閱者(listener
)節點,該節點持續接收自定義消息。
3. 創建自定義消息(Num.msg
),(見4.1小節 創建msg
)
4. 發布訂閱話題chatter
在beginner_tutorials
軟件包的src目錄下創建發布者和訂閱者源文件:
roscd beginner_tutorials
cd src
touch talker.cpp listener.cpp
#include "ros/ros.h"
#include "beginner_tutorials/Num.h" // 在 /devel/include 目錄下
int main(int argc, char **argv)
{
/* 防止中文亂碼 */
setlocale(LC_ALL,"");
/* 初始化ROS節點 */
ros::init(argc, argv, "talker");
/* 為這個進程節點創建句柄 */
ros::NodeHandle nh;
/* 創建發布者對象 */
ros::Publisher pub = nh.advertise<beginner_tutorials::Num>("chatter", 1000);
/* 設定循環發布的頻率為1Hz */
ros::Rate loop_rate(1);
/* 要發布的消息 */
beginner_tutorials::Num msg;
msg.num = 0;
while(ros::ok())
{
ROS_INFO("當前num值為: %d",msg.num);
/* 發布消息 */
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
msg.num += 1;
}
return 0;
}
對上邊的內容進行一下總結:
- 初始化ROS系統
- 向主節點宣告我們將要在
chatter
話題上發布beginner_tutorials/Num
類型的消息- 以每秒1次的速率向
chatter
話題循環發布消息
#include "ros/ros.h"
#include "beginner_tutorials/Num.h" // 在 /devel/include 目錄下
/* 回調函數,當有新消息到達chatter話題時就會調用 */
void chatterCallback(const beginner_tutorials::Num::ConstPtr& msg)
{
ROS_INFO("已收到的Num的值: %d",msg->num);
}
int main(int argc, char **argv)
{
/* 防止中文亂碼 */
setlocale(LC_ALL,"");
/* 初始化ROS節點 */
ros::init(argc, argv, "listener");
/* 為這個進程節點創建句柄 */
ros::NodeHandle nh;
/* 創建訂閱者對象 * 通過節點管理器訂閱chatter話題。收到消息,調用回調函數chatterCallback。 * 第2個參數是隊列大小,>1000時,丟棄舊消息。 */
ros::Subscriber sub = nh.subscribe("chatter",1000, chatterCallback);
/* 啟動自循環 回調函數處理, 不占用太多CPU */
ros::spin();
return 0;
}
同樣地,我們來總結一下:
- 初始化ROS系統
- 訂閱
chatter
話題- 開始spin自循環,等待消息的到達
- 當消息到達後,調用
chatterCallback()
函數
只需將這幾行添加到CMakeLists.txt文件的底部:
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener ${PROJECT_NAME}_generate_messages_cpp)
編譯後,在終端中執行過程如下所示。
在beginner_tutorials
軟件包的scripts
目錄下創建發布者和訂閱者源文件:
roscd beginner_tutorials
cd scripts
touch talker.py listener.py
chmod +x talker.py listener.py
#!/usr/bin/env python
# encoding: utf-8
import rospy
from beginner_tutorials.msg import Num
def talker():
# 初始化ROS節點
rospy.init_node("talker",anonymous=True)
# 創建發布者對象
pub = rospy.Publisher('chatter', Num, queue_size=1000)
# 創建一個Rate對象rate,1Hz
rate = rospy.Rate(1)
# 要發布的消息
msg = Num()
msg.num = 0
# 循環
while not rospy.is_shutdown():
rospy.loginfo("當前num值為: %d",msg.num)
pub.publish(msg)
rate.sleep()
msg.num += 1
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
#!/usr/bin/env python
# encoding: utf-8
import rospy
from beginner_tutorials.msg import Num
def callback(msg):
rospy.loginfo("已收到的Num的值: %d",msg.num)
def listener():
# 初始化ROS節點
rospy.init_node("listener",anonymous=True)
# 創建發布者對象
pub = rospy.Subscriber('chatter', Num, callback, queue_size=1000)
rospy.spin()
if __name__ == '__main__':
listener()
# 安裝python可執行腳本
catkin_install_python(PROGRAMS
scripts/turtle_publisher.py
scripts/talker.py
scripts/listener.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
編譯後,在終端中執行過程如下所示。
ROS.otg. ROS教程[EB/OL]. 2020-12-22[2022-7-5].
http://wiki.ros.org/cn/ROS/Tutorials. ︎
.ROS.org. 編寫簡單的發布者和訂閱者(C++)[EB/OL]. 2020-12-25[2022-07-30]. https://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29. ︎
.ROS.org. 編寫簡單的發布者和訂閱者(Python)[EB/OL]. 2020-12-25[2022-07-30]. https://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28python%29. ︎
ROS.org. msg[EB/OL]. https://wiki.ros.org/msg[2022-07-30]. https://wiki.ros.org/msg.︎