亚博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;以方便后期更好的挖掘业务相关信息或提…

使用 Vue 3 的 watchEffect 和 watch 进行响应式监视

Vue 3 的 Composition API 引入了 <script setup> 语法&#xff0c;这是一种更简洁、更直观的方式来编写组件逻辑。结合 watchEffect 和 watch&#xff0c;我们可以轻松地监视响应式数据的变化。本文将介绍如何使用 <script setup> 语法结合 watchEffect 和 watch&…

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

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

ES6+新特性,var、let 和 const 的区别

在 JavaScript 中&#xff0c;var、let 和 const 都用于声明变量&#xff0c;但它们有一些重要的区别&#xff0c;主要体现在 作用域、可变性和提升机制 等方面。 1. 作用域&#xff08;Scope&#xff09; var: var 声明的变量是 函数作用域&#xff0c;也就是说&#xff0c;它…

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

模拟电子技术-常用半导体器件 一、半导体基础知识二、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 稳…

01-02 三元组与七元组

01-02 三元组与七元组 好的&#xff01;以下是关于网络中的 三元组&#xff08;3-Tuple&#xff09; 和 七元组&#xff08;7-Tuple&#xff09; 的详细扩展说明&#xff0c;包括它们的组成、用途以及与五元组的对比。 1. 三元组&#xff08;3-Tuple&#xff09; 组成 三元组…

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

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

javascript-es6 (一)

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

数据的秘密:如何用大数据分析挖掘商业价值

数据的秘密&#xff1a;如何用大数据分析挖掘商业价值 在这个数据爆炸的时代&#xff0c;我们每天都在产生、存储和处理着海量的数据。然而&#xff0c;仅仅拥有数据并不等于拥有价值。就像拥有一座金矿&#xff0c;不开采和提炼&#xff0c;最终只是一堆毫无用处的石头。如何…

使用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.课…

【Elasticsearch】doc_values 可以用于查询操作

确实&#xff0c;doc values 可以用于查询操作&#xff0c;尽管它们的主要用途是支持排序、聚合和脚本中的字段访问。在某些情况下&#xff0c;Elasticsearch 也会利用 doc values 来执行特定类型的查询。以下是关于 doc values 在查询操作中的使用及其影响的详细解释&#xff…

TS开发的类型索引目录

TypeScript 相关知识整理 一、相关文档 Web API 类型&#xff1a;https://developer.mozilla.org/zh-CN/docs/Web/APIHTML DOM类型&#xff1a;https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElementReact类型文档&#xff1a;https://react-typescript-cheatsheet.…

Python 对列表进行排序的 5 种方法

在 Python 中&#xff0c;排序是一个非常常见且重要的操作&#xff0c;尤其是对列表的排序。Python 提供了多种方法来实现排序操作&#xff0c;从内置函数到自定义排序逻辑&#xff0c;都可以方便地满足不同的需求。以下将介绍 Python 对列表进行排序的 5 种方法&#xff0c;并…

2025年1月26日(超声波模块:上拉或下拉电阻)

添加上拉或下拉电阻是在电子电路设计和嵌入式系统编程中常用的一种技术手段&#xff0c;下面为你详细解释其含义、作用和应用场景。 基本概念 在数字电路里&#xff0c;引脚的电平状态通常有高电平&#xff08;逻辑 1&#xff09;和低电平&#xff08;逻辑 0&#xff09;两种…

项目概述与规划 (I)

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

深入探讨Web应用开发:从前端到后端的全栈实践

目录 引言 1. Web应用开发的基本架构 2. 前端开发技术 HTML、CSS 和 JavaScript 前端框架与库 响应式设计与移动优先 3. 后端开发技术 Node.js&#xff08;JavaScript后端&#xff09; Python&#xff08;Flask和Django&#xff09; Ruby on Rails Java&#xff08;S…

docker如何查看容器启动命令(已运行的容器)

docker ps 查看正在运行的容器 该命令主要是为了详细展示查看运行时的command参数 # 通过docker --no-trunc参数来详细展示容器运行命令 docker ps -a --no-trunc | grep <container_name>通过docker inspect命令 使用docker inspect&#xff0c;但是docker inspect打…

为AI聊天工具添加一个知识系统 之62 详细设计 之3:AI操作系统 之1

本文要点 要点 考虑下面的一组整理&#xff08;重点看一下用词、分组分行分类以及 排列组合&#xff09;&#xff0c;看看应该如何将他们组织到本项目程序中&#xff0c;是否同时还丰富了前面讨论的AI操作系统和Lexicographer 程序的内容。 1、工作任务&#xff1a;运行时编译…