构建一个模拟的两轮ROS机器人
1. 确保已经安装了Rviz
2. 生成并构建ROS功能包
2.1 生成一个catkin工作空间
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace
编译工作空间
$ cd ~/catkin_ws/
$ catkin_make
加载源文件
$ source ~/catkin_ws/devel/setup.bash
在.bashrc文件中加入命令
$ echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
为了确定源文件是否被加载,通过下列命令查询ROS环境正在使用的工作空间
$ echo $ROS_PACKAGE_PATH
对应输出应为:
home/username/catkin_ws/src:/opt/ros/noetic/share
2.2 漏了一个懒得改
2.3 构建差分驱动的机器人的URDF
URDF是具有特殊定义的XML格式的文件,专门用来对机器人组件级别进行抽象的模型描述。
在ros_robotics功能包目录生成一个/urdf目录:
$ cd ~/catkin_ws/src/robotics
$ mkdir urdf
$ cd urdf
2.3.1 创建机器人底座
机器人的第一个组成部分是底座盒子长宽高分别为0.5,0.5,0.25。
新建文件dd_robot.urdf保存在urdf文件夹下。
<<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
</visual>
</link>
</robot>
2.3.2 使用roslaunch
roslaunch:能够简化启动多个ROS节点的过程;简化参数服务器设置的过程
使用时需通过roscore命令来启动节点管理器
roslaunch语法结构
$ roslaunch <package_name> <file.launch>
在ros_robotics功能包里面新建文件夹lacunch,再新建ddrobot_rviz.launch文件
<launch>
<!-- value passed by command line input-->
<arg name="model"/>
<arg name="gui" default="False"/>
<!-- set these parameters on Parameter Server-->
<param name="robot_description"
textfile="$(find ros_robotics)/urdf/$(arg model)"/>
<param name="use_gui" value="$(arg gui)"/>
<!-- Start 3 nodes: joint_state_publisher,
robot_state_publisher and
rviz -->
<node name="joint_state_publisher"
pkg="joint_state_publisher"
type="joint_state_publisher"/>
<node name="robot_state_publisher"
pkg="robot_state_publisher"
type="robot_state_publisher"/>
<node name="rviz" pkg="rviz" type="rviz"
args="-d $(find ros_robotics)/urdf.rviz"
required="true"/>
</launch>
输入以下命令查看机器人模型
$ roslaunch ros_robotics ddrobot_rviz.launch model:=dd_robot.urdf
如果出现下面错误,RLException: [ddrobot_rviz.launch] is neither a launch file in package [launch] nor is [launch] a launch file name
The traceback for the exception was written to the log file
解决方法:将devel/setup.bash添加到系统
source ./devel/setup.bash
在displays添加Robotmodel和TF,并将FIxed frame改为base_link。
2.3.3 添加*
继续在上一段代码加
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
</visual>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</visual>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</visual>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
运行
2.3.4 添加颜色
为了方便观看
还是在上面代码改
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
<material name="blue">
<color rgba="0 0.5 1 1"/>
</material>
</visual>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
继续运行,我们的车出来了
2.3.5 添加小脚轮
添加小脚轮来使小车平衡
在base_link加代码
<!--Caster-->
<visual name="caster">
<origin xyz="0.2 0 -0.125" rpy="0 0 0"/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</visual>
2.3.6 添加碰撞属性
添加碰撞属性来使小车检测和识别物体的边界
同样是在<link>元素中加<collision>属性
完整代码
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
<material name="blue">
<color rgba="0 0.5 1 1"/>
</material>
</visual>
<!--Base collision-->
<collision>
<origin xyz="0 0 0 " rpy="0 0 0 "/>
<geometry>
<box size="0.5 0.5 0.25"/>
</geometry>
</collision>
<!--Caster-->
<visual name="caster">
<origin xyz="0.2 0 -0.125" rpy="0 0 0"/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</visual>
<!--caster collision -->
<collision>
<origin xyz="0.2 0 -0.125" rpy="0 0 0 "/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</collision>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--right wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--left wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
2.3.7 移动*
接下来,我们通过GUI弹窗来控制*的关节组件
将gui添加到命令字段,如下:
$ roslaunch ros_robotics ddrobot_rviz.launch model:=dd_robot.urdf gui:=True
如果发现打开Rviz,发现没有GUI窗口。采用下面这个方法
- 下载joint_state_publisher_gui
$ sudo apt-get install ros-noetic-joint-state-publisher-gui
- 将launch文件里面的joint_state_publisher改为joint_state_publisher_gui
- 重新运行命令,就会出现GUI窗口了
2.3.8 添加物理属性
物理属性:包括惯性<inertia>,3*3矩阵;质量<mass>,单位kg
之后就可以在Gazebo引擎中启动了
需要在<link>中添加<inertial>标签
具体代码较长
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
<material name="blue">
<color rgba="0 0.5 1 1"/>
</material>
</visual>
<!--Base collision-->
<collision>
<origin xyz="0 0 0 " rpy="0 0 0 "/>
<geometry>
<box size="0.5 0.5 0.25"/>
</geometry>
</collision>
<inertial>
<mass value="5"/>
<inertia ixx="0.13" ixy="0.0" ixz="0.0" iyy="0.21" iyz="0.0" izz="0.13"/>
</inertial>
<!--Caster-->
<visual name="caster">
<origin xyz="0.2 0 -0.125" rpy="0 0 0"/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</visual>
<!--caster collision -->
<collision>
<origin xyz="0.2 0 -0.125" rpy="0 0 0 "/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.0001" ixy="0.0" ixz="0.0" iyy="0.0001" iyz="0.0" izz="0.0001"/>
</inertial>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--right wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.005" iyz="0.0" izz="0.005"/>
</inertial>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--left wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.005" iyz="0.0" izz="0.005"/>
</inertial>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
我们可以使用check_urdf工具来检查语法
$ check_urdf dd_robot.urdf
2.4 Gazebo
2.4.1 安装Gazebo
打开Gazebo
$ gazebo
2.4.2 使用roslaunch启动Gazebo
$ roslaunch gazebo_ros empty_world.launch
2.4.3 更改颜色
<gazebo reference="base_link">
material>Gazebo/Blue</material>
<pose>0 0 3 0 0 0</pose>
</gazebo>
2.4.4模型验证
验证代码是否有问题
$ gzsdf -p dd_robot.gazebo
如果这个有问题换下面的
$ gz sdf -p dd_robot.gazebo
2.4.5 在Gazebo中查看URDF
使用XML生成ddrobot_gazebo.launch
<launch>
<!-- We resume the logic in gazebo_ros package empty_world.launch, -->
<!-- changing only the name of the world to be launched -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find ros_robotics)/worlds/ddrobot.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"/>
</include>
<!-- Spawn dd_robot into Gazebo -->
<node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" output="screen"
args="-file $(find ros_robotics)/urdf/dd_robot.gazebo -urdf -model ddrobot" />
</launch>
2.4.6 新建环境
在功能包里面新建文件夹worlds
新建文件ddrobot.world
<?xml version="1.0" ?>
<sdf version="1.4">
<world name="default">
<include>
<uri>model://ground_plane</uri>
</include>
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://construction_cone</uri>
<name>construction_cone</name>
<pose>-3.0 0 0 0 0 0</pose>
</include>
<include>
<uri>model://construction_cone</uri>
<name>construction_cone</name>
<pose>3.0 0 0 0 0 0</pose>
</include>
</world>
</sdf>
参考文献:ROS机器人开发实用案例分析(第二版)