Ros安装:
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 国内: sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116 sudo apt-get update sudo apt-get install ros-melodic-desktop-full
,参看古月21讲!
ros是否安装成功测试:
第一步: roscore
第二步: rosrun turtlesim turtlesim_node
第三步 rosrun turtlesim turtle_teleop_key
此时就可以通过键盘的上下左右键控制 小海龟了!
Ros命令行工具的使用:
命令rqt_graph :
它会显示当前全局的节点图
rosnode 相关的命令:
rosnode list :
它会把所有的节点都列出来。
rosnode info :
它可以查看某个节点的信息:
例如:
rosnode info turtlesim
输出为:
-------------------------------------------------------------------------------- Node [/turtlesim] Publications: * /rosout [rosgraph_msgs/Log] * /turtle1/color_sensor [turtlesim/Color] * /turtle1/pose [turtlesim/Pose] Subscriptions: * /turtle1/cmd_vel [geometry_msgs/Twist] Services: * /clear * /kill * /reset * /spawn * /turtle1/set_pen * /turtle1/teleport_absolute * /turtle1/teleport_relative * /turtlesim/get_loggers * /turtlesim/set_logger_level contacting node http://zcb-vm:35989/ ... Pid: 3141 Connections: * topic: /rosout * to: /rosout * direction: outbound * transport: TCPROS * topic: /turtle1/cmd_vel * to: /teleop_turtle (http://zcb-vm:32913/) * direction: inbound * transport: TCPROS
rostopic 相关的命令:
它是和话题相关的命令
rostopic list :
可以打印出所有的话题列表!
输出为:
/rosout
/rosout_agg
/turtle1/cmd_vel (它就是前面用于 操控海龟运动的消息 )
/turtle1/color_sensor
/turtle1/pose
我们可以 给消息传入数据(通过 rostopic pub 发布) 以实现通过命令行 操控海龟,如下:
通过 -r 参数设置发布频率
-r 10 就是10HZ 就是1s发布10次 。
下面查看rosmsg 的结构:
rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
rosservice 相关的命令:
rostopic list :
可以打印出所有的服务列表!
/clear
/kill
/reset
/rosout/get_loggers
/rosout/set_logger_level
/spawn
/teleop_turtle/get_loggers
/teleop_turtle/set_logger_level
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/get_loggers
/turtlesim/set_logger_level
产生一个新的海龟(使用spawn 服务):
rosservice call call个服务!!!
话题记录工具 rosbag :
它就是用来复现 操作的。
rosbag record
-a 选项的意思是记录全部
后面的cmd_record 是保存到的压缩文件。
之后ctrl c
数据就自动保存到当前终端的目录下了!
然后可以使用rosbag play 命令进行复现!
创建工作空间和功能包:
创建工作空间:
工作空间,就类似于IDE中创建的工程,
src是放 功能包 的!
build 是放置 中间产生的 编译文件的,(基本不用关心它)
devel 是放置 生成的可执行文件,一些库,一些脚本等等,(最终运行都是在这里的!)
install 是 安装成功之后,安装的路径,(类似 win 中program files 是默认的路径一样)
创建功能包:
注意:一定要在 src空间创建功能包。
下面看下它们的作用,
先看package.xml
它主要是关于 功能包的一些信息!
再看CMakeLists.txt
它主要是描述功能包中的编译规则。它使用的语法是cmake 的语法,
总结:
通过功能包可以完成代码的组织,通过工作空间可以完成功能包中代码的编译和运行!!!
发布者publisher的编程实现(topic 的学习):
先创建功能包:
后面的roscpp rospy std_msgs geometry_msgs turtlesim 都是依赖。
创建发布者代码(C++)
C++代码:
1 #include <ros/ros.h> 2 #include <geometry_msgs/Twist.h> 3 4 int main(int argc,char **argv){ 5 //ROS节点初始化 6 ros:: init(argc,argv,"velocity_publisher"); //注意节点名字不能重复 7 8 //创建节点句柄 9 ros:: NodeHandle n; 10 11 //创建一个Publisher ,发布名为 /turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist ,队列长度 10 12 ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10); //第一个参数是向哪个消息中发布数据, 第二个10是队列长度,因为如果每秒发布10000次,但是底层的以太网不可能来得及响应,就会先放到这个队列中 13 //注: 如果队列中占满了,它会去除时间戳最老的数据, 14 15 16 17 18 //设置循环频率 19 ros:: Rate loop_rate(10); //10HZ 1s 10次 20 21 int count =0; 22 while(ros::ok()){ 23 //初始化geometry_msgs::Twist 类型的消息 24 geometry_msgs:: Twist vel_msg; 25 vel_msg.liner.x = 0.5; 26 vel_msg.angular.z = 0.2; 27 28 //发布消息 29 turtle_vel_pub.publish(vel_msg); 30 ROS_INFO("Publish turtle velocity command[%0.2f m/s ,%0.2f rad/s] ", 31 vel_msg.liner.x,vel_msg.angular.z); 32 //ROS_INFO 类似于 printf() 33 34 //按照循环频率 延时 35 loop_rate.sleep(); //1s 10次 36 37 } 38 return 0;
下面要配置 上面代码的编译规则(修改cmakelists.txt)
add_executable () 的作用是将 src/velocity_publisher.cpp 编译成 velocity_publisher 可执行文件。
target_link_libraries()的作用是将 生成的可执行文件和 ros一些库做链接的(主要是C++ 的一些接口)。
总结:先做代码的编译,然后再做 链接。
编译并运行代码:
Python 版本:
#!/usr/bin/env python # -*- coding:utf-8 -*- #该例子 将发布turtle1/cmd_vel 话题,消息类型为geometry_msgs::Twist import rospy from geometry_msgs.msg import Twist def velocity_publisher(): #ROS 节点初始化 rospy.init_node("velocity_publisher",anonymous=True) #匿名的 #创建一个Publisher ,消息名字为/turtle1/cmd_vel 的topic ,消息类型为geometry_msgs::Twist 队列长度为10 turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel',Twist,queue_size=10) #设置循环的频率 rate = rospy.Rate(10) #1s 10次 while not rospy.is_shutdown(): #初始化 geometry_msgs:: Twist 类型的消息 vel_msg = Twist() vel_msg.linear.x = 0.8 vel_msg.angular.z = 0.2 #发布消息 turtle_vel_pub.publish(vel_msg) rospy.loginfo("Publish turtle velocity command [{:.2f}m/s, {:.2f}rad/s ]".format(vel_msg.linear.x,vel_msg.angular.z)) #按照循环 频率延时 rate.sleep() if __name__ == '__main__': try: velocity_publisher() except: pass
注意要给python 文件加上可执行的权限。Python 的代码不需要进行cmake 编译。
订阅者subscriber的编程实现(topic 的学习):
C++代码:
1 /** 2 * 该例子将订阅 /turtle1/pose 话题 ,消息类型为 turtlesim::Pose 3 */ 4 #include <ros/ros.h> 5 #include <turtlesim/Pose.h> 6 7 //接收到订阅消息后,会进入消息回调函数 8 void poseCallback(const turtlesim::Pose::ConstPtr& msg){ 9 //将 接收到的消息 打印出来 10 ROS_INFO("Turtle pose: x:%0.6f ,y:%0.6f",msg->x,msg->y); 11 } 12 int main(int argc,char **argv){ 13 //初始化 ROS 节点 14 ros::init(argc,argv,"pose_subscriber"); 15 16 //创建节点句柄 17 ros::NodeHandle n; 18 19 //创建一个Subscriber ,消息名为 turtle1/pose的消息 ,注册回调函数 20 ros::Subscriber pose_sub = n.subscribe("/turtle1/pose",10,poseCallback); 21 22 //循环等待回调函数 23 ros::spin(); 24 25 return 0; 26 27 }
python 版代码:
1 #!usr/bin/env python 2 # -*- coding:utf-8 -*- 3 #该例子 将订阅 /turtle1/pose 话题,消息类型为 turtlesim::Pose 4 5 import rospy 6 from turtlesim.msg import Pose 7 8 def poseCallback(msg): 9 rospy.loginfo("Turtle pose x:{:.6f} y:{:.6f}".format(msg.x,msg.y)) 10 11 def pose_subscriber(): 12 #ROS 节点初始化 13 rospy.init_node("pose_subscriber",anonymous=True) 14 15 #创建一个 subscriber ,消息名为/turtle1/pose 的topic 注册回调函数poseCallback 16 rospy.Subscriber("/turtle1/pose",Pose,poseCallback) 17 18 #循环等待回调函数 19 rospy.spin() 20 if __name__ == "__main__": 21 pose_subscriber()
这里要注意的是 回调函数中要尽量的快(不能有很多的嵌套)。不然,会有问题出现!
话题消息的自定义与使用(topic的学习):
自定义话题消息:
注:Person.msg 是一个与语言无关的文件。
之后在工作的空间的根目录下使用catkin_make编译。通过之后会在devel/include/learning_topic/下产生一个Person.h 的C++头文件!!!
下面创建消息的发布者和订阅者:
代码:
1 /* 2 该例子将发布/person_info 话题 ,自定义消息类型为 learning_topic::Person 3 4 */ 5 #include <ros/ros.h> 6 #include "learning_topic/Person.h" 7 int main(int argc,char **argv){ 8 //ros节点 初始化 9 ros:: init(argc,argv,"person_publisher"); 10 11 //创建节点句柄 12 ros::NodeHandle n; 13 14 //创建一个Publisher ,发布名为/person_info 消息类型为 learning_topic::Person,队列长度10 15 ros::Publisher person_info_pub = n.advertise<learning_topic::Person>("/person_info",10); 16 17 //设置循环的频率 18 ros::Rate loop_rate(1); 19 20 int count=0; 21 while(ros::ok()){ 22 //初始化 learning_topic::Person 类型的消息 23 learning_topic::Person person_msg; 24 person_msg.name = "tom"; 25 person_msg.age = 18; 26 person_msg.sex = learning_topic::Person::male; 27 28 //发布消息 29 person_info_pub.publish(person_msg); 30 31 ROS_INFO("Publish Person Info:name: %s age: %d sex: %d",person_msg.name.c_str(),person_msg.age,person_msg.sex); 32 33 //按照循环频率延时 34 loop_rate.sleep(); 35 } 36 37 return 0; 38 39 }
1 /* 2 3 该例子订阅/person_info 话题 自定义消息类型为 learning_topic::Person 4 5 */ 6 7 #include <ros/ros.h> 8 #include "learning_topic/Person.h" 9 10 //接收订阅的消息后,会进入到 消息回调函数 11 void personInfoCallback(const learning_topic::Person::ConstPtr & msg){ 12 //将接收到的消息打印出来 13 ROS_INFO("Subscribe Person Info:name:%s age:%d sex:%d",msg->name.c_str(),msg->age,msg->sex); 14 } 15 int main(int argc,char ** argv){ 16 17 //初始化ros节点 18 ros::init(argc,argv,"person_subscriber"); 19 20 //创建节点句柄 21 ros::NodeHandle n; 22 23 //创建一个Subscriber,订阅名为 /person_info 的topic 注册回调函数为personInfoCallback() 24 ros::Subscriber person_info_sub = n.subscribe("/person_info",10,personInfoCallback); 25 26 //循环等待回调函数 27 ros::spin(); 28 29 return 0; 30 }
然后在CMakeLists.txt 中配置代码的编译规则:
之后在工作的空间的根目录下使用catkin_make编译!
下面分别运行:
roscore
rosrun learning_topic person_subscriber
rosrun learning_topic person_publisher
就能看到收发消息了。
具体Python 代码省略。