从零搭建一辆ROS小车(三)使用激光雷达建图

本文将介绍两种使用激光雷达的建图方法

本文所使用的代码:网盘链接 (包括前两篇的代码)


hector_mapping建图与定位

这种方法的优点是简便,只需要有一个激光雷达即可,支持手持建图,不需要底层的里程计数据,

这里我推荐一篇文章https://blog.csdn.net/weixin_41459903/article/details/102795148

 

slam_gampping建图

准备工作

  首先,我们在他的官方文档中可以看到,gmapping功能包订阅了 tf 和 scan,这个tf包括了odom和base_link的变换以及激光雷达和base_link的变换,在之前的文章里为我们介绍了前者,那么接下来将介绍后者的配置。

 

   那么我们需要下载 rplidar_ros 和 slam_gmapping 两个功能包,git太慢的话可以下载我网盘里的。网盘链接

配置串口

  由于激光雷达插在电脑或者其他设备上时串口号总是变来变去,修改代码太麻烦,那么我们将设备和串口号做一个映射就可以解决这个问题了下载网盘的文件,在serial_port/serial_port_sh/rplida/ 下 运行create_udev_rules.sh这个脚本,便可以绑定。对于具体内容可以参考这篇博客,若有不明白的可以私信我。

 

编写rplida.launch

  这个文件中,我们可以看到首先启动了激光雷达的节点,同时在填写串口号的地方,我们改成 /dev/rplidar 这就是因为上文将设备对应的串口号映射为rplidar。

  另外,在原文件中是没有做tf变换的,由于我们需要知道雷达与机器人的相对位置,所以还需要加上tf。

<launch>
  <node name="rplidarNode"          pkg="rplidar_ros"  type="rplidarNode" output="screen">
  <param name="serial_port"         type="string" value="/dev/rplidar"/>
  <param name="serial_baudrate"     type="int"    value="115200"/><!--A1/A2 -->
  <!--param name="serial_baudrate"     type="int"    value="256000"--><!--A3 -->
  <param name="frame_id"            type="string" value="laser"/>
  <param name="inverted"            type="bool"   value="false"/>
  <param name="angle_compensate"    type="bool"   value="true"/>
  </node>

<!-- tf 包的static_transform_publisher 节点 
相对车的xyz方向位置以及xyz方向的角度偏转 父级坐标和雷达坐标,100ms广播一次-->

<node pkg="tf" type="static_transform_publisher"
name="base_link_to_laser"
args="0.01 0 0.01 0 0 0 1  /base_link /laser 100" />


</launch>

 

编写slam_gmapping.launch

<launch>
    <param name="use_sim_time" value="false"/>
    <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen">
      <!--remap from="scan" to="base_scan"/-->
      <param name="map_update_interval" value="5.0"/>
      <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>

编写bringup_base.launch

这个launch文件用于启动我们前两篇文章所提到的节点,包括串口通信,里程计和键盘,顺便把雷达也启动了

<launch>
    <node pkg="serial_port" type="port_SubAndPub.py" name="serial_data_contral" launch-prefix="xterm -e"/>
    <node pkg="serial_port" type="keyboard.py" name="car_teleop" launch-prefix="xterm -e"/>
    <node pkg="odom_tf_package" type="odom_tf_pub" name="odom_tf_pub" launch-prefix="xterm -e" ></node>
    
    <include file="$(find bringup)/launch/include/rplidar.launch" />

</launch>

 

启动建图

roslaunch bringup bringup_base.launch

roslaunch bringup slam_gmapping.launch

rviz

 

打开rviz后设置一下fixed frame 为odom 然后点击add,添加map,LaserScan,至此,通过键盘移动机器人就可以建图了(没实物的话先熟悉下流程,后面会更新仿真环境)

 

 

保存地图

rosrun map_server map_saver -f ~/map/rplidar_gmapping

 

以下是一个简单的 ROS 小车基于激光雷达 SLAM 建图单点导航功能的实现代码: ```python #!/usr/bin/env python import rospy from geometry_msgs.msg import Twist from sensor_msgs.msg import LaserScan from nav_msgs.msg import Odometry from tf.transformations import euler_from_quaternion # 回调函数,用于获取小车当前位置 def get_odom(msg): global x, y, yaw x = msg.pose.pose.position.x y = msg.pose.pose.position.y orientation = msg.pose.pose.orientation (roll, pitch, yaw) = euler_from_quaternion([orientation.x, orientation.y, orientation.z, orientation.w]) # 回调函数,用于获取激光雷达数据 def get_scan(msg): global laser_data laser_data = msg.ranges # 判断小车是否到达目标点 def reached_goal(goal_x, goal_y, distance_tolerance): global x, y distance = abs(((goal_x - x)**2 + (goal_y - y)**2)**0.5) if distance < distance_tolerance: return True else: return False # 主函数 def main(): rospy.init_node('nav_test', anonymous=True) velocity_publisher = rospy.Publisher('/cmd_vel', Twist, queue_size=10) laser_subscriber = rospy.Subscriber('/scan', LaserScan, get_scan) odom_subscriber = rospy.Subscriber('/odom', Odometry, get_odom) # 等待获取激光雷达数据和小车当前位置 while not rospy.is_shutdown(): try: laser_data[0] x y break except: continue goal_x = input("Enter goal x: ") goal_y = input("Enter goal y: ") distance_tolerance = input("Enter tolerance: ") # 控制小车前进或转向 vel_msg = Twist() while not rospy.is_shutdown(): if reached_goal(goal_x, goal_y, distance_tolerance): vel_msg.linear.x = 0 vel_msg.angular.z = 0 velocity_publisher.publish(vel_msg) rospy.loginfo("Goal reached!") break else: # 根据激光雷达数据,确定小车前进方向 front_middle_distance = laser_data[len(laser_data)/2] if front_middle_distance > 0.5: vel_msg.linear.x = 0.2 vel_msg.angular.z = 0 else: right_distance = laser_data[len(laser_data)*3/4] left_distance = laser_data[len(laser_data)/4] if right_distance > left_distance: vel_msg.linear.x = 0 vel_msg.angular.z = -0.5 else: vel_msg.linear.x = 0 vel_msg.angular.z = 0.5 velocity_publisher.publish(vel_msg) rospy.spin() if __name__ == '__main__': try: main() except rospy.ROSInterruptException: pass ``` 该代码首先初始化 ROS 节点,并订阅了激光雷达数据和小车当前位置。然后,通过回调函数获取了激光雷达数据和小车当前位置,并等待获取到这些信息之后再开始执行主循环。 在主循环中,通过输入目标点的坐标和容许的距离误差,控制小车前进或转向,直到到达目标点位置。在控制小车前进或转向时,先通过激光雷达数据确定小车前进方向,然后根据前进方向和目标点的位置计算出小车应该前进的速度和转向的角速度,并通过 /cmd_vel 话题发布给小车的底盘控制器。 值得注意的是,该代码中的小车前进方向的判断方法并不完备,只是一个简单的示例。如果需要更加精确的导航功能,需要使用更为复杂的算法和模型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值