(ROS-4)通信demo

文章目录

1 基于 topic 通信

1.1 自定义message(数据类型)

Message的定义类似C语言中的结构体。Message不仅仅是我们平时理解的一条一条的消息,而且更是ROS中topic的格式规范。或者可以理解msg是一个“类”,那么我们每次发布的内容可以理解为“对象”,这么对比来理解可能更加容易。
我们实际通常不会把Message概念分的那么清,通常说Message既指的是类,也是指它的对象。而msg文件则相当于类的定义了。

rosmsg命令 作用
rosmsg list 列出系统上所有的msg
rosmsg show msg_name 显示某个msg的内容

1.1.1 新建功能包

首先进入src目录下创建功能包,

cd catkin_ws/src/
catkin_create_pkg pkg_a rospy roscpp std_msgs geometry_msgs message_generation message_runtime

依赖:rospy roscpp,是函数接口; std_msgs geometry_msgs,是消息嵌套用到的功能包;

message_generation message_runtime,是编译和运行所需的依赖,在这里添加,则可以省去后面修改package.xml的步骤

1.1.2 新建msg文件

Message的定义位于功能包下的msg目录中(service则位于srv目录中)。

jw@G5-5500:~/catkin_ws$ roscd pkg_a/
jw@G5-5500:~/catkin_ws/src/pkg_a$ ls
CMakeLists.txt  include  package.xml  src
jw@G5-5500:~/catkin_ws/src/pkg_a$ mkdir msg && cd msg
jw@G5-5500:~/catkin_ws/src/pkg_a/msg$ gedit my_message.msg

msg的定义,类似结构体。

自定义的my_message.msg文件的内容如下:

  • 顶行不能为空
  • 中间用空格隔开而不是tab
geometry_msgs/Vector3 v2
geometry_msgs/Vector3 v1
string name
int32 num

geometry_msgs是ros的封装好的类型库,如对几何数据类型中的加速度,geometry_msgs/Accel,其msg内容为

jw@G5-5500:/opt/ros/melodic/share/geometry_msgs/msg$ cat Accel.msg 
# This expresses acceleration in free space broken into its linear and angular parts.
Vector3  linear
Vector3  angular

注意,这里的Vector3之所以没有带geometry_msgs/,是因为Vector3本身就位于包geometry_msgs的msg目录下。

再看Vector3的消息定义

jw@G5-5500:/opt/ros/melodic/share/geometry_msgs/msg$ cat Vector3.msg 
# This represents a vector in free space. 
# It is only meant to represent a direction. Therefore, it does not
# make sense to apply a translation to it (e.g., when applying a 
# generic rigid transformation to a Vector3, tf2 will only apply the
# rotation). If you want your data to be translatable too, use the
# geometry_msgs/Point message instead.

float64 x
float64 y

1.1.3 修改package.xml与CMakeLists.txt

我们要确保msg文件被转换成为C++,Python和其他语言的源代码:
查看package.xml, 确保它包含一下两条语句:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
如果没有,添加进去。 注意,在构建的时候,我们只需要"message_generation"。然而,在运行的时候,我们只需要"message_runtime"。

经过之前的catkin_create_pkg,已经自动把那两条语句添加进了package.xml,检查一下:

jw@G5-5500:~/catkin_ws/src/pkg_a$ ls
CMakeLists.txt  include  msg  package.xml  src
jw@G5-5500:~/catkin_ws/src/pkg_a$ gedit package.xml 

再修改CMakeLists.txt,包括4个点:

jw@G5-5500:~/catkin_ws/src/pkg_a$ gedit CMakeLists.txt
  • 1,find_package,删除message_runtime
find_package(catkin REQUIRED COMPONENTS
  geometry_msgs
  message_generation
  # message_runtime ,删除或注释掉
  roscpp
  rospy
  std_msgs
)
  • 2,catkin_package,取消注释并修改
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES pkg_a
CATKIN_DEPENDS geometry_msgs  message_runtime roscpp rospy std_msgs # 去掉了message_generation
#  DEPENDS system_lib
)
  • 3,add_message_files;取消注释并修改
 add_message_files(
   FILES
   my_message.msg
 )
  • 4,generate_messages;取消注释并修改,添加依赖的msg包
generate_messages(
  DEPENDENCIES
  std_msgs
  geometry_msgs
)

1.1.4 编译

然后进入workplace编译一下,

cd catkin_ws/
catkin_make

编译成功,并且也能查找得到:

jw@G5-5500:~/catkin_ws$ catkin_find_pkg pkg_a
src/pkg_a
jw@G5-5500:~/catkin_ws$ rosmsg list | grep my
pkg_a/my_message
jw@G5-5500:~/catkin_ws$ rosmsg show my_message
[pkg_a/my_message]:
geometry_msgs/Vector3 v2
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 v1
  float64 x
  float64 y
  float64 z
string name
int32 num

1.2 cpp

1.2.1 订阅与发布

roscd pkg_a/src/
gedit puber.cpp 
gedit suber.cpp
//puber.cpp
#include "ros/ros.h"
#include "pkg_a/my_message.h"
#include "sstream"

int main(int argc, char **argv)
{
  std::stringstream ss;
  pkg_a::my_message msg;
  ros::init(argc, argv, "puber");
  ros::NodeHandle h;
  ROS_INFO("Im %s", ros::this_node::getName().c_str());
  ros::Publisher puber = h.advertise<pkg_a::my_message>("my_topic", 10);
  ros::Rate loop_rate(1);
  ss << "A B";

  while (ros::ok())
  {
    
    ss >> msg.name;
    ss >> msg.num;
    ROS_INFO("I Send [name:%s, num:%d]", msg.name.c_str(), msg.num);
    puber.publish(msg);
    loop_rate.sleep();
  }
  return 0;
}


//suber.cpp
#include "ros/ros.h"
#include "pkg_a/my_message.h"

void infoCallback(const pkg_a::my_message::ConstPtr& msg)
// 回调函数名(常量 包名::消息::常量指针 变量名), 用于接收消息,且防止被修改
{
  ROS_INFO("Name Changed [%s %d]", msg->name.c_str(), msg->num);
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "suber");
  ros::NodeHandle n;
  ROS_INFO("Im %s", ros::this_node::getName().c_str());
  ros::Subscriber sub = n.subscribe("my_topic", 1000, infoCallback);
  // 实例化订阅器,且订阅"my_topic"这个话题,并调用回调函数infoCallback
  ros::spin();
  // 有回调函数记得加上这句话
  return 0;
}

1.2.2 修改CmakeLists.txt

除了创建消息的时候,我们修改了功能包pkg_a的CMakeList.xt关于话题使用的消息的配置,现在是节点配置,${PROJECT_NAME}_node直接换成节点名称,其他按照模板填写:

# add_executable(${PROJECT_NAME}_node src/pkg_a_node.cpp)
add_executable(puber src/puber.cpp)
add_executable(suber src/suber.cpp)
# target_link_libraries(${PROJECT_NAME}_node ${catkin_LIBRARIES} )
target_link_libraries(puber ${catkin_LIBRARIES})
target_link_libraries(suber ${catkin_LIBRARIES})
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

1.2.3 编译运行

cd ~/catkin_ws
catkin_make
  • Master
roscore
  • suber
jw@G5-5500:~/catkin_ws$ rosrun pkg_a suber 
[ INFO] [1618652950.893544133]: Im /suber
[ INFO] [1618652951.900597800]: Name Changed [A 0]
  • puber
jw@G5-5500:~/catkin_ws$ rosrun pkg_a puber
[ INFO] [1618652937.898728459]: Im /puber
[ INFO] [1618652937.899726548]: I Send [name:A, num:0]

1.3 python

1.3.1 puber.py

# !/usr/bin/env python
# -*- coding: <encoding name> -*- : # -*- coding: utf-8 -*-
import rospy
from pkg_a.msg import my_message  # 从pkg_a的msg目录下导入my_message.msg
def talker():
	pub = rospy.Publisher('my_topic', my_message, queue_size=10)  # 实例化一个发布者
	rospy.init_node('pyPuber', anonymous=True)  # 初始化节点信息
	rospy.loginfo("Im %s"%rospy.get_name()) # 等同ROS_INFO
	rate = rospy.Rate(10)
	a = my_message()  # 实例化消息
	while not rospy.is_shutdown():
		a.name = "PY"
		a.num = 0
		rospy.loginfo("I sended :%s %d"%(a.name, a.num)) # 等同ROS_INFO
		pub.publish(a)
		rate.sleep()

if __name__ == '__main__':
	try:
		talker()
	except rospy.ROSInterruptException:
		pass

1.3.2 suber.py

#!/usr/bin/env python
# -*- coding: <encoding name> -*- : # -*- coding: utf-8 -*-
import rospy
from pkg_a.msg import my_message  # 从pkg_a的msg目录下导入my_message.msg

def callback(data):
	rospy.loginfo("I receieved :%s %d"%(data.name, data.num))
def listener():
	rospy.init_node('pySuber', anonymous=True)
	rospy.loginfo("Im %s"%rospy.get_name()) # 等同ROS_INFO
	rospy.Subscriber("my_topic", my_message, callback)
	rospy.spin()
if __name__ == '__main__':
    listener()

1.3.3 编译运行

在1.1的基础上,使用自定义的message;

python不需要编译,只需要将.py文件修改为可执行文件即可:

chmod +x puber.py suber.py

运行:

roscore
rosrun pkg_a suber.py 
rosrun pkg_a puber.py 

2 基于 service 通信

2.1 自定义service(包含了request与reply)

2.1.1 新建功能包

2.2 cpp

2.2.1 订阅与发布

2.2.2 编译运行

2.3 python

2.3.1 订阅与发布

2.3.2 编译运行

3 总结cpp与python的区别

上一篇:ROS学习(2)——创建工作空间和创建功能包


下一篇:Ubuntu vscode搭建ROS