ros竞速车仿真

本文详述了ROS环境下智能车竞速的仿真搭建过程,包括环境配置、模型加载、ros_control插件的使用、键盘遥控节点设计、slam-gmapping建图以及move_base导航框架的应用。通过解决gazebo闪退问题,实现机器人关节控制,并成功进行地图保存和导航演示。
摘要由CSDN通过智能技术生成


前言

主要针对大学生智能车线上仿真赛;


主要内容:

在这里插入图片描述

一、仿真环境搭建:

模型使用的是智能车竞赛官方提供的仿真模型:
https://gitee.com/zeende/racecar_sim/tree/noetic/

1.1 模型分析与设计

在这里插入图片描述
代码模型实现:
在这里插入图片描述

1.2 launch启动模型;

1、首先设置racecar_gazebo.launch参数,及机器人初始位置

<!-- 设置launch文件的参数 -->
    <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"/>
<!--机器人的起点放置位置-->
    <arg name="x_pos" default="-0.5"/>
    <arg name="y_pos" default="0"/>
    <arg name="z_pos" default="0.0"/>

2、启动gazebo,并加载环境模型,racetrack.world;

在这里插入图片描述

	<!--运行gazebo仿真环境-->
	<include file="$(find gazebo_ros)/launch/empty_world.launch">
        <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)"/>
		<arg name="world_name" value="$(find racecar_description)/worlds/racetrack.world"/>
    </include>

3、加载机器人模型:racecar.urdf.xacro

<!-- 加载机器人模型描述参数 -->
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find racecar_description)/urdf/racecar.urdf.xacro'"/>

    <!-- 在gazebo中加载机器人模型-->
<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
      args="-urdf -model racecar -param robot_description -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos)"/> 

4、发布机器人关节状态

用于之后在rviz中显示,以及提供关节接口;

<!--运行joint_state_publisher节点,发布机器人关节状态-->
<node name= "robot_state_publisher" pkg= "robot_state_publisher" type= "robot_state_publisher">
	<param name="publish_frequency" type="double" value="20.0" />
	<remap from="/joint_states" to="/racecar/joint_states"/>
</node>

5、显示效果

此时我们启动launch文件:

roslaunch bringup racecar_gazebo.launch

在这里插入图片描述此时,可能会遇到部分问题;
有些开发者在执行gazebo时,会闪退,并出现如下问题,

[gazebo_gui-3] process has died [pid 7811, exit code 134, cmd /opt/ros/kinetic/lib/gazebo_ros/gzclient __name:=gazebo_gui __log:=/home/ubuntu/.ros/log/4570ac34-0278-11ed-917f-000c298f0f5f/gazebo_gui-3.log].

我们可以通过以下方式进行解决:
方式一:
gazebo启用3D加速选项方面存在一些问题,可从VM设置中禁用设置3D加速选项。禁用该选项后,仿真环境运行会比较缓慢,但可以正常工作。如图所示:
在这里插入图片描述
方式二:更改SVGA_VGPU10变量:
先在终端执行:

export SVGA_VGPU10=0

然后再执行roslaunch语句即可。其实,更改SVGA_VGPU10变量是为了告诉系统OpenGL版本。
尝试两种方式,然后看看哪个更适合。如果要使用此选项避免每次启动终端时都设置此变量,只需将此命令添加到.bashrc中即可。

export SVGA_VGPU10=0" >> ~/.bashrc

然后正常roslaunch即可启动仿真环境。

1.3 机器人控制插件ros_control

1、简介ros_control

ROS中提供了丰富的机器人应用:SLAM、导航、MoveIt…但是你可能一直有一个疑问,这些功能包到底应该怎么样用到我们的机器人上,也就是说在应用和实际机器人或者机器人仿真器之间,缺少一个连接两者的东西。
在这里插入图片描述
ros_control就是ROS为用户提供的应用与机器人之间的中间件,包含一系列控制器接口、传动装置接口、硬件接口、控制器工具箱等等,可以帮助机器人应用快速落地,提高开发效率。
在这里插入图片描述

2、在launch中配置联合控制器

因为联合控制器参数比较多,一般会通过在racecar.launch文件中加载yaml文件进行配置:

 <!-- 从yaml文件加载联合控制器的参数 -->
<rosparam file="$(find bringup)/config/ctrl.yaml" command="load"/>

同时需要加载控制器:

<!-- 加载控制器 spawner -->
	<node name="controller_manager" pkg="controller_manager" type="spawner" 
	      respawn="false" output="screen" ns="/racecar" 
	      args="left_rear_wheel_velocity_controller       right_rear_wheel_velocity_controller
	            left_front_wheel_velocity_controller      right_front_wheel_velocity_controller
	            left_steering_hinge_position_controller   right_steering_hinge_position_controller
	            joint_state_controller"/>

此处,我们在功能包中增加config文件夹,增加ctrl.yaml文件,用以参数配置:

racecar: 
  # 命名空间
  # Publish all joint states --公布所有--------------------
  joint_state_controller:
    type: joint_state_controller/JointStateController
    publish_rate: 50
  
  # Velocity Controllers ----速度控制器---------------------
  left_rear_wheel_velocity_controller:
    type: effort_controllers/JointVelocityController
    joint: left_rear_axle
    pid: {p: 1.5, i: 0.0, d: 0.0, i_clamp: 0.0}
  right_rear_wheel_velocity_controller:
    type: effort_controllers/JointVelocityController
    joint: right_rear_axle
    pid: {p: 1.5, i: 0.0, d: 0.0, i_clamp: 0.0}
  left_front_wheel_velocity_controller:
    type: effort_controllers/JointVelocityController
    joint: left_front_axle
    pid: {p: 0.7, i: 0.0, d: 0.0, i_clamp: 0.0}
  right_front_wheel_velocity_controller:
    type: effort_controllers/JointVelocityController
    joint: right_front_axle
    pid: {p: 0.7, i: 0.0, d: 0.0, i_clamp: 0.0}

  # Position Controllers ---位置控制器-----------------------
  left_steering_hinge_position_controller:
    joint: left_steering_joint
    type: effort_controllers/JointPositionController
    pid: {p: 10.0, i: 0.0, d: 0.5}
  right_steering_hinge_position_controller:
    joint: right_steering_joint
    type: effort_controllers/JointPositionController
    pid: {p: 10.0, i: 0.0, d: 0.5}

注意:此处命名空间要和launch文件中的namespace(ns)一致。
参数args标签中的6个话题名称就是我们用户控制的关节。

至此,机器人就可以实现关节控制。

1.4 键盘遥控节点设计

对于阿克曼结构机器人收到的控制指令是速度和前轮转向角,因此我们应该使用ackermann_msgs/AckermannDriveStamped而不是geometry_msgs/Twist;
此时我们需要安装:

ubuntu@ubuntu:~$  rosmsg show ackermann_msgs/AckermannDriveStamped 
std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
ackermann_msgs/AckermannDrive drive
  float32 steering_angle
  float32 steering_angle_velocity
  float32 speed
  float32 acceleration
  float32 jerk

而不是:

ubuntu@ubuntu:~$ 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

1、读取键盘指令,发布控制机器人的话题数据

2、将速度和角度分解到对应的关节上


三、slam-gmapping

3.1 安装slam-gmapping

ubuntu@ubuntu:~$ sudo apt install ros-kinetic-slam-gmapping

3.2 编写launch

编写启动建图的launch文件。

1、racecar_gazebo_rviz.launch

<?xml version="1.0"?>
<launch>
    <include file="$(find bringup)/launch/gazebo/racecar.launch"></include>
    <node name="rviz" pkg="rviz" type="rviz"
          args="-d $(find bringup)/rviz/racecar_urdf.rviz" required="true"/>
    <node name="gazebo_odometry" pkg="racecar_description" type="gazebo_odometry.py"/>
</launch>

解读:

name="gazebo_odometry"

增加里程计节点;

2、racecar.launch

<?xml version="1.0"?>
<launch>
	    <!-- 设置launch文件的参数 -->
    <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"/>
    <!--模型车的起点放置位置-->
    <arg name="x_pos" default="-0.5"/>
    <arg name="y_pos" default="0"/>
    <arg name="z_pos" default="0.0"/>

	<!--运行gazebo仿真环境-->
	<include file="$(find gazebo_ros)/launch/empty_world.launch">
        	<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)"/>
		<arg name="world_name" value="$(find racecar_description)/worlds/racetrack.world"/>
               <!-- .world文件的地址-->
    	</include>

	<!-- 加载机器人模型描述参数 -->
	<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find racecar_description)/urdf/racecar.urdf.xacro'"/>


	<!--运行joint_state_publisher节点,发布机器人关节状态-->
	<!--<node name = "robot_state_publisher" pkg = "robot_state_publisher" type = "state_publisher">-->
	<node name= "robot_state_publisher" pkg= "robot_state_publisher" type= "robot_state_publisher">
		<param name="publish_frequency" type="double" value="20.0" />
		<remap from="/joint_states" to="/racecar/joint_states"/>
	</node>
	<!-- 在gazebo中加载机器人模型-->
    <node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
          args="-urdf -model racecar -param robot_description -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos)"/> 

	<!-- 从yaml文件加载联合控制器的参数 -->
	<rosparam file="$(find bringup)/config/ctrl.yaml" command="load"/>
	
	<!-- 加载控制器 spawner -->
	<node name="controller_manager" pkg="controller_manager" type="spawner" 
	      respawn="false" output="screen" ns="/racecar" 
	      args="left_rear_wheel_velocity_controller       right_rear_wheel_velocity_controller
	            left_front_wheel_velocity_controller      right_front_wheel_velocity_controller
	            left_steering_hinge_position_controller   right_steering_hinge_position_controller
	            joint_state_controller"/>

    <!-- 阿克曼的消息类型对应到机器人关节话题的发布 -->
    <node pkg="racecar_description" type="servo_commands.py" name="servo_commands" output="screen">
    </node>

</launch>

3、slam_gmapping.launch

<launch>
    <arg name="scan_topic"  default="scan" />    <!--雷达话题-->
    <arg name="base_frame"  default="base_footprint"/>    <!--小车在底盘的映射坐标-->
    <arg name="odom_frame"  default="odom"/>    <!--发布的里程计坐标系-->
    <param name="use_sim_time" value="false"/>    
    <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen">

      <param name="base_frame" value="$(arg base_frame)"/>   <!--底盘坐标系-->
      <param name="odom_frame" value="$(arg odom_frame)"/>   <!--里程计坐标系-->      
      <!--remap from="scan" to="base_scan"/-->
      <param name="map_update_interval" value="5.0"/>  <!--更新时间(s),每多久更新一次地图,不是频率-->
      <param name="maxUrange" value="14.0"/>  <!--激光雷达最大可用距离,在此之外的数据截断不用-->
      <param name="sigma" value="0.05"/>
      <param name="kernelSize" value="1"/>
      <param name="lstep" value="0.05"/>
      <param name="astep" value="0.05"/>
      <param name="iterations" value="5"/>
      <param name="lsigma" value="0.075"/>
      <param name="ogain" value="3.0"/>
      <param name="lskip" value="0"/>
      <param name="srr" value="0.01"/>
      <param name="srt" value="0.02"/>
      <param name="str" value="0.01"/>
      <param name="stt" value="0.02"/>
      <param name="linearUpdate" value="0.5"/>
      <param name="angularUpdate" value="0.218"/>
      <param name="temporalUpdate" value="5.0"/>
      <param name="resampleThreshold" value="0.5"/>
      <param name="particles" value="80"/>
      <param name="xmin" value="-1.0"/>
      <param name="ymin" value="-1.0"/>
      <param name="xmax" value="1.0"/>
      <param name="ymax" value="1.0"/>
      <param name="delta" value="0.05"/>
      <param name="llsamplerange" value="0.01"/>
      <param name="llsamplestep" value="0.01"/>
      <param name="lasamplerange" value="0.005"/>
      <param name="lasamplestep" value="0.005"/>
    </node>
</launch>

3.3 保存地图

在三个终端中运行以下三个 launch:

ubuntu@ubuntu:~$ roslaunch bringup racecar_gazebo_rviz.launch 
ubuntu@ubuntu:~/racecar_sim$ rosrun racecar_description keyboard_teleop.py
ubuntu@ubuntu:~$ roslaunch bringup slam_gmapping.launch 

运行第一条指令后,会打开gazebo及rviz。
在这里插入图片描述

rqt_graph 

请添加图片描述

此时启动第二条指令,开始按键控制;
增加了按键控制节点;
请添加图片描述

再启动第三条指令,可以看到地图显示由黑色,变成灰色路径;
在这里插入图片描述
请添加图片描述

通过按键控制,将小车从起点移动到终点;此时我们完成的地图的构建;
在这里插入图片描述
在这里插入图片描述

地图构建完成后,需要保存地图;
此时开启新的终端运行:

ubuntu@ubuntu:~/racecar_sim$ rosrun map_server map_saver -f /home/ubuntu/racecar_sim/src/bringup/map/map
[ INFO] [1657961143.594741695]: Waiting for the map
[ INFO] [1657961143.814344370]: Received a 1184 X 480 map @ 0.050 m/pix
[ INFO] [1657961143.814478020]: Writing map occupancy data to /home/ubuntu/racecar_sim/src/bringup/map/map.pgm
[ INFO] [1657961143.857679615]: Writing map occupancy data to /home/ubuntu/racecar_sim/src/bringup/map/map.yaml
[ INFO] [1657961143.859262512]: Done

此时会在相应路径下生成两个map相关的文件:
在这里插入图片描述
其中map.pgm为地图图片;
map.yaml为方便加载的参数文件;

image: /home/ubuntu/racecar_sim/src/bringup/map/map.pgm
resolution: 0.050000
origin: [-12.200000, -12.200000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196

image: 表示图片路径;
resolution: 地图分辨率 单位:米/像素;
origin: 图像左下角在地图坐标下的坐标
negate: 是否应该颠倒 白:自由/黑:的语义(阈值的解释不受影响)
occupied_thresh: 占用概率大于此阈值的像素被认为已完全占用
free_thresh: 占用率小于此阈值的像素被认为是完全空闲的

四、导航仿真

4.1 move_base框架

move_base框架主要是为ROS提供导航相关的配置、运行、交互的接口;
在这里插入图片描述

1、安装必要功能包:

方法一:

sudo apt-get install ros-kintic-teb-local-planner  (安装包)

rosdep install teb_local_planner(安装依赖)

参考文件:
http://t.zoukankan.com/long5683-p-11404576.html

最好安装整个navigation功能包

4.2 编写launch

因为存在大量的导航配置参数,因此会分类写到各个参数文件内。
在这里插入图片描述
在这里插入图片描述

4.3Teb使用

参考:
https://hermit.blog.csdn.net/article/details/117669476
teb使用的特点:
导航算法一般针对不通结构会用侧重,例如常规的移动机器人底盘结构设计为差速结构,这样会适用于多数常见算法,如base_local_planner、dwa_local_planner等,单数对于阿克曼结构,它的特点是存在最小转弯半径的限制,这样就导致常见的算法并不合适,由此teb_local_planner比较合适。
teb_local_planner提供了一种car-like的动力学模型,就是像汽车一样存在最小转弯半径限制,这样它就可以完成阿克曼结构的动力学解算。

参数文件说明:
在这里插入图片描述
首先查看move_base.launch,里面加载了此处所有的yaml文件。

<launch>
    <!--启动move_base节点,然后加载参数文件-->
   <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
    <rosparam file="$(find bringup)/param/costmap_common_params.yaml" command="load" ns="global_costmap" /> 
    <rosparam file="$(find bringup)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />
    <rosparam file="$(find bringup)/param/local_costmap_params.yaml" command="load" />
    <rosparam file="$(find bringup)/param/global_costmap_params.yaml" command="load" /> 
    <rosparam file="$(find bringup)/param/teb_local_planner_params.yaml" command="load" />
    <rosparam file="$(find bringup)/param/move_base_params.yaml" command="load" />
    <!--设置局部路径规划器为TeblocalPlanner-->
    <param name="base_local_planner" value="teb_local_planner/TebLocalPlannerROS" />
    <!--<param name="controller_frequency" value="10" />
    <param name="controller_patiente" value="15.0"/>-->
   </node>
   	<node name="map_server" pkg="map_server" type="map_server" args="$(find bringup)/map/map.yaml" output="screen">
                <param name="frame_id" value="map"/>
    </node>

    <!--<node pkg="tf" type="static_transform_publisher"
        name="odom_to_map"
        args="0 0 0 0 0 0 1  /odom /map 100" />-->

    <!--<include file="$(find bringup)/launch/robot_amcl.launch.xml" />-->

   <node name="nav_sim" pkg="racecar_description" type="nav_sim.py" >
    </node>
    
   <arg name="use_map_topic"   default="True"/>
    <arg name="scan_topic"      default="/scan"/> 
    <arg name="initial_pose_x"  default="-0.5"/>
    <arg name="initial_pose_y"  default="0.0"/>
    <arg name="initial_pose_a"  default="0.0"/>
    <arg name="odom_frame_id"   default="odom"/>
    <arg name="base_frame_id"   default="base_footprint"/>
    <arg name="global_frame_id" default="map"/>
    <node pkg="amcl" type="amcl" name="amcl">
      <param name="use_map_topic"             value="$(arg use_map_topic)"/>
      <!-- Publish scans from best pose at a max of 10 Hz -->
      <param name="odom_model_type"           value="diff"/>
      <param name="odom_alpha5"               value="0.1"/>
      <param name="gui_publish_rate"          value="10.0"/>
      <param name="laser_max_beams"           value="810"/>
      <param name="laser_max_range"           value="-1"/>
      <param name="min_particles"             value="500"/>
      <param name="max_particles"             value="5000"/>
      <param name="kld_err"                   value="0.05"/>
      <param name="kld_z"                     value="0.99"/>
      <param name="odom_alpha1"               value="0.2"/>
      <param name="odom_alpha2"               value="0.2"/>
      <!-- translation std dev, m -->
      <param name="odom_alpha3"               value="0.2"/>
      <param name="odom_alpha4"               value="0.2"/>
      <param name="laser_z_hit"               value="0.5"/>
      <param name="laser_z_short"             value="0.05"/>
      <param name="laser_z_max"               value="0.05"/>
      <param name="laser_z_rand"              value="0.5"/>
      <param name="laser_sigma_hit"           value="0.2"/>
      <param name="laser_lambda_short"        value="0.1"/>
      <param name="laser_model_type"          value="likelihood_field"/>
      <!-- <param name="laser_model_type" value="beam"/> -->
      <param name="laser_likelihood_max_dist" value="2.0"/>
      <param name="update_min_d"              value="0.1"/>
      <param name="update_min_a"              value="0.2"/>
      <param name="odom_frame_id"             value="$(arg odom_frame_id)"/> 
      <param name="base_frame_id"             value="$(arg base_frame_id)"/> 
      <param name="global_frame_id"           value="$(arg global_frame_id)"/>
      <param name="resample_interval"         value="1"/>
      <!-- Increase tolerance because the computer can get quite busy -->
      <param name="transform_tolerance"       value="1.0"/>
      <param name="recovery_alpha_slow"       value="0.0"/>
      <param name="recovery_alpha_fast"       value="0.0"/>
      <param name="initial_pose_x"            value="$(arg initial_pose_x)"/>
      <param name="initial_pose_y"            value="$(arg initial_pose_y)"/>
      <param name="initial_pose_a"            value="$(arg initial_pose_a)"/>
      <remap from="/scan"                     to="$(arg scan_topic)"/>
      <remap from="/tf_static"                to="/tf_static"/>
    </node>
   </launch> 

解读yaml:

4.4 添加amcl定位

4.5 导航功能演示

ubuntu@ubuntu:~$ roslaunch bringup racecar_gazebo_rviz.launch
ubuntu@ubuntu:~$ roslaunch bringup move_base.launch
在这里插入图片描述
启动2D Nav Goal,开始导航,可以看到绿色为路径规划。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值