Bootstrap

远程控制ROS机器人建图与规划

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档



一、启动仿真

roslaunch mbot_gazebo view_mbot_gazebo.launch
sudo apt install ros-noetic-teleop-twist-keyboard
rosrun teleop_twist_keyboard teleop_twist_keyboard.py
sudo apt-get install ros-noetic-map-server

二、建图

1创建工作空间

mkdir -p xjq_ws/src 
cd xjq_ws/src 
catkin_create_pkg xjq_navigation actionlib geometry_msgs move_base_msgs rospy
catkin_make
echo "source ~/PATH/xjq_ws/devel/setup.bash">> ~/.bashrc
cd xjq_navigation
mkdir launch map

2.创建LAUNCH文件

launch/gmapping.launch:

<launch>
    /
    <arg name="scan_topic" default="scan" />
   
    <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen" clear_params="true">
        // mbot_gazebo 会通过发/odom topic,传出里程计数据
        <param name="odom_frame" value="odom"/>
        <param name="map_update_interval" value="5.0"/>
        <!-- Set maxUrange < actual maximum range of the Laser -->
        <param name="maxRange" value="5.0"/>
        <param name="maxUrange" value="4.5"/>
        <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.436"/>
        <param name="temporalUpdate" value="-1.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"/>
        <remap from="scan" to="$(arg scan_topic)"/>
    </node>
    
</launch>

手动建图

rosrun teleop_twist_keyboard teleop_twist_keyboard.py
roslaunch xjq_navigation gmapping.launch 

保存地图

cd ~/catkin_ws/src/xjq_navigation/maps
rosrun map_server map_saver -f map

三、导航

1.创建LAUNCH文件

launch/navigation_with_map.launch

<launch>

    <!-- 设置地图的配置文件 -->
    <arg name="map" default="map.yaml" />

    <!-- 运行地图服务器,并且加载设置的地图-->
    <node name="map_server" pkg="map_server" type="map_server" args="$(find mbot_navigation)/maps/$(arg map)"/>

    <!-- 运行move_base节点 -->
    <include file="$(find mbot_navigation)/launch/move_base.launch"/>

    <!-- 启动AMCL节点 -->
    <include file="$(find mbot_navigation)/launch/amcl.launch" />


</launch>

launch/amcl.launch

 <launch>
    <arg name="scan_topic" default="scan"/>
    <arg name="initial_pose_x" default="0.0"/>
    <arg name="initial_pose_y" default="0.0"/>
    <arg name="initial_pose_a" default="0.0"/>

    <node pkg="amcl" type="amcl" name="amcl" clear_params="true">
        <param name="min_particles"             value="500"/>
        <param name="max_particles"             value="3000"/>
        <param name="kld_err"                   value="0.02"/>
        <param name="update_min_d"              value="0.20"/>
        <param name="update_min_a"              value="0.20"/>
        <param name="resample_interval"         value="1"/>
        <param name="transform_tolerance"       value="0.5"/>
        <param name="recovery_alpha_slow"       value="0.00"/>
        <param name="recovery_alpha_fast"       value="0.00"/>
        <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)"/>
        <param name="gui_publish_rate"          value="50.0"/>

        <remap from="scan"                      to="$(arg scan_topic)"/>
        <param name="laser_max_range"           value="3.5"/>
        <param name="laser_max_beams"           value="180"/>
        <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_likelihood_max_dist" value="2.0"/>
        <param name="laser_model_type"          value="likelihood_field"/>

        <param name="odom_model_type"           value="diff"/>
        <param name="odom_alpha1"               value="0.1"/>
        <param name="odom_alpha2"               value="0.1"/>
        <param name="odom_alpha3"               value="0.1"/>
        <param name="odom_alpha4"               value="0.1"/>
        <param name="odom_frame_id"             value="odom"/>
        <param name="base_frame_id"             value="base_footprint"/>
    </node>
</launch>

launch/move_base.launch

 <launch>

  <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="true">
    <param name="base_local_planner" value="dwa_local_planner/DWAPlannerROS" />

    <rosparam file="$(find mbot_navigation)/config/move_base/costmap_common_params.yaml" command="load" ns="global_costmap" />
    <rosparam file="$(find mbot_navigation)/config/move_base/costmap_common_params.yaml" command="load" ns="local_costmap" /> 
    <rosparam file="$(find mbot_navigation)/config/move_base/local_costmap_params.yaml" command="load" />
    <rosparam file="$(find mbot_navigation)/config/move_base/global_costmap_params.yaml" command="load" />

    <rosparam file="$(find mbot_navigation)/config/move_base/move_base_params.yaml" command="load" />
    <rosparam file="$(find mbot_navigation)/config/move_base/dwa_local_planner_params.yaml" command="load" />
  </node>
  
</launch>

2.导航

roslaunch xjq_navigation navigation_with_map.launch
mkdir scripts/test.py
vim CMakeLists.txt

mkdir config

waypoints.yaml

waypoints:
  - x: 1.0
    y: 0.0
    theta: 0.0
  - x: 1.0
    y: 0.0
    theta: 0.0
  - x: 1.0
    y: 0.0
    theta: 0.0
rosparam load target_points.yaml
 catkin_install_python(PROGRAMS
   scripts/test.py
   scripts/get_current_pos.py
   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
 )
#!/usr/bin/env python3
import rospy
import actionlib
from actionlib_msgs.msg import *  
from geometry_msgs.msg import Pose, PoseWithCovarianceStamped, Point, Quaternion, Twist  
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal  
from tf.transformations import quaternion_from_euler

def create_pose(x, y, theta):
    pose = Pose()
    pose.position.x = x
    pose.position.y = y
    pose.position.z = 0.0

    quaternion = quaternion_from_euler(0, 0, theta)
    pose.orientation = Quaternion(*quaternion)

    return pose
    
def main():
  rospy.init_node("move_test", anonymous=True)
  move_base_client = actionlib.SimpleActionClient("move_base", MoveBaseAction)
  rospy.loginfo("Waiting for move_base action server...")  
  while move_base_client.wait_for_server(rospy.Duration(5.0)) == 0:
    rospy.loginfo("connected to move base server")
  	
  target_list = []
  # 从参数服务器读取目标点数据
  waypoints = rospy.get_param('waypoints')
  rospy.loginfo("Loaded waypoints: %s", waypoints)
  # 处理目标点
  for wp in waypoints:
      pose = create_pose(wp['x'], wp['y'], wp['theta'])
      rospy.loginfo("Waypoint Pose: %s", pose)
      target_list.append(pose)
        

  
  for i, target in enumerate(target_list):
    start_time = rospy.Time.now()  
    
    goal = MoveBaseGoal()
    
    goal.target_pose.header.frame_id = 'base_link'
    goal.target_pose.header.stamp = rospy.Time.now()
    goal.target_pose.pose = target
    
    #goal.target_pose.pose.position.x = 1.0
    #goal.target_pose.pose.orientation.w = 1.0
    
    rospy.loginfo("going to {0} goal".format(i))
    move_base_client.send_goal(goal)
    finished_within_time = move_base_client.wait_for_result(rospy.Duration(300))
    
    if not finished_within_time:
      move_base_client.cancel_goal()
      rospy.loginfo("time out, failed to goal")
    else:
      running_time = (rospy.Time.now() - start_time).to_sec()
      if move_base_client.get_state() == GoalStatus.SUCCEEDED:
        rospy.loginfo("go to {0} goal succeeded, run time: {1} sec".format(i, running_time))
      else:
        rospy.loginfo("goal failed")
    
if __name__ == "__main__":
  main()
  
rosrun xjq_navigation test.py
;