ROS通信实操(小乌龟通信实现)(九)C 、Python
目录
简介
实操一:话题发布
话题与消息获取
实现发布节点
命令行实现控制圆周运动
编码实现
C++实现
python实现
实现话题订阅功能
话题与消息获取
命令方式获取乌龟位姿
C++实现
python实现
实现话题订阅生成多个小乌龟
用命令实现生成小乌龟
C++实现
Python实现
参数服务器实现改颜色
命令行更改颜色
C++实现
用节点句柄的方式实现
Python修改参数服务器实现改颜色
通信机制比较
简介
主要是通过ROS内置的turtlesim案例,结合已经介绍ROS命令获取节点、话题、话题消息、服务、服务消息与参数的信息,最终再以编码的方式实现乌龟运动的控制、乌龟位姿的订阅、乌龟生成与乌龟窗体背景颜色的修改。
实操一:话题发布
实现分析:
- 乌龟运动控制实现,关键节点有两个,一个是乌龟运动显示节点 turtlesim_node,另一个是控制节点,二者是订阅发布模式实现通信的,乌龟运动图形化显示节点直接调用即可,运动控制节点之前是使用的 turtle_teleop_key通过键盘 控制,现在需要自定义控制节点。
- 控制节点自实现时,首先需要了解控制节点与显示节点通信使用的话题与消息,可以使用ros命令结合计算图来获取。
- 了解了话题与消息之后,通过 C++ 或 Python 编写运动控制节点,通过指定的话题,按照一定的逻辑发布消息即可。
实现流程:
- 通过计算图结合ros命令获取话题与消息信息。
- 编码实现运动控制节点。
- 启动 roscore、turtlesim_node 以及自定义的控制节点,查看运行结果。
话题与消息获取
准备: 先启动键盘控制乌龟运动案例。
话题获取
显示了节点的话题
消息获取
通过上面获取的话题名来获取消息type
获取消息格式:
乌龟线速度取值只有x和角速度z
因为只有前后左右四个键位控制运动
来验证一下
可以看到只有线速度x和角速度y
因为只有上下左右四个键
上下控制线速度x
左右控制角速度z
弧度: 单位弧度定义为圆弧长度等于半径时的圆心角。
实现发布节点
命令行实现控制圆周运动
输入这一段,然后一直按Tab补全
改成这个
然后回车
就简单实现了
编码实现
新建功能包
建立依赖
C++实现
新建文件
复制以下代码
/*编写 ROS 节点,控制小乌龟画圆准备工作:1.获取topic(已知: /turtle1/cmd_vel)2.获取消息类型(已知: geometry_msgs/Twist)3.运行前,注意先启动 turtlesim_node 节点实现流程:1.包含头文件2.初始化 ROS 节点3.创建发布者对象4.循环发布运动控制消息
*/#include "ros/ros.h"
#include "geometry_msgs/Twist.h"int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 2.初始化 ROS 节点ros::init(argc,argv,"control");ros::NodeHandle nh;// 3.创建发布者对象ros::Publisher pub = nh.advertise("/turtle1/cmd_vel",1000);// 4.循环发布运动控制消息//4-1.组织消息geometry_msgs::Twist msg;msg.linear.x = 1.0;msg.linear.y = 0.0;msg.linear.z = 0.0;msg.angular.x = 0.0;msg.angular.y = 0.0;msg.angular.z = 2.0;//4-2.设置发送频率ros::Rate r(10);//4-3.循环发送while (ros::ok()){pub.publish(msg);ros::spinOnce();}return 0;
}
配置CMakeLists
然后编译
运行完成
如果出现编译无异常,但是运行起来,小乌龟不动的话,肯定是话题名有问题输错了
python实现
新建文件
复制以下代码
#! /usr/bin/env python
"""编写 ROS 节点,控制小乌龟画圆准备工作:1.获取topic(已知: /turtle1/cmd_vel)2.获取消息类型(已知: geometry_msgs/Twist)3.运行前,注意先启动 turtlesim_node 节点实现流程:1.导包2.初始化 ROS 节点3.创建发布者对象4.循环发布运动控制消息"""import rospy
from geometry_msgs.msg import Twistif __name__ == "__main__":# 2.初始化 ROS 节点rospy.init_node("control_circle_p")# 3.创建发布者对象pub = rospy.Publisher("/turtle1/cmd_vel",Twist,queue_size=1000)# 4.循环发布运动控制消息rate = rospy.Rate(10)msg = Twist()msg.linear.x = 1.0msg.linear.y = 0.0msg.linear.z = 0.0msg.angular.x = 0.0msg.angular.y = 0.0msg.angular.z = 0.5while not rospy.is_shutdown():#判断rospy是否是关闭状态,如果不是运行以下代码pub.publish(msg)rate.sleep()
授予权限
修改配置
编译
打开终端测试
此处实现成功
实现话题订阅功能
需求描述: 已知turtlesim中的乌龟显示节点,会发布当前乌龟的位姿(窗体中乌龟的坐标以及朝向),要求控制乌龟运动,并时时打印当前乌龟的位姿。
实现分析:
- 首先,需要启动乌龟显示以及运动控制节点并控制乌龟运动。
- 要通过ROS命令,来获取乌龟位姿发布的话题以及消息。
- 编写订阅节点,订阅并打印乌龟的位姿。
实现流程:
- 通过ros命令获取话题与消息信息。
- 编码实现位姿获取节点。
- 启动 roscore、turtlesim_node 、控制节点以及位姿订阅节点,控制乌龟运动并输出乌龟的位姿。
话题与消息获取
先编写一个launch文件
命令方式获取乌龟位姿
C++实现
实现订阅节点
创建功能包需要依赖的功能包: roscpp rospy std_msgs turtlesim
直接修改包依赖
然后编译一下看看有没有问题
然后修改CMakeLists
然后复制以下代码
/* 订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印准备工作:1.获取话题名称 /turtle1/pose2.获取消息类型 turtlesim/Pose3.运行前启动 turtlesim_node 与 turtle_teleop_key 节点实现流程:1.包含头文件2.初始化 ROS 节点3.创建 ROS 句柄4.创建订阅者对象5.回调函数处理订阅的数据6.spin
*/#include "ros/ros.h"
#include "turtlesim/Pose.h"void doPose(const turtlesim::Pose::ConstPtr& p){ROS_INFO("乌龟位姿信息:x=%.2f,y=%.2f,theta=%.2f,lv=%.2f,av=%.2f",p->x,p->y,p->theta,p->linear_velocity,p->angular_velocity);
}int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 2.初始化 ROS 节点ros::init(argc,argv,"sub_pose");// 3.创建 ROS 句柄ros::NodeHandle nh;// 4.创建订阅者对象ros::Subscriber sub = nh.subscribe("/turtle1/pose",1000,doPose);// 5.回调函数处理订阅的数据// 6.spinros::spin();return 0;
}
然后打开终端进行测试
实现成功
python实现
新建文件
复制以下代码
#! /usr/bin/env python
"""订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印准备工作:1.获取话题名称 /turtle1/pose2.获取消息类型 turtlesim/Pose3.运行前启动 turtlesim_node 与 turtle_teleop_key 节点实现流程:1.导包2.初始化 ROS 节点3.创建订阅者对象4.回调函数处理订阅的数据5.spin"""import rospy
from turtlesim.msg import Posedef doPose(data):rospy.loginfo("乌龟坐标:x=%.2f, y=%.2f,theta=%.2f",data.x,data.y,data.theta)
#指向节点里的信息(data只是一个名字可以任意取)if __name__ == "__main__":# 2.初始化 ROS 节点rospy.init_node("sub_pose_p")# 3.创建订阅者对象sub = rospy.Subscriber("/turtle1/pose",Pose,doPose,queue_size=1000)# 4.回调函数处理订阅的数据# 5.spinrospy.spin()
修改CMakeList
授予权限
编译
然后打开终端测试
实现成功
实现话题订阅生成多个小乌龟
需求描述:编码实现向 turtlesim 发送请求,在乌龟显示节点的窗体指定位置生成一乌龟,这是一个服务请求操作。
实现分析:
- 首先,需要启动乌龟显示节点。
- 要通过ROS命令,来获取乌龟生成服务的服务名称以及服务消息类型。
- 编写服务请求节点,生成新的乌龟。
实现流程:
- 通过ros命令获取服务与服务消息信息。
- 编码实现服务请求节点。
- 启动 roscore、turtlesim_node 、乌龟生成节点,生成新的乌龟。
先启动launch文件打开乌龟
服务名称与服务消息获取
用命令实现生成小乌龟
输入这一行命令后按Tab补齐
输入对应指令后生成了一只新的乌龟
C++实现
新建文件此处依赖跟上一个实现一致,所以不再修改依赖
复制以下代码
/*生成一只小乌龟准备工作:1.服务话题 /spawn2.服务消息类型 turtlesim/Spawn3.运行前先启动 turtlesim_node 节点实现流程:1.包含头文件需要包含 turtlesim 包下资源,注意在 package.xml 配置2.初始化 ros 节点3.创建 ros 句柄4.创建 service 客户端5.等待服务启动6.发送请求7.处理响应*/#include "ros/ros.h"
#include "turtlesim/Spawn.h"int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 2.初始化 ros 节点ros::init(argc,argv,"set_turtle");// 3.创建 ros 句柄ros::NodeHandle nh;// 4.创建 service 客户端ros::ServiceClient client = nh.serviceClient("/spawn");// 5.等待服务启动// client.waitForExistence();ros::service::waitForService("/spawn");// 6.发送请求turtlesim::Spawn spawn;spawn.request.x = 1.0;spawn.request.y = 1.0;spawn.request.theta = 1.57;spawn.request.name = "my_turtle";bool flag = client.call(spawn);// 7.处理响应结果if (flag){ROS_INFO("新的乌龟生成,名字:%s",spawn.response.name.c_str());} else {ROS_INFO("乌龟生成失败!!!");}return 0;
}
修改配置
编译
打开终端测试
运行成功
Python实现
新建文件
复制以下代码
#! /usr/bin/env python
"""生成一只小乌龟准备工作:1.服务话题 /spawn2.服务消息类型 turtlesim/Spawn3.运行前先启动 turtlesim_node 节点实现流程:1.导包需要包含 turtlesim 包下资源,注意在 package.xml 配置2.初始化 ros 节点3.创建 service 客户端4.等待服务启动5.发送请求6.处理响应"""import rospy
from turtlesim.srv import Spawn,SpawnRequest,SpawnResponseif __name__ == "__main__":# 2.初始化 ros 节点rospy.init_node("set_turtle_p")# 3.创建 service 客户端client = rospy.ServiceProxy("/spawn",Spawn)# 4.等待服务启动client.wait_for_service()# 5.发送请求req = SpawnRequest()req.x = 2.0req.y = 2.0req.theta = -1.57req.name = "my_turtle_p"try:response = client.call(req)# 6.处理响应rospy.loginfo("乌龟创建成功!,叫:%s",response.name)except expression as identifier:rospy.loginfo("服务调用失败")
授权
修改配置
编译
终端中打开
运行成功
参数服务器实现改颜色
需求描述: 修改turtlesim乌龟显示节点窗体的背景色,已知背景色是通过参数服务器的方式以 rgb 方式设置的。
实现分析:
- 首先,需要启动乌龟显示节点。
- 要通过ROS命令,来获取参数服务器中设置背景色的参数。
- 编写参数设置节点,修改参数服务器中的参数值。
实现流程:
- 通过ros命令获取参数。
- 编码实现服参数设置节点。
- 启动 roscore、turtlesim_node 与参数设置节点,查看运行结果。
用终端启动小乌龟GUI
不用launch启动的原因
因为launch同时启动roscore和GUI节点
更新参数后需要重启节点
关闭了launch后roscore也关闭了
参数服务器重置
更新的参数失效
所以用终端
保持roscore启动的同时关闭节点
让节点从roscore参数服务器中重新获取参数更新GUI
这里可以看到三个参数的值构成了这样的背景色
命令行更改颜色
修改后颜色没变
是因为节点启动的时候调用的未修改的参数
重新启动节点即可
C++实现
新建文件
复制以下代码
/*注意命名空间的使用。*/
#include "ros/ros.h"int main(int argc, char *argv[])
{ros::init(argc,argv,"haha");ros::NodeHandle nh("turtlesim");//ros::NodeHandle nh;// ros::param::set("/turtlesim/background_r",0);// ros::param::set("/turtlesim/background_g",0);// ros::param::set("/turtlesim/background_b",0);nh.setParam("background_r",0);nh.setParam("background_g",0);nh.setParam("background_b",0);return 0;
}
修改配置
编译
打开终端测试
变成黑色了
用节点句柄的方式实现
代码如下
测试
Python修改参数服务器实现改颜色
新建文件
授予权限
修改配置
此处注意,编译是针对整个功能包进行编译,会自动保存
打开终端测试
通信机制比较
三种通信机制中,参数服务器是一种数据共享机制,可以在不同的节点之间共享数据,话题通信与服务通信是在不同的节点之间传递数据的,三者是ROS中最基础也是应用最为广泛的通信机制。
这其中,话题通信和服务通信有一定的相似性也有本质上的差异,在此将二者做一下简单比较:
二者的实现流程是比较相似的,都是涉及到四个要素:
下表为话题通信和服务通信比较
话题通信可以理解成打电话(a要联系b)
服务通信可以理解成跟服务商联系进行服务(比如说a要计算1+1,发给了b,b算好了发给a)
标签:
相关文章
-
无相关信息