当前位置:   article > 正文

ROS通信实操(小乌龟通信实现)(九)C++、Python_python实现turtle_teleop_key

python实现turtle_teleop_key

目录

简介

实操一:话题发布

话题与消息获取

 实现发布节点

命令行实现控制圆周运动 

编码实现 

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++实现 

 新建文件

 复制以下代码

  1. /*
  2. 编写 ROS 节点,控制小乌龟画圆
  3. 准备工作:
  4. 1.获取topic(已知: /turtle1/cmd_vel)
  5. 2.获取消息类型(已知: geometry_msgs/Twist)
  6. 3.运行前,注意先启动 turtlesim_node 节点
  7. 实现流程:
  8. 1.包含头文件
  9. 2.初始化 ROS 节点
  10. 3.创建发布者对象
  11. 4.循环发布运动控制消息
  12. */
  13. #include "ros/ros.h"
  14. #include "geometry_msgs/Twist.h"
  15. int main(int argc, char *argv[])
  16. {
  17. setlocale(LC_ALL,"");
  18. // 2.初始化 ROS 节点
  19. ros::init(argc,argv,"control");
  20. ros::NodeHandle nh;
  21. // 3.创建发布者对象
  22. ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",1000);
  23. // 4.循环发布运动控制消息
  24. //4-1.组织消息
  25. geometry_msgs::Twist msg;
  26. msg.linear.x = 1.0;
  27. msg.linear.y = 0.0;
  28. msg.linear.z = 0.0;
  29. msg.angular.x = 0.0;
  30. msg.angular.y = 0.0;
  31. msg.angular.z = 2.0;
  32. //4-2.设置发送频率
  33. ros::Rate r(10);
  34. //4-3.循环发送
  35. while (ros::ok())
  36. {
  37. pub.publish(msg);
  38. ros::spinOnce();
  39. }
  40. return 0;
  41. }

 配置CMakeLists

 然后编译

运行完成 

如果出现编译无异常,但是运行起来,小乌龟不动的话,肯定是话题名有问题输错了 

python实现 

新建文件

 

 复制以下代码

  1. #! /usr/bin/env python
  2. """
  3. 编写 ROS 节点,控制小乌龟画圆
  4. 准备工作:
  5. 1.获取topic(已知: /turtle1/cmd_vel)
  6. 2.获取消息类型(已知: geometry_msgs/Twist)
  7. 3.运行前,注意先启动 turtlesim_node 节点
  8. 实现流程:
  9. 1.导包
  10. 2.初始化 ROS 节点
  11. 3.创建发布者对象
  12. 4.循环发布运动控制消息
  13. """
  14. import rospy
  15. from geometry_msgs.msg import Twist
  16. if __name__ == "__main__":
  17. # 2.初始化 ROS 节点
  18. rospy.init_node("control_circle_p")
  19. # 3.创建发布者对象
  20. pub = rospy.Publisher("/turtle1/cmd_vel",Twist,queue_size=1000)
  21. # 4.循环发布运动控制消息
  22. rate = rospy.Rate(10)
  23. msg = Twist()
  24. msg.linear.x = 1.0
  25. msg.linear.y = 0.0
  26. msg.linear.z = 0.0
  27. msg.angular.x = 0.0
  28. msg.angular.y = 0.0
  29. msg.angular.z = 0.5
  30. while not rospy.is_shutdown():#判断rospy是否是关闭状态,如果不是运行以下代码
  31. pub.publish(msg)
  32. rate.sleep()

授予权限

修改配置

 

编译

打开终端测试

此处实现成功

实现话题订阅功能

 需求描述: 已知turtlesim中的乌龟显示节点,会发布当前乌龟的位姿(窗体中乌龟的坐标以及朝向),要求控制乌龟运动,并时时打印当前乌龟的位姿。

实现分析:

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

实现流程:

  1. 通过ros命令获取话题与消息信息。
  2. 编码实现位姿获取节点。
  3. 启动 roscore、turtlesim_node 、控制节点以及位姿订阅节点,控制乌龟运动并输出乌龟的位姿。

 话题与消息获取

先编写一个launch文件

 

 

命令方式获取乌龟位姿 

 

 

 C++实现

实现订阅节点

创建功能包需要依赖的功能包: roscpp rospy std_msgs turtlesim

直接修改包依赖

 

 

 然后编译一下看看有没有问题

然后修改CMakeLists

然后复制以下代码

  1. /*
  2. 订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印
  3. 准备工作:
  4. 1.获取话题名称 /turtle1/pose
  5. 2.获取消息类型 turtlesim/Pose
  6. 3.运行前启动 turtlesim_node 与 turtle_teleop_key 节点
  7. 实现流程:
  8. 1.包含头文件
  9. 2.初始化 ROS 节点
  10. 3.创建 ROS 句柄
  11. 4.创建订阅者对象
  12. 5.回调函数处理订阅的数据
  13. 6.spin
  14. */
  15. #include "ros/ros.h"
  16. #include "turtlesim/Pose.h"
  17. void doPose(const turtlesim::Pose::ConstPtr& p){
  18. ROS_INFO("乌龟位姿信息:x=%.2f,y=%.2f,theta=%.2f,lv=%.2f,av=%.2f",
  19. p->x,p->y,p->theta,p->linear_velocity,p->angular_velocity
  20. );
  21. }
  22. int main(int argc, char *argv[])
  23. {
  24. setlocale(LC_ALL,"");
  25. // 2.初始化 ROS 节点
  26. ros::init(argc,argv,"sub_pose");
  27. // 3.创建 ROS 句柄
  28. ros::NodeHandle nh;
  29. // 4.创建订阅者对象
  30. ros::Subscriber sub = nh.subscribe<turtlesim::Pose>("/turtle1/pose",1000,doPose);
  31. // 5.回调函数处理订阅的数据
  32. // 6.spin
  33. ros::spin();
  34. return 0;
  35. }

然后打开终端进行测试

 实现成功

python实现

新建文件

 

 复制以下代码

  1. #! /usr/bin/env python
  2. """
  3. 订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印
  4. 准备工作:
  5. 1.获取话题名称 /turtle1/pose
  6. 2.获取消息类型 turtlesim/Pose
  7. 3.运行前启动 turtlesim_node 与 turtle_teleop_key 节点
  8. 实现流程:
  9. 1.导包
  10. 2.初始化 ROS 节点
  11. 3.创建订阅者对象
  12. 4.回调函数处理订阅的数据
  13. 5.spin
  14. """
  15. import rospy
  16. from turtlesim.msg import Pose
  17. def doPose(data):
  18. rospy.loginfo("乌龟坐标:x=%.2f, y=%.2f,theta=%.2f",data.x,data.y,data.theta)
  19. #指向节点里的信息(data只是一个名字可以任意取)
  20. if __name__ == "__main__":
  21. # 2.初始化 ROS 节点
  22. rospy.init_node("sub_pose_p")
  23. # 3.创建订阅者对象
  24. sub = rospy.Subscriber("/turtle1/pose",Pose,doPose,queue_size=1000)
  25. # 4.回调函数处理订阅的数据
  26. # 5.spin
  27. rospy.spin()

修改CMakeList

 授予权限

 编译

然后打开终端测试

 实现成功

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

需求描述:编码实现向 turtlesim 发送请求,在乌龟显示节点的窗体指定位置生成一乌龟,这是一个服务请求操作。 

 

实现分析:

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

实现流程:

  1. 通过ros命令获取服务与服务消息信息。
  2. 编码实现服务请求节点。
  3. 启动 roscore、turtlesim_node 、乌龟生成节点,生成新的乌龟。

先启动launch文件打开乌龟

 

 服务名称与服务消息获取

 

 

 用命令实现生成小乌龟

 输入这一行命令后按Tab补齐

输入对应指令后生成了一只新的乌龟

C++实现 

 新建文件此处依赖跟上一个实现一致,所以不再修改依赖

 复制以下代码

  1. /*
  2. 生成一只小乌龟
  3. 准备工作:
  4. 1.服务话题 /spawn
  5. 2.服务消息类型 turtlesim/Spawn
  6. 3.运行前先启动 turtlesim_node 节点
  7. 实现流程:
  8. 1.包含头文件
  9. 需要包含 turtlesim 包下资源,注意在 package.xml 配置
  10. 2.初始化 ros 节点
  11. 3.创建 ros 句柄
  12. 4.创建 service 客户端
  13. 5.等待服务启动
  14. 6.发送请求
  15. 7.处理响应
  16. */
  17. #include "ros/ros.h"
  18. #include "turtlesim/Spawn.h"
  19. int main(int argc, char *argv[])
  20. {
  21. setlocale(LC_ALL,"");
  22. // 2.初始化 ros 节点
  23. ros::init(argc,argv,"set_turtle");
  24. // 3.创建 ros 句柄
  25. ros::NodeHandle nh;
  26. // 4.创建 service 客户端
  27. ros::ServiceClient client = nh.serviceClient<turtlesim::Spawn>("/spawn");
  28. // 5.等待服务启动
  29. // client.waitForExistence();
  30. ros::service::waitForService("/spawn");
  31. // 6.发送请求
  32. turtlesim::Spawn spawn;
  33. spawn.request.x = 1.0;
  34. spawn.request.y = 1.0;
  35. spawn.request.theta = 1.57;
  36. spawn.request.name = "my_turtle";
  37. bool flag = client.call(spawn);
  38. // 7.处理响应结果
  39. if (flag)
  40. {
  41. ROS_INFO("新的乌龟生成,名字:%s",spawn.response.name.c_str());
  42. } else {
  43. ROS_INFO("乌龟生成失败!!!");
  44. }
  45. return 0;
  46. }

修改配置

 编译

 打开终端测试

运行成功

 Python实现

新建文件

 

复制以下代码

  1. #! /usr/bin/env python
  2. """
  3. 生成一只小乌龟
  4. 准备工作:
  5. 1.服务话题 /spawn
  6. 2.服务消息类型 turtlesim/Spawn
  7. 3.运行前先启动 turtlesim_node 节点
  8. 实现流程:
  9. 1.导包
  10. 需要包含 turtlesim 包下资源,注意在 package.xml 配置
  11. 2.初始化 ros 节点
  12. 3.创建 service 客户端
  13. 4.等待服务启动
  14. 5.发送请求
  15. 6.处理响应
  16. """
  17. import rospy
  18. from turtlesim.srv import Spawn,SpawnRequest,SpawnResponse
  19. if __name__ == "__main__":
  20. # 2.初始化 ros 节点
  21. rospy.init_node("set_turtle_p")
  22. # 3.创建 service 客户端
  23. client = rospy.ServiceProxy("/spawn",Spawn)
  24. # 4.等待服务启动
  25. client.wait_for_service()
  26. # 5.发送请求
  27. req = SpawnRequest()
  28. req.x = 2.0
  29. req.y = 2.0
  30. req.theta = -1.57
  31. req.name = "my_turtle_p"
  32. try:
  33. response = client.call(req)
  34. # 6.处理响应
  35. rospy.loginfo("乌龟创建成功!,叫:%s",response.name)
  36. except expression as identifier:
  37. 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++实现

新建文件

 

复制以下代码

  1. /*
  2. 注意命名空间的使用。
  3. */
  4. #include "ros/ros.h"
  5. int main(int argc, char *argv[])
  6. {
  7. ros::init(argc,argv,"haha");
  8. ros::NodeHandle nh("turtlesim");
  9. //ros::NodeHandle nh;
  10. // ros::param::set("/turtlesim/background_r",0);
  11. // ros::param::set("/turtlesim/background_g",0);
  12. // ros::param::set("/turtlesim/background_b",0);
  13. nh.setParam("background_r",0);
  14. nh.setParam("background_g",0);
  15. nh.setParam("background_b",0);
  16. return 0;
  17. }

 修改配置

编译

 打开终端测试

 变成黑色了

用节点句柄的方式实现

代码如下 

 

 测试

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

 新建文件

 

 授予权限

 

 

修改配置

 此处注意,编译是针对整个功能包进行编译,会自动保存

打开终端测试

 通信机制比较

三种通信机制中,参数服务器是一种数据共享机制,可以在不同的节点之间共享数据,话题通信与服务通信是在不同的节点之间传递数据的,三者是ROS中最基础也是应用最为广泛的通信机制。 

这其中,话题通信和服务通信有一定的相似性也有本质上的差异,在此将二者做一下简单比较:

二者的实现流程是比较相似的,都是涉及到四个要素:

  • 要素1: 消息的发布方/客户端(Publisher/Client)
  • 要素2: 消息的订阅方/服务端(Subscriber/Server)
  • 要素3: 话题名称(Topic/Service)
  • 要素4: 数据载体(msg/srv)

下表为话题通信和服务通信比较 

 

 话题通信可以理解成打电话(a要联系b)

服务通信可以理解成跟服务商联系进行服务(比如说a要计算1+1,发给了b,b算好了发给a)

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/401088?site
推荐阅读
相关标签
  

闽ICP备14008679号