前言
📢本系列将依托赵虚左老师的ROS课程,写下自己的一些心得与笔记。
📢课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ
📢讲义链接:http://www.autolabor.com.cn/book/ROSTutorials/index.html
📢 文章可能存在疏漏的地方,恳请大家指出。
实现流程:
一些关于运动学的基本概念可以参考
自动驾驶路径跟踪控制——车辆动力学建模基本概念
创建功能包需要依赖的功能包: roscpp rospy std_msgs geometry_msgs
注意多了一个geometry_msgs
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
/*编写 ROS 节点,控制小乌龟画圆准备工作:1.获取topic(已知: /turtle1/cmd_vel)2.获取消息类型(已知: geometry_msgs/Twist)3.运行前,注意先启动 turtlesim_node 节点实现流程:1.包含头文件2.初始化 ROS 节点3.创建发布者对象4.循环发布运动控制消息
*/
int main(int argc, char *argv[])
{//初始化 ROS 节点ros::init(argc,argv,"talker_turtle");ros::NodeHandle nh;// 创建发布者对象ros::Publisher pub = nh.advertise("/turtle1/cmd_vel",30);//设置发布频率ros::Rate rate(10);//循环发布运动控制消息geometry_msgs::Twist twist;//线速度twist.linear.x = 1.0;twist.linear.y = 0.0;twist.linear.z = 0.0;//角速度twist.angular.x = 0.0;twist.angular.y = 0.0;twist.angular.z = 1.0;while(ros::ok()){pub.publish(twist);rate.sleep();ros::spinOnce();}return 0;
}
CmakeLists配置
add_executable(test_publisher_turtle src/test_publisher_turtle.cpp)add_dependencies(test_publisher_turtle ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})target_link_libraries(test_publisher_turtle${catkin_LIBRARIES}
)
#! /usr/bin/env python
#-- coding:UTF-8 --
import rospy
from geometry_msgs.msg import Twist"""编写 ROS 节点,控制小乌龟画圆准备工作:1.获取topic(已知: /turtle1/cmd_vel)2.获取消息类型(已知: geometry_msgs/Twist)3.运行前,注意先启动 turtlesim_node 节点实现流程:1.导包2.初始化 ROS 节点3.创建发布者对象4.循环发布运动控制消息"""if __name__ == "__main__":# 初始化 ROS 节点rospy.init_node("test_pub")# 创建发布者对象pub = rospy.Publisher("/turtle1/cmd_vel",Twist,queue_size =30)# 循环发布运动控制消息rate = rospy.Rate(10)# 创建速度消息twist = Twist()twist.linear.x = 1.0twist.linear.y = 0.0twist.linear.z = 0.0twist.angular.x = 0.0twist.angular.y = 0.0twist.angular.z = 1.0# 循环发布while not rospy.is_shutdown():pub.publish(twist)rate.sleep()
实现流程:
创建功能包需要依赖的功能包: roscpp rospy std_msgs turtlesim
因为先前已经创建过功能包了,所以只需在配置文件中补上相关内容。
CmakeLists
find_package(catkin REQUIRED COMPONENTSgeometry_msgsroscpprospystd_msgsturtlesim
)
package.xml
turtlesim turtlesim
/* 订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印准备工作: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;
}
launch文件
#! /usr/bin/env python
#-- coding:UTF-8 --
"""订阅小乌龟的位姿: 时时获取小乌龟在窗体中的坐标并打印准备工作: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,linear_velocity=%lf",data.x,data.y,data.theta,data.linear_velocity)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()
实现流程:
创建功能包需要依赖的功能包: roscpp rospy std_msgs turtlesim
/*生成一只小乌龟准备工作: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 = "turtle2";bool flag = client.call(spawn);// 7.处理响应结果if (flag){ROS_INFO("新的乌龟生成,名字:%s",spawn.response.name.c_str());} else {ROS_INFO("乌龟生成失败!!!");}return 0;
}
#! /usr/bin/env python
#-- coding:UTF-8 --
"""生成一只小乌龟准备工作: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("服务调用失败")
实现流程:
/*注意命名空间的使用。*/
#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;
}
#! /usr/bin/env python
#-- coding:UTF-8 --
import rospyif __name__ == "__main__":rospy.init_node("hehe")# rospy.set_param("/turtlesim/background_r",255)# rospy.set_param("/turtlesim/background_g",255)# rospy.set_param("/turtlesim/background_b",255)rospy.set_param("background_r",255)rospy.set_param("background_g",255)rospy.set_param("background_b",255) # 调用时,需要传入 __ns:=xxx
首先,启动 roscore;
然后启动背景色设置节点;
最后启动乌龟显示节点;
最终执行结果与演示结果类似。
PS: 注意节点启动顺序,如果先启动乌龟显示节点,后启动背景色设置节点,那么颜色设置不会生效。
rosparam set /turtlesim/background_b 自定义数值
rosparam set /turtlesim/background_r 自定义数值
rosparam set /turtlesim/background_g 自定义数值
rosrun turtlesim turtlesim_node _background_r:=100 _background_g:=0 _background_b:=0