素材巴巴 > 程序开发 >

ROS通信实操(小乌龟通信实现)(九)C 、Python

程序开发 2023-09-02 20:23:08

目录

简介

实操一:话题发布

话题与消息获取

 实现发布节点

命令行实现控制圆周运动 

编码实现 

C++实现 

python实现 

实现话题订阅功能

 话题与消息获取

命令方式获取乌龟位姿 

 C++实现

python实现

实现话题订阅生成多个小乌龟

 用命令实现生成小乌龟

C++实现 

 Python实现

参数服务器实现改颜色

 命令行更改颜色

 C++实现

用节点句柄的方式实现

 Python修改参数服务器实现改颜色

 通信机制比较


 

简介

主要是通过ROS内置的turtlesim案例,结合已经介绍ROS命令获取节点、话题、话题消息、服务、服务消息与参数的信息,最终再以编码的方式实现乌龟运动的控制、乌龟位姿的订阅、乌龟生成与乌龟窗体背景颜色的修改。

实操一:话题发布

实现分析:

  1. 乌龟运动控制实现,关键节点有两个,一个是乌龟运动显示节点 turtlesim_node,另一个是控制节点,二者是订阅发布模式实现通信的,乌龟运动图形化显示节点直接调用即可,运动控制节点之前是使用的 turtle_teleop_key通过键盘 控制,现在需要自定义控制节点。
  2. 控制节点自实现时,首先需要了解控制节点与显示节点通信使用的话题与消息,可以使用ros命令结合计算图来获取。
  3. 了解了话题与消息之后,通过 C++ 或 Python 编写运动控制节点,通过指定的话题,按照一定的逻辑发布消息即可。

实现流程:

  1. 通过计算图结合ros命令获取话题与消息信息。
  2. 编码实现运动控制节点。
  3. 启动 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中的乌龟显示节点,会发布当前乌龟的位姿(窗体中乌龟的坐标以及朝向),要求控制乌龟运动,并时时打印当前乌龟的位姿。

实现分析:

  1. 首先,需要启动乌龟显示以及运动控制节点并控制乌龟运动。
  2. 要通过ROS命令,来获取乌龟位姿发布的话题以及消息。
  3. 编写订阅节点,订阅并打印乌龟的位姿。

实现流程:

  1. 通过ros命令获取话题与消息信息。
  2. 编码实现位姿获取节点。
  3. 启动 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 发送请求,在乌龟显示节点的窗体指定位置生成一乌龟,这是一个服务请求操作。 

 

实现分析:

  1. 首先,需要启动乌龟显示节点。
  2. 要通过ROS命令,来获取乌龟生成服务的服务名称以及服务消息类型。
  3. 编写服务请求节点,生成新的乌龟。

实现流程:

  1. 通过ros命令获取服务与服务消息信息。
  2. 编码实现服务请求节点。
  3. 启动 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 方式设置的。

 

实现分析:

  1. 首先,需要启动乌龟显示节点。
  2. 要通过ROS命令,来获取参数服务器中设置背景色的参数。
  3. 编写参数设置节点,修改参数服务器中的参数值。

实现流程:

  1. 通过ros命令获取参数。
  2. 编码实现服参数设置节点。
  3. 启动 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)

 


标签:

素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。