ROS之命令与编程实践
参考资料
- 古月居ROS21讲
- ROSwiki
ROS命令行概述
-
roscore启动命令
-
rosrun
rosrun [package_name] [node_name] #允许你使用包名直接运行一个包内的节点(而不需要知道这个包的路径)。
-
rosls
rosls是rosbash命令集中的一部分,它允许你直接按软件包的名称而不是绝对路径执行ls命令(罗列目录).
rosls beginner_tutorials/
CMakeLists.txt include package.xml src -
roscd log
使用roscd log可以切换到ROS保存日记文件的目录下。需要注意的是,如果你没有执行过任何ROS程序,系统会报错说该目录不存在。
-
rosed
rosed 是 rosbash 的一部分。利用它可以直接通过package名来获取到待编辑的文件而无需指定该文件的存储路径了。
rosed [package_name] [filename]
这个实例展示了如何编辑roscpp package里的Logger.msg文件。
-
rospack命令
rospack允许你获取软件包的有关信息
rospack find roscpp
/opt/ros/kinetic/share/roscpp
rospack list #显示出当前的包信息
rospack depends1 beginner_tutorials #显示当前包的一级依赖
rospack depends beginner_tutorials #显示当前包的所有依赖 -
rqt
rqt_graph #显示计算图
-
rosnode
rosnode ping 节点名 #测试节点的联通情况
rosnode list #显示全部节点
rosnode info 节点名 #显示节点信息
rosnode machine #显示当前机器
rosnode kill 节点名 #结束一个正在运行的node
rosnode cleanup #清除无法访问的节点的注册信息 -
rostopic
rostopic bw #显示主题使用的带宽
rostopic delay #从标题中的时间戳显示主题的延迟
rostopic echo #将消息打印到屏幕,可以显 示在某个话题上发布的数据.
rostopic find #按类型查找主题
rostopic hz #显示主题的发布率
rostopic info #打印有关活动主题的信息
rostopic list #列出活动主题
-h, --help #(显示此帮助消息并退出)
-b BAGFILE, --bag=BAGFILE #(列出.bag文件中的主题)
-v, --verbose #(列出每个主题的完整详细信息)
-p #(仅列出发布商)
-s #(仅列出订阅者)
--host #(按主机名分组)
rostopic pub #将数据发布到主题
rostopic type #打印主题或字段类型,命令用来查看所发布话题的消息类型。 -
rostopic pub
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
发送一条消息给turtlesim,告诉它以2.0大小的线速度和1.8大小的角速度开始移动。
这条命令以1Hz的频率发布速度命令到速度话题上。
rostopic pub -r 10 /turtle1/cmd_vel geometry_msgs/Twist"linear:
x:1.0
y:0.0
z:0.0
angular:
x:0.0
y:0.0
z:0.0"
/turtle1/cmd_vel话题名
geometry_msgs/Twist消息结构
-r 表示循环 -
rostopic hz
rostopic hz /turtle1/pose
subscribed to [/turtle1/pose]
average rate: 62.486
min: 0.015s max: 0.017s std dev: 0.00047s window: 60
average rate: 62.476
min: 0.015s max: 0.018s std dev: 0.00045s window: 122
average rate: 62.514
min: 0.014s max: 0.020s std dev: 0.00057s window: 185
average rate: 62.506
min: 0.013s max: 0.020s std dev: 0.00061s window: 248 -
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 -
rosbag
将ROS系统运行过程中的数据录制到一个.bag文件中,然后可以通过回放数据来重现相似的运行过程.退出录制时按Ctrl-C退出该命令,你应该会看到在当前目录下一个以年份、日期和时间命名并以.bag作为后缀的文件。
录制所有发布的话题,其中 -a 选项,该选项表示将当前发布的所有话题数据都录制保存到一个bag文件中。
rosbag record -a
回放bag文件以再现系统运行过程
rosbag play <your bagfile>
以某一频率发布消息(控制bag包播放的频率) : rosbag play -r 2
从某一时间节点开始播放发布消息 : rosbag play -s 2
rosbag info <your bagfile> #rosbag info 查看bag文件信息
rosbag record -O 2018-12.bag /turtle1/command_velocity /turtle1/pose
rosbag record命令支持只录制某些特别指定的话题到单个bag文件中,这样就允许用户只录制他们感兴趣的话题
rosbag record -a -O 2018-12.bag
可以使用rosbag info 2018-12.bag 命令查看录制时指定话题的信息.
也可以只指定bag包的文件名,录制所有数据
rosbag record --split --duration=5m -e /radar/back_targets /vehicle_speed /imu_data
录取指定topic,并且每五分钟分割一次, -e为正则匹配。
rosrun image_view image_view image:=/camera/front_middle compressed
如果查看视频,就可以实现视频播放功能
创建工作空间和功能包
工程文件 workspace
四个文件夹:
- src代码空间
- build编译空间
- devel开发空间
- install安装空间
创建工作空间 |
发布者publisher编程实现
创建功能包 |
代码放到src目录
创建一个.cpp文件即可,注意文件名不能重复!!
/** |
接下来需要编译运行,需要配置CMakeLists.txt中的编译规则
cmake_minimum_required(VERSION 3.0.2) |
接下来就可以编译,在你的工作空间的src下
catkin_make |
设置环境变量
source devel/setup.bash |
也可以在主文件夹下
cd / |
接下来就可以执行
roscore |
也可用python来完成,首行注意添加 #!/usr/bin/env python
#!/usr/bin/env python |
订阅者subscriber的编程实现
项目工程文件夹下src中创建代码
//pose_subscriber.CPP |
编译执行过程同发布者 |
#!/usr/bin/env python |
话题消息定义与使用
如何自定义一个话题的消息
-
定义msg文件
在项目文件夹下创建一个msg文件夹,专门存放.msg文件,不能随便命名
string name
uint8 sex
uint8 age
uint8 unknown = 0
uint8 male = 1
uint8 female =2 -
在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend> -
在CMakeList.txt添加编译选项
# Find catkin macros and libraries
# if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
# is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
geometry_msgs
roscpp
rospy
std_msgs
turtlesim
message_generation #添加功能包
)
# Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
geometry_msgs# std_msgs
)
add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)
##################################
# catkin specific configuration ##
##################################
# The catkin_package macro generates cmake config files for your package
# Declare things to be passed to dependent projects
# INCLUDE_DIRS: uncomment this if your package contains header files
# LIBRARIES: libraries you create in this project that dependent projects also need
# CATKIN_DEPENDS: catkin_packages dependent projects also need
# DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
INCLUDE_DIRS include
LIBRARIES learning_topic
CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime #添加此处
DEPENDS system_lib
) -
最后直接编译catkin_make编译即可
客户端Client的编程实现
-
创建一个新的功能包文件夹
cd ~/catkin_ws/src
catkin_create_pkg learnin_service roscpp rospy std_msgs geometry_msgs turtlesim -
在learnin_service的src下创建cpp代码
/**
*该程序将请求/spawn服务,服务数据类型turtlesim::Spawn
*/
int main(int argc,char **argv)
{
//初始化ROS节点
ros::init(argc,argv,"turtle_spawn");
//创建节点句柄
ros::NodeHandle node;
//发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
ros::service::waitForService("/spawn"); //循环等待
ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
//初始化turtlesim::Spawn的请求数据
turtlesim::Spawn srv;
srv.request.x = 2.0;
srv.request.y = 2.0;
srv.request.name = "turtle2";
//请求服务调用
ROS_INFO("Call service to spwan turtle[x:%0.6f,y:%0.6f,name:%s]",srv.request.x,srv.request.y,srv.request.name.c_str());
add_turtle.call(srv);
//显示服务调用结果
ROS_INFO("Spwan turtle successfully [name:%s]",srv.response.name.c_str());
return 0;
}配置编译规则CMakeList.txt
add_executable(turtle_spawn src/turtle_spawn.cpp) //设置需要编译的代码和生成的可执行文件;
target_link_libraries(turtle_spawn ${catkin_LIBRARIES}) //设置链接库;回到根目录/catkin_ws编译并运行客户端
编译成功后在devel/lib下产生功能包
服务端Server的编程实现
在src下turtle_command_server.cpp
/** |
配置CMakeLists
add_executable(turtle_command_server src/turtle_command_server.cpp) |
编译运行服务器
cd ~/catkin_ws |
自定义服务数据
-
定义srv文件
string name
uint8 age
uint8 sex
uint8 unknown = 0
uint8 male = 1
uint8 female = 2
--- //之上表示request,之下表示respons
string result -
在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend> -
在CMakeLists.txt提娜佳编译选项
find_package( …… message_generation)
add_service_files(FILES Person.srv)
generate_messages(DEPENDENCIES std_msgs)
catkin_package(…… message_runtime) -
编译生成语言相关文件
-
服务端实现
/**
* 该例程将请求/show_person服务,服务数据类型learning_service::Person
*/
// service回调函数,输入参数req,输出参数res
bool personCallback(learning_service::Person::Request &req,
learning_service::Person::Response &res)
{
// 显示请求数据
ROS_INFO("Person: name:%s age:%d sex:%d", req.name.c_str(), req.age, req.sex);
// 设置反馈数据
res.result = "OK";
return true;
}
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc, argv, "person_server");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个名为show_person的erver,注册回调函数ersonCallback
ros::ServiceServer person_service = n.advertiseService("/show_person", personCallback);
// 循环等待回调函数
ROS_INFO("Ready to show person informtion.");
ros::spin();
return 0;
} -
客户端实现
/**
* 该例程将请求/show_person服务,服务数据类型learning_service::Person
*/
int main(int argc, char** argv)
{
// 初始化ROS节点
ros::init(argc, argv, "person_client");
// 创建节点句柄
ros::NodeHandle node;
// 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
ros::service::waitForService("/show_person");
ros::ServiceClient person_client = node.serviceClient<learning_service::Person>("/show_person");
// 初始化learning_service::Person的请求数据
learning_service::Person srv;
srv.request.name = "Tom";
srv.request.age = 20;
srv.request.sex = learning_service::Person::Request::male;
// 请求服务调用
ROS_INFO("Call service to show person[name:%s, age:%d, sex:%d]",
srv.request.name.c_str(), srv.request.age, srv.request.sex);
person_client.call(srv);
// 显示服务调用结果
ROS_INFO("Show person result : %s", srv.response.result.c_str());
return 0;
};配置编译规则
add_executable(person_server src/person_server.cpp)
target_link_libraries(person_server ${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_gencpp)
add_executable(person_client src/person_client.cpp)
target_link_libraries(person_client ${catkin_LIBRARIES})
add_dependencies(person_client ${PROJECT_NAME}_gencpp) -
运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun learning_service person_server
rosrun learning_service person_client
参数的使用与编程方法
-
创建功能包
cd ~/catkin_ws/src
catkin_create_pkg learning_parameter roscpp rospy std_srvs -
参数命令行使用
rosparam list #列出当前多有参数
rosparam get param_key #显示某个参数值
rosparam set param_key param_value #设置某个参数值
rosparam dump file_name #保存参数到文件
rosparam load file_name #从文件读取参数
rosparam delete param_key #删除参数 -
创建parameter_conflg.cpp
/**
* 该例程设置/读取海龟例程中的参数
*/
int main(int argc, char **argv)
{
int red, green, blue;
// ROS节点初始化
ros::init(argc, argv, "parameter_config");
// 创建节点句柄
ros::NodeHandle node;
// 读取背景颜色参数
ros::param::get("/background_r", red);
ros::param::get("/background_g", green);
ros::param::get("/background_b", blue);
ROS_INFO("Get Backgroud Color[%d, %d, %d]", red, green, blue);
// 设置背景颜色参数
ros::param::set("/background_r", 255);
ros::param::set("/background_g", 255);
ros::param::set("/background_b", 255);
ROS_INFO("Set Backgroud Color[255, 255, 255]");
// 读取背景颜色参数
ros::param::get("/background_r", red);
ros::param::get("/background_g", green);
ros::param::get("/background_b", blue);
ROS_INFO("Re-get Backgroud Color[%d, %d, %d]", red, green, blue);
// 调用服务,刷新背景颜色
ros::service::waitForService("/clear");
ros::ServiceClient clear_background = node.serviceClient<std_srvs::Empty>("/clear");
std_srvs::Empty srv;
clear_background.call(srv);
sleep(1);
return 0;
} -
配置CMakeLists参数
add_executable(parameter_config src/parameter_config.cpp)
target_link_libraries(parameter_config ${catkin_LIBRARIES}) -
编译运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun turtlesim turtlesim_node
rosrun learning_parameter parameter_config
ROS中的坐标系管理系统
-
机器人中的坐标变换
TF功能包
sudo apt-get install ros-melodic-turtle-tf
roslaunch,启动脚本文件
roslaunch turtle_tf turtle_tf_demo.launch
rosrun turtlesim turtle_teleop_key
各种工具
rosrun tf view_frames
rosrun tf tf_echo turtle1 turtle2
rosrun rviz rviz -d `rospack find turtle_tf`/rviz/turtle_rviz.rviz
TF坐标系广播监听的编程管理
-
创建功能包
cd ~/catkin_ws/src
catkin_create_pkg learning_tf roscpp rospy tf turtlesim -
广播器broadcaster.cpp
/**
* 该例程产生tf数据,并计算、发布turtle2的速度指令
*/
std::string turtle_name;
void poseCallback(const turtlesim::PoseConstPtr& msg)
{
// 创建tf的广播器
static tf::TransformBroadcaster br;
// 初始化tf数据
tf::Transform transform;
transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) );
tf::Quaternion q;
q.setRPY(0, 0, msg->theta);
transform.setRotation(q);
// 广播world与海龟坐标系之间的tf数据
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
}
int main(int argc, char** argv)
{
// 初始化ROS节点
ros::init(argc, argv, "my_tf_broadcaster");
// 输入参数作为海龟的名字
if (argc != 2)
{
ROS_ERROR("need turtle name as argument");
return -1;
}
turtle_name = argv[1];
// 订阅海龟的位姿话题
ros::NodeHandle node;
ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);
// 循环等待回调函数
ros::spin();
return 0;
}; -
监听器
/**
* 该例程监听tf数据,并计算、发布turtle2的速度指令
*/
int main(int argc, char** argv)
{
// 初始化ROS节点
ros::init(argc, argv, "my_tf_listener");
// 创建节点句柄
ros::NodeHandle node;
// 请求产生turtle2
ros::service::waitForService("/spawn");
ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
turtlesim::Spawn srv;
add_turtle.call(srv);
// 创建发布turtle2速度控制指令的发布者
ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel", 10);
// 创建tf的监听器
tf::TransformListener listener;
ros::Rate rate(10.0);
while (node.ok())
{
// 获取turtle1与turtle2坐标系之间的tf数据
tf::StampedTransform transform;
try
{
listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0));
listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);
}
catch (tf::TransformException &ex)
{
ROS_ERROR("%s",ex.what());
ros::Duration(1.0).sleep();
continue;
}
// 根据turtle1与turtle2坐标系之间的位置关系,发布turtle2的速度控制指令
geometry_msgs::Twist vel_msg;
vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),
transform.getOrigin().x());
vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +
pow(transform.getOrigin().y(), 2));
turtle_vel.publish(vel_msg);
rate.sleep();
}
return 0;
}; -
编译配置
add_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp)
target_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})
add_executable(turtle_tf_listener src/turtle_tf_listener.cpp)
target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES}) -
编译运行
cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun turtlesim turtlesim_node
重命名,避免冲突
rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2
rosrun learning_tf turtle_tf_listener
rosrun turtlesim turtle_teleop_key
launch启动文件的使用方法
-
Launch文件:通过XML文件实现多节点的配置和启动(可自动启动ROS Master)
-
node启动节点 :
pkg:节点所在的功能包名称
type:节点的可执行文件名称
name:节点运行时的名称
output 、respawn 、required 、ns 、args
<node pkg="package-name" type="executable-name" name="node-name" />
-
参数设置
实例
常用可视化工具
-
rqt
rqt
-
Rviz
rosrun rviz
-
Gazebo