roscore 打开主节点
rosnode list 显示所有激活的节点名
rostopic list 显示所有激活的主题名
rosmsg list 显示所有消息列表
rosnode info 节点名
rosrun 包名 节点名
source devel/setup.sh
source /opt/ros/noetic/setup.sh
rosrun haitao fabu.py
这里haitao是包名,fabu.py是节点文件的名称
rosversion -d 查看ros的版本
rospy.Timer(rospy.Duration(5), 指定方法) 定时5秒触发指定方法
rqt_graph 显示节点的订阅关系
catkin_make 进入工作空间目录,执行这条指令,进行编译,一般对c++节点修改添加后 都要重新编译
rosrun 功能包名 节点名
在 工作空间/src下创建一个包 ,包名后面的就是依赖
cd ~/工作空间名/src catkin_create_pkg 包名 std_msgs rospy roscpp geometry_msgs turtlesim
创建的包内容如下:
创建一个节点,并在节点里发布一个话题
可以在功能包下面创建一个文件夹scripts,专门用于存放python节点
可以在功能包/src下创建一个cpp节点
/*创建一个小海龟的速度发布者*/
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "turtle_velocity_publisher");//ROS节点初始化
ros::NodeHandle n;//这里是创建句柄
//创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10
ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>
("/turtle1/cmd_vel", 10);
ros::Rate loop_rate(10);//设置循环的频率
while (ros::ok())
{
//初始化需要发布的消息,类型需与Publisher一致
geometry_msgs::Twist turtle_vel_msg;
turtle_vel_msg.linear.x = 0.8;
turtle_vel_msg.angular.z = 0.6;
turtle_vel_pub.publish(turtle_vel_msg);// 发布速度消息
//打印发布的速度内容
ROS_INFO("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]",
turtle_vel_msg.linear.x, turtle_vel_msg.angular.z);
loop_rate.sleep();//按照循环频率延时
}
return 0;
}
创建上面节点后,然后在功能包下的CMakelist.txt中添加如下
add_executable(节点名 src/节点名.cpp)
target_link_libraries(节点名 ${catkin_LIBRARIES})
然后回到工作空间下,注意是在工作空间下执行,执行
catkin_makec
创建一个节点,并在一个节点里订阅一个话题
/*创建一个小海龟的当前位姿信息接收*/
#include <ros/ros.h>
#include "turtlesim/Pose.h"
// 接收消息后,会进入消息回调函数,回调函数里边会对接收到的数据进行处理
void turtle_poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
// 打印接收到的消息
ROS_INFO("Turtle pose: x:%0.3f, y:%0.3f", msg->x, msg->y);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "turtle_pose_subscriber");// 初始化ROS节点
ros::NodeHandle n;//这里是创建句柄
// 创建一个订阅者,订阅的话题是/turtle1/pose的topic,poseCallback是回调函数
ros::Subscriber pose_sub = n.subscribe("/turtle1/pose", 10,turtle_poseCallback);
ros::spin(); // 循环等待回调函数
return 0;
}
在CMakelist.txt中配置
add_executable(节点名 src/节点名.cpp)
target_link_libraries(节点名 ${catkin_LIBRARIES})
工作空间下执行
catkin_make
下面用python实现一个订阅的节点
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from turtlesim.msg import Pose
def poseCallback(msg):
rospy.loginfo("Turtle pose: x:%0.3f, y:%0.3f", msg.x, msg.y)
def turtle_pose_subscriber():
rospy.init_node('turtle_pose_subscriber', anonymous=True)# ROS节点初始化
# 创建一个Subscriber,订阅名为/turtle1/pose的topic,注册回调函数poseCallback
rospy.Subscriber("/turtle1/pose", Pose, poseCallback)
rospy.spin()# 循环等待回调函数
if __name__ == '__main__':
turtle_pose_subscriber()
注意:
python程序不需要编译,但是需要添加可执行的权限,终端输入,
cd ~/ros_ws/src/功能包名/scripts
sudo chmod a+x 节点名.py
运行一个节点
rosrun 包名 可执行程序名
备注:可执行程序如果是python就直接是python文件名称,不需要再多的配置,如果是c++程序,就是CMakeLists.txt配置的那个
ros1自定义一个消息
功能包下新建一个文件夹msg
切换至msg目录下,新建一个空白的msg文件,以msg为后缀表示代表是msg文件。这里我们以Information.msg为例子说明下,把以下代码复制到刚刚创建好的msg文件里边
string company
string city
在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
在CMakeLists.txt添加编译选项 (注意下面三行里第一行别遗漏了)
搜find_package ,然后里边加上message_generation add_message_files(FILES Information.msg) generate_messages(DEPENDENCIES std_msgs)
最后 工作空间下执行 catkin_make
下面分别创建一个发布和订阅节点
发布节点 : Information_publisher.cpp
/**
* 该例程将发布/company_info话题,消息类型是自定义的learn_topic::Information
*/
#include <ros/ros.h>
#include "learn_topic/Information.h"
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc, argv, "company_Information_publisher");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个Publisher,发布名为/company_info的topic,消息类型为learn_topic::Person,队列长度10
ros::Publisher Information_pub = n.advertise<learn_topic::Information>("/company_info", 10);
// 设置循环的频率
ros::Rate loop_rate(1);
int count = 0;
while (ros::ok())
{
// 初始化learn_topic::Information类型的消息
learn_topic::Information info_msg;
info_msg.company = "Yahboom";
info_msg.city = "Shenzhen";
// 发布消息
Information_pub.publish(info_msg);
ROS_INFO("Information: company:%s city:%s ",info_msg.company.c_str(), info_msg.city.c_str());
loop_rate.sleep();// 按照循环频率延时
}
return 0;
}
订阅节点 : Information_subscriber.cpp
/**
* 该例程将订阅/company_info话题,自定义消息类型learn_topic::Information
*/
#include <ros/ros.h>
#include "learn_topic/Information.h"
// 接收到订阅的消息后,会进入消息回调函数处理数据
void CompanyInfoCallback(const learn_topic::Information::ConstPtr& msg)
{
// 打印接收到的消息
ROS_INFO("This is: %s in %s", msg->company.c_str(), msg->city.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "company_Information_subscriber");// 初始化ROS节点
ros::NodeHandle n;// 这里是创建节点句柄
// 创建一个Subscriber,订阅名话题/company_info的topic,注册回调函数CompanyInfoCallback
ros::Subscriber person_info_sub = n.subscribe("/company_info", 10,CompanyInfoCallback);
ros::spin();// 循环等待回调函数
return 0;
}
修改CMakeLists.txt文件,添加以下内容,
add_executable(Information_publisher src/Information_publisher.cpp)
target_link_libraries(Information_publisher ${catkin_LIBRARIES})
add_dependencies(Information_publisher ${PROJECT_NAME}_generate_messages_cpp)
add_executable(Information_subscriber src/Information_subscriber.cpp)
target_link_libraries(Information_subscriber ${catkin_LIBRARIES})
add_dependencies(Information_subscriber ${PROJECT_NAME}_generate_messages_cpp)
python如何使用自定义消息的,同样是一个发送者和接收者
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from learn_topic.msg import Information #导入自定义的msg
def information_publisher():
rospy.init_node('information_publisher', anonymous=True)# ROS节点初始化
# 创建一个Publisher,发布名为/company_info的topic,消息类型为learn_topic::Information,队列长度6
info_pub = rospy.Publisher('/company_info', Information, queue_size=6)
rate = rospy.Rate(10) #设置循环的频率
while not rospy.is_shutdown():
# 初始化learn_topic::Information 类型的消息
info_msg = Information()
info_msg.company = "Yahboom";
info_msg.city = "Shenzhen";
info_pub.publish(info_msg)# 发布消息
rospy.loginfo("This is %s in %s.", info_msg.company, info_msg.city)# 打印发布消息
rate.sleep()# 按照循环频率延时
if __name__ == '__main__':
try:
information_publisher()
except rospy.ROSInterruptException:
pass
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from learning_topic.msg import Information #导入自定义的msg
def CompanyInfoCallback(msg):
rospy.loginfo("company: name:%s city:%s ", msg.company, msg.city)#打印订阅接收到信息
def Infomation_subscriber():
rospy.init_node('Infomation_subscriber', anonymous=True)# ROS节点初始化
# 创建一个Subscriber,订阅名为/company_info的topic,注册回调函数personInfoCallback
rospy.Subscriber("/company_info", Information, CompanyInfoCallback)
rospy.spin()# 循环等待回调函数
if __name__ == '__main__':
Infomation_subscriber()
两个文件保存后,需要给定执行权限,
cd ~/ros_ws/src/learn_topic/scripts
sudo chmod a+x Information_publisher.py
sudo chmod a+x Information_subscriber.py
备注:
from learn_topic.msg import Information
learn_topic表示功能包、msg表示功能包下的msg文件夹,Infomation表示自定义msg文件的名字
Launch相关
在功能包下创建一个文件夹 叫launch
mkdir launch
再回到工作空间目录下进行编译,
cd ~/ros_ws
catkin_make
然后在launch文件夹下,新建一个文件,文件名是turtle_node.launch,把以下内容负责到里边
备注:
pkg : 包名
type : 运行节点的可执行程序的名字 ,这个是add_executable 第一个参数定义得名字
name:节点的名字,不一定要与程序中定义节点名字一样,可以任意命名,这个名字就是通过 rostopic list 看到的名字
<launch>
<node pkg="turtlesim" type="turtlesim_node" name="turtle"/>
</launch>
roslaunch learn_launch turtle_node.launch
同时launch文件还可以加载运行launch文件
launch文件中,不仅可以运行节点,还可以加载运行launch文件,也就是嵌套使用,这里需要用到的标签是。常用的格式为,
<include file=”$(find package_name)/launch/launch_file_name”/>
package_name:表示launch文件所在的功能包
launch_file_name:表示需要运行的launch文件的文件名字
<launch>
<include file="$(find 包名)/launch/launch名.launch"/>
<node pkg="learn_topic" type="turtle_pose_subscriber" name="turtle_pose"
output="screen"/>
</launch>
这里在node这里启动的时候加入了一个参数output,因为我们是想要在终端打印这个信息的,所以是输出到屏幕screen
还有两个值分别是log
输出到日志,none
无输出
launch文件加载参数
在launch文件中,有两个变量是表示参数的,分别是arg和param,它们的含义如下:
- name:参数的名称
- default:参数的默认值
-
<launch> <arg name="r_value" default="100"/> <arg name="g_value" default="0"/> <arg name="b_value" default="100"/> <node pkg="turtlesim" type="turtlesim_node" name="turtle"> <param name="/background_r" value="$(arg r_value)"/> <param name="/background_g" value="$(arg g_value)"/> <param name="/background_b" value="$(arg b_value)"/> </node> </launch>
我们还可以在启动的时候,在命令行修改rgb的值,只要带上参数即可,例如,终端输入,
-
roslaunch 包名 launch名.launch b_value:=2
可以看出,我们在启动命令的时候,把b_value的值修改成2,然后传入进去。这里的参数是怎么传递的呢?在node标签里边,我们设置了三个参数,分别是/background_r、/background_g和/background_b,它们value的值,分别是$(arg r_value)、$(arg g_value)和$(arg b_value);再看看r_value、g_value和b_value的默认值,分别是上边arg标签里边的100、0和100,这就很明了了:我们在arg里定义的值,然后在arg里定义的值传给param里的value。在引用的时候加上$(arg g_value)即可,当然,你也可以不用,也就是写成把那么这样,这个/background_g的参数值就是固定的255了。
话题名称映射
在实际的开发过程中,原本预设定话题的名字往往需要根据其他节点的话题名字进行修改,源码修改比较麻烦,C++版本的代码修改完还需要编译,比较麻烦,但在launch文件中,用标签即可实现重映射话题名字,把预设定的话题的名字映射成其它的,用法如下,
<remap from="original_topic" to="remapped_topic" />
成功运行后,输入rostopic list看看,终端输入, 发现话题得名称已经换成了映射后得名字
<launch>
<node pkg="turtlesim" type="turtlesim_node" name="turtle">
<remap from="/turtle1/cmd_vel" to="/ctrl_vel"/>
</node>
</launch>
这时候,原来的/turtle1/cmd_vel没有了,映射成/ctrl_vel了,这是因为我们在launch文件,重新映 射了话题,
launch文件中使用条件语句
我们在launch文件中,可以加上条件判断来决定是否要启动节点程序,条件判断在launch文件中由if
和unless
来控制,具体的用法举例说明,在launch文件夹新建一个文件命名为condition_ctrl_turtle.launch,程序运行后,根据实际的参数,进行判断是否启动某节点
<launch>
<arg name="ctrl_node" default="true"/>
<node pkg="turtlesim" type="turtlesim_node" name="turtle"/>
<node pkg="turtlesim" type="turtle_teleop_key" name="turtle_ctrl" if="$(eval arg('ctrl_node') == true)"/>
</launch>
roslaunch learn_launch condition_ctrl_turtle.launch ctrl_node:=false
运行时候通过语句末尾添加一些参数,决定
launch文件中有个组的概念,标签是,它可以将指定的节点nodes组织起来,将几个nodes放进同一个namespace中。namespace是命名空间,作用是避免名称冲突,ros系统中不允许出现相同的节点名字。比如说,我们想要在在一个终端打开两个小海龟的节点,如果没有命名空间,直接启动的话,是会产生冲突导致程序退出的,因此,我们需要在launch文件中,加上命令空间namespace,相当于在相同节点前再添加一个标识来区分两个节点
我们在group中加上了ns,即可为所有节点名前添加命名空间
<launch>
<group ns="robot1">
<node pkg="turtlesim" type="turtlesim_node" name="turtle"/>
</group>
<group ns="robot2">
<node pkg="turtlesim" type="turtlesim_node" name="turtle"/>
</group>
</launch>
rosnode list