在ROS中有3个可以模拟机器人的模拟器软件:
Gazebo
Stage
ArbotiX(就是RVIz)
你可以任选一个:
Gazebo是一个仿真环境(平台),可以进行三维机器人动力学仿真等,够模拟复杂和现实的环境中关节型机器人,很强大。可以模拟出完整的现实世界,但是软件使用起来比较复杂。
Stage:简单的2D模拟器,可以管理多个机器人和各种传感器,比如激光传感器。
ArbotiX:它就是Rviz,它跟Gazebo软件比较,它不能模拟物理现象和没有传感器反馈。
准备工作: 创建工作空间
1.安装gazebo
sudo apt-get install ros-kinetic-simulators
2.运行 Gazebo
首先配置环境变量
source /opt/ros/kinetic/setup.bash
运行
1) empty_world.launch
roslaunch gazebo_ros empty_world.launch
"paused" default="false"/>
"use_sim_time" default="true"/>
"extra_gazebo_args" default=""/>
"gui" default="true"/>
"headless" default="false"/>
"debug" default="false"/>
"physics" default="ode"/>
"verbose" default="false"/>
"world_name" default="worlds/empty.world"/>
如图,添加了两个球体和一个圆柱以及一个正方体。
4 基本工具介绍
1)移动工具
2)旋转工具
3)缩放工具
4)或者使用ctrl+B来进行地图编辑
5 按照ROS的教程
a)写一个urdf的模型文件
使用终端,建立并编辑urdf文件
写入代码:
<robot name="simple_box">
<link name="my_box">
<inertial>
<origin xyz="2 0 0" />
<mass value="1.0" />
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="100.0" iyz="0.0" izz="1.0" />
inertial>
<visual>
<origin xyz="2 0 1"/>
<geometry>
<box size="1 1 2" />
geometry>
visual>
<collision>
<origin xyz="2 0 1"/>
<geometry>
<box size="1 1 2" />
geometry>
collision>
link>
<gazebo reference="my_box">
<material>Gazebo/Bluematerial>
gazebo>
robot>
使用roslaunch命令打开gazebo:
roslaunch gazebo_ros empty_world.launch
接下来使用rosrun命令将前面写的urdf文件放进去(记得先用终端cd到你放置urdf文件的路径下):
(到此为止,共打开三个终端,一个roscore,一个用来开启gazebo,一个运行urdf)
rosrun gazebo_ros spawn_model -file `pwd`/object.urdf -urdf -z 1 -model my_object
运行结束之后,会发现你的gazebo多了一个蓝色的物体,如图:
b)使用roslaunch命令为模拟器中添加一张桌子
首先,使用终端,进入到gazebo_ros文件夹下。
cd /opt/ros/kinetic/share/gazebo_ros
建立一个objects文件夹,这里主要用来储存后续的模型文件
sudo mkdir objects
然后,使用终端,进入到gazebo_ros下launch文件夹下。
cd /opt/ros/kinetic/share/gazebo_ros/launch
创建一个table.launch文件
sudo gedit table.launch
将以下代码复制进去
roslaunch gazebo_ros table.launch
但是终端会提示错误,解决:
a . 首先,你缺少了一个模型文件,即table的模型文件,我们使用的launch文件只是添加模型,但模型的具体文件不存在,需要我们手动建立。
我们进入到前面建立的objects文件夹下,建立一个名为table.urdf.xacro格式的文件
cd /opt/ros/indigo/share/gazebo_ros/objects
sudo gedit table.urdf.xacro
代码:
<robot name="table"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:gazebo="http://playerstage.sourceforge.net/gazebo/xmlschema/#gz"
xmlns:model="http://playerstage.sourceforge.net/gazebo/xmlschema/#model"
xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor"
xmlns:body="http://playerstage.sourceforge.net/gazebo/xmlschema/#body"
xmlns:geom="http://playerstage.sourceforge.net/gazebo/xmlschema/#geom"
xmlns:joint="http://playerstage.sourceforge.net/gazebo/xmlschema/#joint"
xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface"
xmlns:rendering="http://playerstage.sourceforge.net/gazebo/xmlschema/#rendering"
xmlns:renderable="http://playerstage.sourceforge.net/gazebo/xmlschema/#renderable"
xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller"
xmlns:physics="http://playerstage.sourceforge.net/gazebo/xmlschema/#physics">
<property name="table_height" value="0.55" />
<property name="table_width" value="1.0" />
<property name="table_depth" value="2.0" />
<property name="leg_radius" value="0.02" />
<property name="table_x" value="0.98" />
<property name="table_y" value="0.0" />
<property name="table_z" value="0.0" />
<property name="table_top_thickness" value="0.05"/>
<property name="M_PI" value="3.1415926535897931" />
<link name="table_top_link">
<inertial>
<mass value="1.0" />
<origin xyz="${table_x} ${table_y} ${table_z+table_height-table_top_thickness/2}" />
<inertia ixx="1" ixy="0" ixz="0"
iyy="1" iyz="0"
izz="1" />
inertial>
<visual>
<origin xyz="${table_x} ${table_y} ${table_z+table_height-table_top_thickness/2}" />
<geometry>
<box size="${table_width} ${table_depth} ${table_top_thickness}" />
geometry>
visual>
<collision>
<origin xyz="${table_x} ${table_y} ${table_z+table_height-table_top_thickness/2}" />
<geometry>
<box size="${table_width} ${table_depth} ${table_top_thickness}" />
geometry>
collision>
link>
<gazebo reference="table_top_link">
<material>Gazebo/Woodmaterial>
<mu1>50.0mu1>
<mu2>50.0mu2>
<kp>1000000.0kp>
<kd>1.0kd>
gazebo>
<joint name="leg1_joint" type="fixed" >
<parent link="table_top_link" />
<origin xyz="${table_x+table_width/2} ${table_y+table_depth/2} ${table_z+table_height}" rpy="0 0 0" />
<child link="leg1_link" />
joint>
<link name="leg1_link">
<inertial>
<mass value="1.0" />
<origin xyz="0 0 ${-table_height/2}" />
<inertia ixx="0.1" ixy="0" ixz="0"
iyy="0.1" iyz="0"
izz="0.01" />
inertial>
<visual>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0 0 0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
visual>
<collision>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0.0 0.0 0.0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
collision>
link>
<gazebo reference="leg1_link">
<material>Gazebo/Redmaterial>
<mu1>1000.0mu1>
<mu2>1000.0mu2>
<kp>10000000.0kp>
<kd>1.0kd>
<selfCollide>trueselfCollide>
gazebo>
<joint name="leg2_joint" type="fixed" >
<parent link="table_top_link" />
<origin xyz="${table_x-table_width/2} ${table_y+table_depth/2} ${table_z+table_height}" rpy="0 0 0" />
<child link="leg2_link" />
joint>
<link name="leg2_link">
<inertial>
<mass value="1.0" />
<origin xyz="0 0 ${-table_height/2}" />
<inertia ixx="0.1" ixy="0" ixz="0"
iyy="0.1" iyz="0"
izz="0.01" />
inertial>
<visual>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0 0 0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
visual>
<collision>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0.0 0.0 0.0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
collision>
link>
<gazebo reference="leg2_link">
<material>Gazebo/Redmaterial>
<mu1>1000.0mu1>
<mu2>1000.0mu2>
<kp>10000000.0kp>
<kd>1.0kd>
<selfCollide>trueselfCollide>
gazebo>
<joint name="leg3_joint" type="fixed" >
<parent link="table_top_link" />
<origin xyz="${table_x+table_width/2} ${table_y-table_depth/2} ${table_z+table_height}" rpy="0 0 0" />
<child link="leg3_link" />
joint>
<link name="leg3_link">
<inertial>
<mass value="1.0" />
<origin xyz="0 0 ${-table_height/2}" />
<inertia ixx="0.1" ixy="0" ixz="0"
iyy="0.1" iyz="0"
izz="0.01" />
inertial>
<visual>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0 0 0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
visual>
<collision>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0.0 0.0 0.0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
collision>
link>
<gazebo reference="leg3_link">
<material>Gazebo/Redmaterial>
<mu1>1000.0mu1>
<mu2>1000.0mu2>
<kp>10000000.0kp>
<kd>1.0kd>
<selfCollide>trueselfCollide>
gazebo>
<joint name="leg4_joint" type="fixed" >
<parent link="table_top_link" />
<origin xyz="${table_x-table_width/2} ${table_y-table_depth/2} ${table_z+table_height}" rpy="0 0 0" />
<child link="leg4_link" />
joint>
<link name="leg4_link">
<inertial>
<mass value="1.0" />
<origin xyz="0 0 ${-table_height/2}" />
<inertia ixx="0.1" ixy="0" ixz="0"
iyy="0.1" iyz="0"
izz="0.01" />
inertial>
<visual>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0 0 0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
visual>
<collision>
<origin xyz="0.0 0.0 ${-table_height/2}" rpy="0.0 0.0 0.0" />
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}" />
geometry>
collision>
link>
<gazebo reference="leg4_link">
<material>Gazebo/Redmaterial>
<mu1>1000.0mu1>
<mu2>1000.0mu2>
<kp>10000000.0kp>
<kd>1.0kd>
<selfCollide>trueselfCollide>
gazebo>
<gazebo>
<static>truestatic>
<canonicalBody>table_top_linkcanonicalBody>
gazebo>
robot>
运行roslaunch gazebo_ros table.launch,还是有错
b . 修改table.launch文件
将table.launch的代码中的这句
<param name="table_description" command="$(find xacro)/xacro.py $(find gazebo_worlds)/objects/table.urdf.xacro" />
替换为
<param name="table_description" command="$(find xacro)/xacro.py $(find gazebo_ros)/objects/table.urdf.xacro" />
原因是因为我们使用的indigo版本对应的文件夹名称为gazebo_ros而非gazebo_worlds
保存退出,然后你发现运行roslaunch gazebo_ros table.launch
还是报错: ERROR:cannot launch node of type [gazebo/spawn_model]: gazebo
原来是在已经运行的节点名称不对,找不到这个gazebo名字啊
熟悉ros的朋友这会估计已经可以自己解决了,跳过c)也能自己正常做到了
好的,我们根据这个,找到我们前面打开的empty_worlds.launch这个文件
发现其中尾部有一句关键句为:好的,我们根据这个,找到我们前面打开的empty_worlds.launch这个文件
发现其中尾部有一句关键句为:
我们可以看到,pkg=“gazebo_ros”
而table.launch文件对应的为:
"spawn_table" pkg="gazebo" type="spawn_model" args="-urdf -param table_description -z 0.01 -model table_model" respawn="false" output="screen" />
发现不同,原来这里pkg=”gazebo”
c . 将pkg改正过来
我们再次编辑table.launch文件,将这段代码:
"spawn_table" pkg="gazebo" type="spawn_model" args="-urdf -param table_description -z 0.01 -model table_model" respawn="false" output="screen" />
替换为:
"spawn_table" pkg="gazebo_ros" type="spawn_model" args="-urdf -param table_description -z 0.01 -model table_model" respawn="false" output="screen" />
然后保存关闭。
那么ros kinetic 版本下,正确的table.launch文件代码全文如下:
<launch>
<param name="table_description" command="$(find xacro)/xacro.py $(find gazebo_ros)/objects/table.urdf.xacro" />
<node name="spawn_table" pkg="gazebo_ros" type="spawn_model" args="-urdf -param table_description -z 0.01 -model table_model" respawn="false" output="screen" />
launch>
终端中运行正确的launch文件
roslaunch gazebo_ros table.launch
然后你会看到你的gazebo模拟器中,出现了如图所示的一张桌子:
我这开始也不行 因为我以为蓝色柱子和桌子并不是一个整体呢……嗖嘎~OK 关于urdf,rviz,gazebo的入门已结束,明天得开始机械臂的正式仿真了,不然本周任务又完成不了~
6 使用launch文件导入多个模型
为了方便,我们把这两个物体写到一个launch文件中,一次性运行可以导入两个;
首先,把最开始写的object.urdf复制到 /opt/ros/kinetic/share/gazebo_ros/objects路径下,然后到launch文件夹下建立all.launch文件
sudo cp ~/catkin_ws/src/smartcar/urdf/object.urdf /opt/ros/kinetic/share/gazebo_ros/objects
sudo gedit all.launch
<launch>
<param name="table_description" command="$(find xacro)/xacro.py $(find gazebo_ros)/objects/table.urdf.xacro" />
<param name="box_description" textfile="$(find gazebo_ros)/objects/object.urdf" />
<node name="spawn_table" pkg="gazebo_ros" type="spawn_model" args="-urdf -param table_description -z 0.01 -model table_model" respawn="false" output="screen" />
<node name="spawn_box" pkg="gazebo_ros" type="spawn_model" args="-urdf -param box_description -z 0.01 -model box_model" respawn="false" output="screen" />
launch>
保存并关闭
运行all.launch文件
roslaunch gazebo_ros all.launch
你就会看到你的两个物体先后生成到模拟器中,但要注意,如果你的模拟器中已经存在了这两个物体,那么不会重新添加,因为节点信息已经存在了。