# 一、ros_control
# 1.1概念
ROS提供了相当多的功能包,如:SLAM、导航、MoveIt等等,但是这些功能包的应用缺少了控制的中间件
ros_control就是应用和实际机器人或者机器人仿真器之间的中间件
ros_control就是ROS为用户提供的应用与机器人之间的中间件,包含一系列控制器接口、传动装置接口、硬件接口、控制器工具箱等等,可以帮助机器人应用快速落地,提高开发效率
# 1.1ros_control框架
ros_control框架针对不同类型的机器人(移动机器人、机械臂等等)提供了多种类型的控制器(controller),但是这些控制器的接口各不相同
ros_control框架还提供了一个硬件抽象层,负责机器人硬件资源的管理,而controller从抽象层请求资源即可,无需直接接触硬件
- 控制器管理器(Controller Manager)每一个机器人系统可能会有多个控制器,控制器管理器的作用就是提供一种通用的接口来管理不同的控制器,其输入就是ROS上层应用功能包的输出
- 控制器(Controller)控制器可以完成每个joint的控制,读取硬件资源接口中的状态,然后再发布控制命令并提供PID控制器
- 硬件资源(Hardware Resource)为上下两层提供硬件资源的接口
- 机器人硬件抽象(RobotHW)机器人硬件抽象和硬件资源直接交互,通过read和write方法完成对硬件的操作,这一层也包含了关节约束、例句转换、状态转换等功能
- 真实机器人(Real Robot)真实机器人上需要有自己的嵌入式控制器,将接收到的命令反映到执行器上
下面反映的就是一个完整的ros_control数据流图
# 1.2控制器
目前ROS中的ros_controllers功能包提供了以下控制器:
也可以根据自己的需求,创建需要的controller,然后通过控制器管理器(controller manager)来管理自己创建的controller
可参考https://github.com/ros-controls/ros_control/wiki/controller_interface
# 1.3硬件接口
硬件接口是控制器与机器人硬件抽象(RobotHW)沟通的接口,基本与控制器种类相互对应
同样可以自己创建需要的接口,可参考https://github.com/ros-controls/ros_control/wiki/hardware_interface
# 1.4传动系统
传动系统(Transmission)可以将机器人的关节指令转化为执行器的控制信号
注意:机器人的每一个需要运动的关节都需要配置相应的传动系统
其配置可以在机器人的URDF文件中按照以下方式进行:
<transmission name="simple_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="foo_joint">
<hardwareInterface>EffortJointInterface</hardwareInterface>
</joint>
<actuator name="foo_motor">
<mechanicalReduction>50</mechanicalReduction>
<hardwareInterface>EffortJointInterface</hardwareInterface>
</actuator>
</transmission>
# 1.5关节约束
关节约束(Joint Limits)是硬件抽象层中的一部分,维护一个关节约束的数据结构
这些约束数据可以从机器人的URDF文件中加载出来,也可以在ROS的参数服务器中加载(需要先用YAML文件导入ROS参数服务器)
其包含的约束包括:关节速度、位置、加速度、加加速度、力矩、位置软限位、速度边界、位置边界等等
可以使用如下方法在URDF中进行设置:
<joint name="$foo_joint" type="revolute">
<!-- other joint description elements -->
<!-- Joint limits -->
<limit lower="0.0" upper="1.0" effort="10.0" velocity="5.0" />
<!-- Soft limits -->
<safety_controller k_position="100" k_velocity="10" soft_lower_limit="0.1" soft_upper_limit="0.9" />
</joint>
还有一些参数需要通过YAML配置文件事先加载到参数服务器中,示例如下所示:
joint_limits:
foo_joint:
has_position_limits: true
min_position: 0.0
max_position: 1.0
has_velocity_limits: true
max_velocity: 2.0
has_acceleration_limits: true
max_acceleration: 5.0
has_jerk_limits: true
max_jerk: 100.0
has_effort_limits: true
max_effort: 5.0
bar_joint:
has_position_limits: false # Continuous joint
has_velocity_limits: true
max_velocity: 4.0
# 1.6控制器管理器
控制器管理器提供了一种多控制的机制,可以实现控制器的加载、开始运行、停止运行、卸载等多种操作
此外,控制器管理器还提供了多种工具来辅助操作
# 1.6.1命令行工具
标准使用格式:
$ rosrun controller_manager controller_manager <command> <controller_name>
支持的<command>
命令如下所示:
- load:加载控制器
- unload:卸载控制器
- start:启动控制器
- stop:停止控制器
- spawn:加载并启动控制器
- kill:停止并卸载控制器
如果希望查看某一个控制器的状态,使用命令:
$ rosrun controller_manager controller_manager <command>
支持的<command>
命令如下所示:
- list:根据执行顺序列出所有控制器
- list-types:显示所有控制器的类型
- reload-libraries:以插件形式重新加载所有控制器的库,不需要重新启动,方便对控制器的开发和测试
- reload-libraries--restore:以插件形式重新加载所有控制器的库,并恢复到初始状态
使用spawner命令一次控制多个控制器:
$ rosrun controller_manager spawner [--stopped] name1 name2 name3
加上--stop
命令表示仅加载不执行
如果想要停止一系列的控制器,但不需要卸载,使用如下命令:
$ rosrun controller_manager unspawner name1 name2 name3
# 1.6.2launch工具
在launch文件中,同样可以通过运行controller_manager包的命令,来加载和启动一系列controller
<launch>
<node pkg="controller_manager" type="spawner" args="controller_name1 controller_name2" />
</launch>
上边的launch文件会加载并启动controllers,如果只需要加载:
<launch>
<node pkg="controller_manager" type="spawner" args="--stopped controller_name1 controller_name2" />
</launch>
# 1.6.3可视化工具
controller_manager还提供了可视化工具rqt_controller_manager
安装:rosrun rqt_controller_manager rqt_controller_manager
,直接使用下边的命令打开:
$ rosrun rqt_controller_manager rqt_controller_manager
# 二、Gazebo仿真
# 2.1引入Gazebo属性
首先应该确保每个link的<inertia>
元素已经进行了合理的设置
然后为每个必要的<link>
、<joint>
、<robot>
设置<gazebo>
标签
# 2.1.1为link添加<gazebo>
标签
每一个link都应该添加<gazebo>
标签,其包含的属性只有material,该属性与<visual>
中的material作用相同
由于Gazebo无法通过visual来配置外观属性,所以需要单独设置,否则会采用默认的灰白色
<gazebo reference="wheel_${lr}_link">
<material>Gazebo/Black</material>
</gazebo>
# 2.1.2添加传动
目的:为驱动机器人提供动力源
需要在模型中加入<transmission>
元素,将传动与joint绑定
<!-- Transmission is important to link the joints and the controller -->
<transmission name="wheel_${lr}_joint_trans">
<type>transmission_interface/SimpleTransmission</type>
<joint name="base_to_wheel_${lr}_joint" />
<actuator name="wheel_${lr}_joint_motor">
<hardwareInterface>VelocityJointInterface</hardwareInterface>
<mechanicalReduction>1</mechanicalReduction>
</actuator>
</transmission>
代码解析:
<joint name="base_to_wheel_${lr}_joint" />
用于绑定对应的驱动器joint<type>transmission_interface/SimpleTransmission</type>
用于设定使用的传动装置类型<hardwareInterface>VelocityJointInterface</hardwareInterface>
配置使用的硬件接口类型,这里使用的是速度接口类型
# 2.1.3添加Gazebo控制器插件
Gazebo插件赋予了URDF模型更加强大的功能,可以帮助模型绑定ROS消息,从而完成传感器的方针输出以及对电机的控制
Gazebo插件可以根据插件的作用范围应用到URDF模型的<robot>
、<link>
、<joint>
上,需要使用<gazebo>
标签进行包裹
# (1)为robot元素添加插件
<gazebo>
<plugin name="unique_name" filename="plugin_name.so">
... plugin parameters ...
</plugin>
</gazebo>
如果<gazebo>
元素中没有设置reference="x"
属性,则默认应用于<robot>
标签
# (2)为link、joint添加插件
<gazebo reference="your_link_name">
<plugin name="unique_name" filename="plugin_name.so">
... plugin parameters ...
</plugin>
</gazebo>
Gazebo插件支持的种类在ROS默认安装路径下的/opt/ros/melodic/lib文件夹中可以找到
所有插件都是以libgazeboXXX.so
方式进行命名的
# (3)范例
Gazebo提供的差速控制插件的应用
<!-- controller -->
<gazebo>
<plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
<rosDebugLevel>Debug</rosDebugLevel>
<publishWheelTF>true</publishWheelTF>
<!-- 机器人命名空间,插件所有数据的发布、订阅都在该命名空间中 -->
<robotNamespace>/</robotNamespace>
<publishTf>1</publishTf>
<publishWheelJointState>true</publishWheelJointState>
<alwaysOn>true</alwaysOn>
<updateRate>100.0</updateRate>
<legacyMode>true</legacyMode>
<!-- 左右轮转动的关节joint,插件需要控制这两个joint转动 -->
<leftJoint>base_to_wheel_left_joint</leftJoint>
<rightJoint>base_to_wheel_right_joint</rightJoint>
<!-- 模型相关尺寸,在计算差速参数时会用到 -->
<wheelSeparation>${base_link_radius*2}</wheelSeparation>
<wheelDiameter>${2*wheel_radius}</wheelDiameter>
<wheelTorque>30</wheelTorque>
<!-- 车轮转动的加速度 -->
<wheelAcceleration>1.8</wheelAcceleration>
<!-- 控制器订阅的速度控制指令,在ROS中通常都命名为cmd_vel -->
<commandTopic>cmd_vel</commandTopic>
<!-- 里程计数据的参考坐标系,在ROS中通常为odom -->
<odometryFrame>odom</odometryFrame>
<odometryTopic>odom</odometryTopic>
<robotBaseFrame>base_footprint</robotBaseFrame>
</plugin>
</gazebo>
# 2.2模型显示
首先需要更改launch文件,运行Gazebo并加载机器人模型,并启动必要节点
<launch>
<!-- 设置launch文件的参数 -->
<arg name="world_name" value="$(find mrobot_gazebo)/worlds/playground.world"/>
<arg name="paused" default="false"/>
<arg name="use_sim_time" default="true"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>
<arg name="debug" default="false"/>
<!-- 运行gazebo仿真环境 -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(arg world_name)" />
<arg name="debug" value="$(arg debug)" />
<arg name="gui" value="$(arg gui)" />
<arg name="paused" value="$(arg paused)"/>
<arg name="use_sim_time" value="$(arg use_sim_time)"/>
<arg name="headless" value="$(arg headless)"/>
</include>
<!-- 加载机器人模型描述参数 -->
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find mrobot_gazebo)/urdf/mrobot.urdf.xacro'" />
<!-- 运行joint_state_publisher节点,发布机器人的关节状态 -->
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" ></node>
<!-- 运行robot_state_publisher节点,发布tf -->
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" output="screen" >
<param name="publish_frequency" type="double" value="50.0" />
</node>
<!-- 在gazebo中加载机器人模型-->
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
args="-urdf -model mrobot -param robot_description"/>
</launch>
该launch文件中主要做了两项工作:
- 启动机器人状态并发布节点,同事家在带有Gazebo属性的机器人URDF模型
- 启动Gazebo,并将机器人模型加载到Gazebo仿真环境中
启动命令:roslaunch mrobot_gazebo view_mrobot_gazebo.launch
结果如下所示:
# 2.3运动控制
由于模型中已经加入了libgazebo_ros_diff_drive.so
插件,可以使用差速控制器控制机器人运动
启动命令:$ roslaunch mrobot_teleop mrobot_teleop.launch
,即可运转
# 2.4摄像头仿真
为机器人模型添加一个摄像头插件,让机器人能看到Gazebo中的虚拟环境
同样的需要在摄像头camera的URDF模型文件中添加<gazebo>
相关配置
两个
配置完成后运行仿真环境:roslaunch mrobot_gazebo view_mrobot_with_camera_gazebo.launch
使用rqt工具查看当前机器人眼前的世界
$ rqt_image_view
启动结果如下所示:
# 2.5Kinect仿真
同样的,使用
完成后运行仿真环境:roslaunch mrobot_gazebo view_mrobot_with_kinect_gazebo.launch
运行仿真环境后可以使用RViz查看Kinect的点云数据:
$ rosrun rviz rviz
如果要在RViz中查看点云信息需要在软件中将Fixed Frame设置为
camera_frame_optical
并添加PointCloud2类型插件
结果如下所示:
# 2.6激光雷达仿真
同摄像头仿真和Kinect仿真,激光雷达仿真在配置gazebo相关设定后启动
$ roslaunch mrobot_gazebo view_mrobot_with_laser_gazebo.launch
另外使用RViz可以查看激光数据
$ rosrun rviz rviz
如果要在RViz中查看点云信息需要在软件中将Fixed Frame设置为
base_footprint
并添加LaserScan类型插件
结果如下所示:
# 三、问题解决
# 3.1Resource not found: gazebo_ros
在首次运行命令式出现如下错误,问题根本原因在于没有安装Gazebo仿真环境
- 解决办法:
$ sudo apt-get install ros-melodic-gazebo-ros-pkgs ros-melodic-gazebo-ros-control
# 3.2Gazebo [Err] [REST.cc:205] Error in REST request
运行终端命令启动Gazebo报错,Gazebo页面卡住黑屏,在终端出现Gazebo [Err] [REST.cc:205] Error in REST request
- 解决办法:
$ sudo gedit ~/.ignition/fuel/config.yaml
打开文件并将url : https://api.ignitionfuel.org
修改为url: https://api.ignitionrobotics.org