亚博microros小车-原生ubuntu支持系列:13 激光雷达避障

一 背景知识

小车发了了数据包含激光雷达数据,类型是sensor_msgs/msg/LaserScan

bohu@bohu-TM1701:~$ ros2 node info /YB_Car_Node
/YB_Car_Node
  Subscribers:
    /beep: std_msgs/msg/UInt16
    /cmd_vel: geometry_msgs/msg/Twist
    /servo_s1: std_msgs/msg/Int32
    /servo_s2: std_msgs/msg/Int32
  Publishers:
    /battery: std_msgs/msg/UInt16
    /imu: sensor_msgs/msg/Imu
    /odom_raw: nav_msgs/msg/Odometry
    /scan: sensor_msgs/msg/LaserScan
  Service Servers:

  Service Clients:

  Action Servers:

  Action Clients

激光雷达数据

sensor_msgs/msg/LaserScan 格式

scan_data 是从激光雷达(LiDAR)获取的激光扫描数据,通常使用 sensor_msgs/LaserScan 消息类型表示。该消息包含以下字段:

    header:
        std_msgs/Header 类型,包含消息的元数据,如时间戳和坐标系 ID。

    angle_min:
        float32 类型。表示扫描的最小角度,通常以弧度为单位。

    angle_max:
        float32 类型。表示扫描的最大角度,通常以弧度为单位。

    angle_increment:
        float32 类型。每个测量点之间的角度增量,即相邻点之间的角度差,通常以弧度为单位。

    time_increment:
        float32 类型。相邻测量点之间的时间增量,单位是秒。

    scan_time:
        float32 类型。完成一次扫描的总时间,单位是秒。

    range_min:
        float32 类型。激光雷达可检测到的最小距离,通常以米为单位。该值用于过滤无效数据。

    range_max:
        float32 类型。激光雷达可检测到的最大距离,通常以米为单位。该值用于过滤无效数据。

    ranges:
        float32[] 数组。存储每个扫描点的距离值,通常以米为单位。数组中的每个元素代表从激光雷达到障碍物的距离。

    intensities:
    float32[] 数组。存储每个扫描点的强度值,表示反射回来的信号强度。这个字段并不是所有激光雷达都支持或使用的。

小车的贴一下实际获取数据如下

header:stamp:sec: 1737861564nanosec: 600000000frame_id: laser_frame
angle_min: -3.1415927410125732
angle_max: 3.1415927410125732
angle_increment: 0.01745329238474369
time_increment: 0.0
scan_time: 0.0
range_min: 0.11999999731779099
range_max: 8.0
ranges:
- 1.0069999694824219
- 1.0269999504089355
- 1.0880000591278076
- 1.1549999713897705
- 1.2380000352859497
- 1.3289999961853027
- 1.50600004196167
- 0.9179999828338623
- 0.9210000038146973
- 1.4880000352859497
- 1.4830000400543213
- 1.4769999980926514
- 1.468999981880188
- 1.4670000076293945
- 1.3170000314712524
- 1.4570000171661377
- 1.4509999752044678
- 1.4459999799728394
- 1.440999984741211
- 1.4390000104904175
- 1.437000036239624
- 1.434000015258789
- 1.4329999685287476
- 1.4329999685287476
- 1.4329999685287476
- 1.4329999685287476
- 1.1959999799728394
- 1.1779999732971191
- 1.1759999990463257
- 1.1720000505447388
- 0.12200000137090683
- 0.13300000131130219
- 0.13300000131130219
- 0.0
- 0.03099999949336052
- 1.4450000524520874
- 1.4479999542236328
- 1.4520000219345093
- 0.847000002861023
- 0.8130000233650208
- 0.7940000295639038
- 0.7979999780654907
- 0.8029999732971191
- 0.8050000071525574
- 0.8050000071525574
- 0.8090000152587891
- 0.8240000009536743
- 1.5520000457763672
- 1.562999963760376
- 1.5729999542236328
- 1.593999981880188
- 1.6030000448226929
- 1.6130000352859497
- 1.6349999904632568
- 1.6349999904632568
- 1.6579999923706055
- 1.6790000200271606
- 1.690999984741211
- 1.7170000076293945
- 0.6190000176429749
- 0.6159999966621399
- 0.6330000162124634
- 0.6779999732971191
- 0.9139999747276306
- 0.890999972820282
- 0.8830000162124634
- 0.8709999918937683
- 0.8410000205039978
- 0.6729999780654907
- 0.6650000214576721
- 0.6510000228881836
- 0.6460000276565552
- 0.6389999985694885
- 0.6190000176429749
- 0.6119999885559082
- 0.6039999723434448
- 0.5929999947547913
- 0.5870000123977661
- 0.5809999704360962
- 0.5699999928474426
- 0.5649999976158142
- 0.5600000023841858
- 0.550000011920929
- 0.5460000038146973
- 0.5410000085830688
- 0.5239999890327454
- 0.5230000019073486
- '...'
intensities:
- 154.0
- 154.0
- 155.0
- 87.0
- 78.0
- 78.0
- 124.0
- 177.0
- 166.0
- 170.0
- 171.0
- 175.0
- 175.0
- 170.0

 

二 激光雷达避障

小车连接上代理,运行程序,小车上的雷达扫描设定范围内是否有障碍物,有障碍物则会根据障碍物的位置,自动调整速度,使其自身避开障碍物。通过动态参数调节器可以调整雷达检测的范围和避障检测的距离等参数。

src/yahboomcar_laser/yahboomcar_laser/目录下新建文件laser_Avoidance.py

代码如下:

#ros lib
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan #激光雷达消息类型
import os
import sys#commom lib
import math
import numpy as np
import time
from time import sleep
from yahboomcar_laser.common import *
print ("improt done")
RAD2DEG = 180 / math.pi #弧度转角度class laserAvoid(Node):def __init__(self,name):super().__init__(name)#create a sub  订阅激光雷达数据的主题 /scanself.sub_laser = self.create_subscription(LaserScan,"/scan",self.registerScan,1)self.sub_JoyState = self.create_subscription(Bool,'/JoyState', self.JoyStateCallback,1)#订阅手柄控制状态的主题 #create a pub 发布机器人控制指令的主题self.pub_vel = self.create_publisher(Twist,'/cmd_vel',1)#declareparam 声明参数self.declare_parameter("linear",0.3)#线速度self.linear = self.get_parameter('linear').get_parameter_value().double_valueself.declare_parameter("angular",1.0)#角速度self.angular = self.get_parameter('angular').get_parameter_value().double_valueself.declare_parameter("LaserAngle",45.0)#激光雷达角度self.LaserAngle = self.get_parameter('LaserAngle').get_parameter_value().double_valueself.declare_parameter("ResponseDist",0.55)#响应距离self.ResponseDist = self.get_parameter('ResponseDist').get_parameter_value().double_valueself.declare_parameter("Switch",False)#开关self.Switch = self.get_parameter('Switch').get_parameter_value().bool_valueself.Right_warning = 0#存储各方向障碍物检测结果self.Left_warning = 0self.front_warning = 0self.Joy_active = False #手柄控制是否激活self.Moving = Falseself.ros_ctrl = SinglePID()#前面common的PID控制器self.timer = self.create_timer(0.01,self.on_timer)#定时器,每0.01秒调用on_timer()def on_timer(self):self.Switch = self.get_parameter('Switch').get_parameter_value().bool_valueself.angular = self.get_parameter('angular').get_parameter_value().double_valueself.linear = self.get_parameter('linear').get_parameter_value().double_valueself.LaserAngle = self.get_parameter('LaserAngle').get_parameter_value().double_valueself.ResponseDist = self.get_parameter('ResponseDist').get_parameter_value().double_value#手柄回调函数def JoyStateCallback(self, msg):if not isinstance(msg, Bool): returnself.Joy_active = msg.data#退出时发的指令    def exit_pro(self):cmd1 = "ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "cmd2 = '''"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"'''cmd = cmd1 +cmd2os.system(cmd)#激光雷达回调函数 :处理订阅到的雷达数据   def registerScan(self, scan_data):if not isinstance(scan_data, LaserScan): returnranges = np.array(scan_data.ranges)#数据转换self.Right_warning = 0self.Left_warning = 0self.front_warning = 0for i in range(len(ranges)):angle = (scan_data.angle_min + scan_data.angle_increment * i) * RAD2DEGif angle > 180: angle = angle - 360#60 means that the range of radar detection is set to 120 degrees#根据设定的雷达检测的角度和障碍物检测距离判断前、左、右是否有障碍物存在if 20 < angle < self.LaserAngle:if ranges[i] < self.ResponseDist*1.5:self.Left_warning += 1if -self.LaserAngle < angle < -20:if ranges[i] < self.ResponseDist*1.5:self.Right_warning += 1if abs(angle) <= 20:if ranges[i] <= self.ResponseDist*1.5: self.front_warning += 1if self.Joy_active or self.Switch == True: #手柄或者开关打开,则停止移动if self.Moving == True:self.pub_vel.publish(Twist())self.Moving = not self.Movingreturnself.Moving = Truetwist = Twist()#根据检测到障碍物,发布小车的指令让小车避开障碍物if self.front_warning > 10 and self.Left_warning > 10 and self.Right_warning > 10:print ('1, there are obstacles in the left and right, turn right')twist.linear.x = self.lineartwist.angular.z = -self.angularself.pub_vel.publish(twist)sleep(0.2)elif self.front_warning > 10 and self.Left_warning <= 10 and self.Right_warning > 10:print ('2, there is an obstacle in the middle right, turn left')twist.linear.x = self.lineartwist.angular.z = self.angularself.pub_vel.publish(twist)sleep(0.2)if self.Left_warning > 10 and self.Right_warning <= 10:twist.linear.x = self.lineartwist.angular.z = -self.angularself.pub_vel.publish(twist)sleep(0.5)elif self.front_warning > 10 and self.Left_warning > 10 and self.Right_warning <= 10:print ('4. There is an obstacle in the middle left, turn right')twist.linear.x = self.lineartwist.angular.z = -self.angular#self.pub_vel.publish(twist)sleep(0.2)if self.Left_warning <= 10 and self.Right_warning > 10:twist.linear.x = self.lineartwist.angular.z = self.angularself.pub_vel.publish(twist)sleep(0.5)elif self.front_warning > 10 and self.Left_warning < 10 and self.Right_warning < 10:print ('6, there is an obstacle in the middle, turn left')twist.linear.x = self.lineartwist.angular.z = self.angularself.pub_vel.publish(twist)sleep(0.2)elif self.front_warning < 10 and self.Left_warning > 10 and self.Right_warning > 10:print ('7. There are obstacles on the left and right, turn right')twist.linear.x = self.lineartwist.angular.z = -self.angularself.pub_vel.publish(twist)sleep(0.4)elif self.front_warning < 10 and self.Left_warning > 10 and self.Right_warning <= 10:print ('8, there is an obstacle on the left, turn right')twist.linear.x = self.lineartwist.angular.z = -self.angularself.pub_vel.publish(twist)sleep(0.2)elif self.front_warning < 10 and self.Left_warning <= 10 and self.Right_warning > 10:print ('9, there is an obstacle on the right, turn left')twist.linear.x = self.lineartwist.angular.z = self.angularself.pub_vel.publish(twist)sleep(0.2)elif self.front_warning <= 10 and self.Left_warning <= 10 and self.Right_warning <= 10:print ('10, no obstacles, go forward')twist.linear.x = self.lineartwist.angular.z = 0.0self.pub_vel.publish(twist)#self.pub_vel.publish(twist)def main():rclpy.init()laser_avoid = laserAvoid("laser_Avoidance")print ("start it")try:rclpy.spin(laser_avoid)except KeyboardInterrupt:passfinally:laser_avoid.exit_pro()laser_avoid.destroy_node()rclpy.shutdown()

我加了注释,主要逻辑是收到激光雷达数据后回调处理registerScan,通过发布/cmd_vel 来控制小车避障。

小车运行:

ros2 run yahboomcar_laser laser_Avoidance

6, there is an obstacle in the middle, turn left
6, there is an obstacle in the middle, turn left
6, there is an obstacle in the middle, turn left
6, there is an obstacle in the middle, turn left
6, there is an obstacle in the middle, turn left
2, there is an obstacle in the middle right, turn left
9, there is an obstacle on the right, turn left
10, no obstacles, go forward
10, no obstacles, go forward
10, no obstacles, go forward
10, no obstacles, go forward
10, no obstacles, go forward

控制参数调整

ros2 run rqt_reconfigure rqt_reconfigure

以上的参数说明如下:

  • linera:线速度大小

  • angular:角速度大小

  • LaserAngle:雷达检测角度

  • ResponseDist:障碍物检测距离,当检测的物体在该范围内,则认为是障碍物

  • Switch:玩法开关

我测试了下,大一些障碍物能识别到,垃圾桶、鞋盒子这种。椅子腿细一些的不太行会撞上去。

太矮的也不行。能从房间自主识别到门口出去。这算是小车第一次不是根据键盘控制自主运行,虽然没一会就回遇到障碍物困住了。避障的逻辑处理的相对简单些。

从节点图来看,小车的激光雷达发布的数据被程序节点laser_Avoidance接受,通过/cmd_vel 控制小车运动避障。

至此。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/68290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习 ---逻辑回归

逻辑回归是属于机器学习里面的监督学习&#xff0c;它是以回归的思想来解决分类问题的一种非常经典的二分类分类器。由于其训练后的参数有较强的可解释性&#xff0c;在诸多领域中&#xff0c;逻辑回归通常用作 baseline 模型&#xff0c;以方便后期更好的挖掘业务相关信息或提…

volatile之四类内存屏障指令 内存屏障 面试重点 底层源码

目录 volatile 两大特性 可见性 有序性 总结 什么是内存屏障 四个 CPU 指令 四大屏障 重排 重排的类型 为什么会有重排&#xff1f; 线程中的重排和可见性问题 如何防止重排引发的问题&#xff1f; 总结 happens-before 和 volatile 变量规则 内存屏障指令 写操作…

模拟电子技术-常用半导体器件

模拟电子技术-常用半导体器件 一、半导体基础知识二、PN结2.1 PN结简介2.2 PN结正向导电性2.2.1 正向电压2.2.2 反向电压2.2.3 PN结伏安特性 三、二极管3.1 二极管伏安特性曲线3.2 二极管参数和等效电路3.2.1 性能参数3.2.2 等效电路 3.3 二极管限幅和整流应用(正向特性)3.4 稳…

2024年博客之星主题创作|2024年蓝桥杯与数学建模年度总结与心得

引言 2024年&#xff0c;我在蓝桥杯编程竞赛和数学建模竞赛中投入了大量时间和精力&#xff0c;这两项活动不仅加深了我对算法、数据结构、数学建模方法的理解&#xff0c;还提升了我的解决实际问题的能力。从蓝桥杯的算法挑战到数学建模的复杂应用&#xff0c;我在这些竞赛中…

javascript-es6 (一)

作用域&#xff08;scope&#xff09; 规定了变量能够被访问的“范围”&#xff0c;离开了这个“范围”变量便不能被访问 局部作用域 函数作用域&#xff1a; 在函数内部声明的变量只能在函数内部被访问&#xff0c;外部无法直接访问 function getSum(){ //函数内部是函数作用…

使用eNSP配置GRE VPN实验

实验拓扑 实验需求 1.按照图示配置IP地址 2.在R1和R3上配置默认路由使公网区域互通 3.在R1和R3上配置GRE VPN&#xff0c;使两端私网能够互相访问&#xff0c;Tunne1口IP地址如图 4.在R1和R3上配置RIPv2来传递两端私网路由 GRE VPN配置方法&#xff1a; 发送端&#xff1a; …

Ansible自动化运维实战--script、unarchive和shell模块(6/8)

文章目录 一、script模块1.1、功能1.2、常用参数1.3、举例 二、unarchive模块2.1、功能2.2、常用参数2.3、举例 三、shell模块3.1、功能3.2、常用参数3.3、举例 一、script模块 1.1、功能 Ansible 的 script 模块允许你在远程主机上运行本地的脚本文件&#xff0c;其提供了一…

大数据Hadoop入门1

目录 相关资料 第一部分 1.课程内容大纲和学习目标 2.数据分析和企业数据分析方向 3.数据分析基本流程步骤 4.大数据时代 5.分布式和集群 6.Linux操作系统概述 7.VMware虚拟机概念与安装 8.centos操作系统的虚拟机导入 9.VMware虚拟机常规使用、快照 第二部分 1.课…

项目概述与规划 (I)

项目概述与规划 (I) JavaScript的学习已经接近尾声了&#xff0c;最后我们将通过一个项目来讲我们在JavaScript中学习到的所有都在这个项目中展现出来&#xff0c;这个项目的DEMO来自于Udemy中的课程&#xff0c;作者是Jonas Schmedtmann&#xff1b; 项目规划 项目步骤 用户…

项目集成RabbitMQ

文章目录 1.common-rabbitmq-starter1.创建common-rabbitmq-starter2.pom.xml3.自动配置1.RabbitMQAutoConfiguration.java2.spring.factories 2.测试使用1.创建common-rabbitmq-starter-demo2.目录结构3.pom.xml4.application.yml5.TestConfig.java 配置交换机和队列6.TestCon…

RK3568 adb使用

文章目录 一、adb介绍**ADB 主要功能****常用 ADB 命令****如何使用 ADB****总结** 二、Linux下载adb**方法 1&#xff1a;使用包管理器&#xff08;适用于 Ubuntu/Debian 系统&#xff09;****方法 2&#xff1a;通过 Snap 安装&#xff08;适用于支持 Snap 的系统&#xff09…

STM32项目分享:智能宠物喂食系统(升级版)

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; STM32智能宠物喂食系统(升级版) &#xff08;资…

软件测试 —— 性能测试(jmeter)

软件测试 —— 性能测试&#xff08;jmeter&#xff09; 什么是jmeter安装jmeterjmeter常用组件线程组取样器结果树 我们之前学习了接口测试工具Postman&#xff0c;我们今天要学习的是性能测试工具——jmeter 什么是jmeter Apache JMeter 是一个开源的性能测试工具&#xff…

电阻补偿OTA的噪声分析

上文&#xff08;补偿电阻对ota零极点的影响-CSDN博客&#xff09;分析了补偿电阻对五管OTA零极点的影响&#xff0c;该篇借分析电阻补偿OTA的噪声来串联复习下噪声章节的一些基础概念。 1.噪声分析 辅助定理 开始分析OTA噪声之前&#xff0c;先引入一个辅助定理&#xff08;R…

从CRUD到高级功能:EF Core在.NET Core中全面应用(四)

初识表达式树 表达式树&#xff1a;是一种可以描述代码结构的数据结构&#xff0c;它由一个节点组成&#xff0c;节点表示代码中的操作、方法调用或条件表达式等&#xff0c;它将代码中的表达式转换成一个树形结构&#xff0c;每个节点代表了代码中的操作例如&#xff0c;如果…

C语言初阶力扣刷题——349. 两个数组的交集【难度:简单】

1. 题目描述 力扣在线OJ题目 给定两个数组&#xff0c;编写一个函数来计算它们的交集。 示例&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 输入&#xff1a;nums1 [4,9,5], nums2 [9,4,9,8,4] 输出&#xff1a;[9,4] 2. 思路 直接暴力…

在Qt中实现点击一个界面上的按钮弹窗到另一个界面

文章目录 步骤 1&#xff1a;创建新窗口类步骤 2&#xff1a;设计窗口的 UI步骤 3&#xff1a;设计响应函数 以下是一个完整的示例&#xff0c;展示在Qt中如何实现在一个窗口中通过点击按钮弹出一个新窗口。 步骤 1&#xff1a;创建新窗口类 假设你要创建一个名为 WelcomeWidg…

dm8在Linux环境安装精简步骤说明(2024年12月更新版dm8)

dm8在Linux环境安装详细步骤 - - 2025年1月之后dm8 环境介绍1 修改操作系统资源限制2 操作系统创建用户3 操作系统配置4 数据库安装5 初始化数据库6 实例参数优化7 登录数据库配置归档与备份8 配置审计9 创建用户10 屏蔽关键字与数据库兼容模式11 jdbc连接串配置12 更多达梦数据…

Spring MVC 综合案例

目录 一. 加法计算器 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 3. 服务器端代码 4. 运行测试 二. 用户登录 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 (1) 登录界面接口 (2) 首页接口 3. 服务器端代码 4. 运行测试 三. 留言板 1. 准备…

神经网络|(一)加权平均法,感知机和神经元

【1】引言 从这篇文章开始&#xff0c;将记述对神经网络知识的探索。相关文章都是学习过程中的感悟和理解&#xff0c;如有雷同或者南辕北辙的表述&#xff0c;请大家多多包涵。 【2】加权平均法 在数学课本和数理统计课本中&#xff0c;我们总会遇到求一组数据平均值的做法…