ROS学习——初级阶段

ROS是什么

作用:提高机器人研发中心的软件服用率。

  1. 通信机制:松耦合分布式通信
  2. 开发工具:TF坐标变换、QT工具箱、RVIZ、Gazebo。
  3. 应用功能:Navigation、SLAM。
  4. 生态系统:
    ROS社区资源的组织形式
    在这里插入图片描述

通信机制

节点与节点管理器
  1. 节点(Node) -------执行单元
    1)执行具体任务的进程、独立运行的可执行文件;
    2)不同节点可使用不同的编程语言,可分布式运行在不同的主机;
    3)节点在系统中的名称必须是唯一的。

  2. 节点管理器(ROS Master)------控制中心
    1)为节点提供命名和注册服务。
    2)跟踪和记录话题/服务通信,辅助节点相互查找、建立连接。
    3)提供参数服务器,节点使用此服务器存储和检索运行时的参数。

通信方法

话题通信(适用于:数据传输)
  1. 话题(Topic)-----异步通信机制
  1. 节点间用来传输数据的重要总线。
  2. 使用发布/订阅模型,数据由发布者传输至订阅者,同一个话题的订阅者或发布者可以不唯一
  1. 消息(Message) -----话题数据
    1)具有一定的类型和数据结构,包括ROS提供的标准类型和用户自定义类型;
    2)使用编程语言无关的.msg文件定义,编译过程中生成对应的代码文件。
服务通信(适用于:逻辑处理)
  1. 服务(Service)--------同步通信机制
    1)使用客户端/服务器模型,客户端发送请求数据,服务器完成处理后返回应答数据;
    2)使用编程语言无关的.srv文件定义请求和应答数据结构,编译过程中生成对应的代码文件。

ROS命令行工具

  1. 常用命令
    rostopic rosservice rosnode rosparam rosmsg rossrv rosrun
    rosrun:第一个参数为功能包名,第二个参数为具体节点名。如:rosrun turtlesim turtlesim_node
    话题记录rosbag record -a -O cmd_record.bag(保存运行时的数据)
    话题复现rosbag play cmd_record.bag
参数
  • 参数(Parameter)-----全局共享字典
    1)可通过网络访问的共享、多变量字典。
    2)节点使用此服务器来存储和检索运行时的参数。
    3)适合存储静态、非二进制的配置参数,不适合存储动态配置的数据。

创建工作空间

工作空间相关的文件夹

  • src:代码空间(Source Space)
  • build:编译空间(Build Space)
  • devel:开发空间(Development Space)
  • install:安装空间(Install Space)

建立工作空间

  • 在新建的工作空间下的src目录下:catkin_init_workspace
  • 在工作空间下:catkin_make
  • 设置环境变量:source devel/setup.bash
  • 检查环境变量:echo $ROS_PACKAGE_PATH
  • 产生install文件夹:catkin_make install

创建功能包

同一个工作空间下,不予许存在同名功能包,不同工作空间下,允许存在同名功能包。
创建功能包:cd ~/catkin_ws/src catkin_create_pkg test_pkg std_msgs rospy roscpp
编译功能包:cd ~/catkin_ws catkin_make source ~/catkin_ws/devel/setup.bash

ROS中Topic相关组成元素的实现

如何实现一个发布者:

  • 初始化ROS节点;
  • 向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型;(初始化)
  • 创建消息数据;(填充)
  • 按照一定频率循环发布消息。(发布)
// 创建一个订阅者,包括msg结构体以及Topic名字
ros::Publisher pubfun_name = nodehandle.advertise<msg_name::msg>("/Topic_name", queue_number);
// ROS c++ 循环发布,发布数据
ros::Rate loop_rate(10);
loop_rate.sleep();

pubfun_name.publish(msg_name::msg);

如何实现一个订阅者:

  • 初始化ROS节点;
  • 订阅需要的话题;
  • 循环等待话题消息,接收到消息后进入回调函数;
// 创建一个订阅者
ros::Subscriber subfun_name = nodehandle.subscribe("/Topic_name", queue_number, Callbackfun());
// 一直死锁在这个死循环,等待消息到来,有消息就调用回调函数
ros::spin();
  • 回调函数中完成消息处理。

配置CMakeLists.txt中的编译规则

  • 设置需要编译的代码和生成的可执行文件;
  • 设置连接库;
add_executable(node_name src/node_name.cpp)
target_link_libraries(node_name ${catkin_LIBRARIES})

设置脚本文件

每次打开中端重新设置:source devel/setup.bash
或一次性设置:在主文件夹.bashrc隐藏文件下添加source /home/ly/catkin_ws/devel/setup.bash
移植ROS系统时也会把.bash文件加入到这个文件夹下:

source /opt/ros/melodic/setup.bash

自定义话题消息

定义msg文件:msg_name.msg
在package.xml中添加功能包依赖:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
在CMakeLists.txt添加编译选项:
  • find_package(… message_generation)
  • add_message_file(FILES msg_name.msg)
    generate_messages(DEPENDENCIES std_msgs)
  • catkin_package(… message_runtime)
    最后会在devel/include/topic_name目录下生成一个msg_name.h的头文件

编译自定义消息的Publisher和Subscriber

  • 设置需要编译的代码和生成的可执行文件;
  • 设置连接库;
  • 添加依赖项。(与生成的头文件相联系)
add_executable(publisher_name src/publisher_name.cpp)
target_link_libraries(publisher_name ${catkin_LIBRARIES})
add_dependencies(publisher ${PROJECT_NAME}_generate_messages_cpp)

ROS中Service相关组成元素的实现

实现一个客户端

  • 初始化ROS节点;
  • 创建一个Client实例;
  • 发布服务请求数据;
  • 等待Server处理之后的应答结果。
// 创建一个Client
ros::service::waitForService("/service_name")    //阻塞型API,循环等待服务数据,这里的name是spawn
ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/service_name"); //创建一个Client

//填充service数据
turtlesim::Spawn srv;

//请求服务调用
add_turtle.call(srv);  //发送填充好的数据,等待server端的responce到来

实现一个服务端

  • 初始化ROS节点;
  • 创建一个Server实例,注册回调函数;
  • 循环等待回调函数;
  • 在回调函数中进行相关处理。
//创建一个名为/turtle_command的server,注册回调函数commandCallback
ros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback);
// 回调函数中填充responce的内容
// 循环等待回调函数
ros::spin();
bool commandCallback(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)    
{}  //填充responce
// 循环等待回调函数
while(1)
{
	ros::spinOnce();
}

客户端发布Call指令

rosservice call /turtle_command "{}"  //turtle_command是发送的service的名字

服务数据的定义和使用

定义srv文件:srv_name.srv

文件中---之前的是request数据,之后是response数据。

在package.xml中添加功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
在CMakeLists.txt添加编译选项
  • find_package(… message_generation)
  • add_service_files(FILES srv_name.srv)
    generate_messages(DEPENDENCIES std_msgs)
  • catkin_package(… message_runtime)
编译生成相应的头文件catkin_make

使用自己定义的srv配置编译规则

  • 设置需要编译的代码和生成的可执行文件;
  • 设置链接库;
  • 添加依赖项。
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)

机器人中的坐标变换

*参考:《机器人学导论》

TF功能包的作用

  • 五秒钟之前,机器人头部坐标系相对于全局坐标系关系是什么样的
  • 机器人夹取的物体相对于机器人中心坐标系的位置在哪里
  • 机器人中心坐标系相对于全局坐标系的位置在哪里

TF坐标变换实现

  • 广播TF变换
  • 监听TF变换

TF坐标变换实例

实现两只小海龟跟随
  • 安装TF功能包:sudo apt-get install ros-melodic-turtle-tf
  • 启动launch文件:roslaunch turtle_tf turtle_tf_demo.launch
  • 启动小海龟运动键盘:rosrun turtlesim turtle_teleop_key
  • 启动坐标树界面,可以看到坐标树之间的关系:rosrun tf view_frames
TF变换相关的命令行工具
  • 查看所有的坐标树:rosrun tf view_frames
  • 查看某两个坐标树之间的关系:rosrun tf tf_echo turtle1 turtle2
实现一个TF广播器
  • 定义TF广播器;
  • 创建坐标变换值;
  • 发布坐标变换。
//创建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)); // "world"坐标系与海龟之间的坐标关系

实现一个TF监听器
  • 定义TF监听器;
  • 查找坐标变换;
// 创建tf的监听器
tf::TransformListener listener;

//获取turtle1与turtle2坐标系之间的tf数据
tf::stampedTransform transform;
listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0)); //Duration为查询等待时间,超时就会出错
listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform); //transform为保存tf坐标之间的关系,包括平移和旋转

//发布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);

重映射机制

同一个话题拥有两个同名的节点名字

rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2

launch文件的使用

可自动启动ROS Master

<launch>
	<node pkg="turtlesim" name="sim1" type="turtlesim_node"/>
	<node pkg="turtlesim" name="sim2" type="turtlesim_node"/> 
</launch>

创建launch功能包

// launch文件需要依赖其他的文件,所以不需要添加依赖的库
catkin_creat_pkg learning_launch

launch

launch文件中的根元素采用标签定义

node

启动节点

  • pkg:节点所在的功能包名称
  • type:节点的可执行文件名称
  • name:节点运行时的名称
  • output、respawn、required、ns、args
    name可以取代初始化时的节点名

param/rosparam

设置ROS系统运行中的参数,存储在参数服务器中。

<param name="output_frame" value="odom"/>
  • name:参数名
  • value:参数值
    加载参数文件中的多个参数
<rosparam file="params.yaml" command="load" ns="params" />

arg

launch文件内部的局部变量,仅限于launch文件使用

  • name:参数名
  • value:参数值

调用:

<param name="foo" value="$(arg arg-name)" />
<node name="node" pkg="package" type="type" args="$(arg arg-name)" />
<node name="node" pkg="package" type="type" args="$(arg arg-name)" />

remap

重映射ROS计算图资源的命名,修改Topic名字

<remape from="/turtlebot/cmd_vel" to="/cmd_vel"/>
  • from:原名字
  • to:映射之后的命名

include

包含其他launch文件,类似C语言中的头文件包含。

<include file="$(dirname)/other.launch" />
  • file:包含的其他launch文件路径

使用launch文件

roslaunch learning_launch simple.launch

launch文件实例

// 启动海龟仿真器,启动键盘节点,设置参数到Master中,将键盘输出到频幕上
<launch>
	<param name="/turtle_number" value="2"/>
	<node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node">
		<param name="turtle_name1" value="Tom"/>
		<param name="turtle_name2" value="Jerry"/>
		<rosparam file="$(find learning_launch)/config/param.yaml" command="load">
	</node>
	<node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop_key" output="screen"/>
</launch>
// 创建两次broadcaster,使用args来进行区分,args也就是Topic名字
<launch>
	<node pkg="turtlesim" type="turtlesim_node" name="sim"/>
	<node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>
	<node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster"/>
	<node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster"/>
</launch>

可视化工具的使用

日志输出工具:rqt_console

  • 显示报错信息

计算图可视化工具:rqt_graph

数据绘图工具:rqt_plot

  • 订阅相关的数据并绘制曲线图,比如某个Topic话题/turtle1/pose

图像渲染工具:rqt_image_view

  • 显示摄像头图像信息

综合工具:rqt

  • 可以打开所有其他的工具

机器人开发过程中的数据可视化界面:Rviz

rosrun rviz rviz

三维物理仿真平台:Gazebo

  • 测试机器人算法
  • 机器人的设计
  • 现实情景下的回溯测试
roslaunch gazebo_ros willowgarage_world.launch
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值