Jetson Nano之ROS入门 -- YOLO目标检测与定位
文章目录
- 前言
- 一、yolo板端部署推理
- 二、目标深度测距
- 三、目标方位解算与导航点设定
- 1、相机成像原理
- 2、Python实现目标定位
- 总结
前言

Darknet_ros是一个基于ROS(机器人操作系统)的开源深度学习框架,它使用YOLO算法进行目标检测和识别。YOLO算法是一种实时物体检测算法,它能够在单个前向传递中同时检测图像中的多个目标。
Darknet_ros将YOLO算法集成到ROS中,使得机器人可以实时地检测和识别周围环境中的物体。它提供了一些ROS节点和服务,可以在ROS系统中轻松使用YOLO算法进行目标检测和识别。同时,它还提供了一些示例程序,帮助用户快速了解如何在ROS中使用深度学习算法进行机器人视觉任务。
Darknet_ros的优点是速度快、准确度高,可以在实时应用中使用。它还可以在不同的机器人项目中使用,例如无人机、机器人车辆和机器人臂等。
一、yolo板端部署推理
首先确认CUDA,OpenCV,cuDNN已安装,可以用命令查看CUDA是否安装
ls -l /usr/local | grep cuda
查看opencv版本
opencv_version
接着从gitee上克隆darknet_ros源码下来
git clone https://gitee.com/bluesky_ryan/darknet_ros.git
按照如下指引下载权重文件,将下载的weights权重文件放在
darknet_ros/darknet_ros/yolo_network_config/weights
cd catkin_workspace/src/darknet_ros/darknet_ros/yolo_network_config/weights/COCO data set (Yolo v2):wget http://pjreddie.com/media/files/yolov2.weightswget http://pjreddie.com/media/files/yolov2-tiny.weightsVOC data set (Yolo v2):wget http://pjreddie.com/media/files/yolov2-voc.weightswget http://pjreddie.com/media/files/yolov2-tiny-voc.weightsYolo v3:wget http://pjreddie.com/media/files/yolov3.weightswget http://pjreddie.com/media/files/yolov3-voc.weights
使用jetson nano自带的opencv4.x编译会报错,需要安装opencv3.4.2版本,配置opencv cmake桥接目录
sudo vim /opt/ros/melodic/share/cv_bridge/cmake/cv_bridgeConfig.cmake

接着cd到工作空间下,编译darknet_ros功能包
catkin_make -DCATKIN_WHITELIST_PACKAGES="darknet_ros"
配置launch文件图像输入的topic,可以打开摄像头节点后用rostopic命令查看
rostopic list
我的RGB图像发布的话题是/camera/rgb/image_raw,接着配置yolo网络参数,我用的是yolov2-tiny权重文件,检查一下ros.yaml文件也要配置成/camera/rgb/image_raw

打开终端,source一下工作空间下ros的环境变量
source /catkin_ws/devel/setup.bash
首先启动相机节点,需要有/camera/rgb/image_raw的话题输出,再运行darknet_ros 节点
roslaunch darknet_ros darknet_ros.launch
接着会弹出一个窗口,展示识别到的物体

二、目标深度测距
目标的深度测距的实现我们可以结合darknet_ros功能包,我这里用的是RGBD相机,型号是Astra_Pro,深度相机节点在启动后会输出深度图的话题
rostopic list/camera/depth/image_rect_raw
查看一下darknet_ros功能包的msg消息文件,下面是BoundingBoxes.msg消息文件
Header header
Header image_header
BoundingBox[] bounding_boxes
下面是BoundingBox.msg消息文件
float64 probability
int64 xmin
int64 ymin
int64 xmax
int64 ymax
int16 id
string Class
用rostopic info命令可以看到/darknet_ros/bounding_boxes话题的具体内容
rostopic info /darknet_ros/bounding_boxesType: darknet_ros_msgs/BoundingBoxesPublishers: * /darknet_ros (http://localhost:43545/)
这个话题就是我们需要的目标检测框的信息,将目标检测框输出到深度图我们就可以读取目标的深度
首先创建一个scripts文件夹,创建ObjectLocation.py文件
touch ObjectLocation.py
目标深度测距的代码思路首先导入rospy、cv2、numpy、darknet_ros_msgs等包,创建一个目标定位的类,实例化类的一些参数,订阅深度图话题并转化为深度矩阵,订阅目标检测框将坐标信息对齐到深度图中,按照3x3滑动窗口遍历检测框进行中值滤波,最后取中心深度作为目标的估计深度,并发布距离话题
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
from darknet_ros_msgs.msg import BoundingBoxes
import numpy as np
from scipy.ndimage import median_filter
import mathclass ObjectLocation:def __init__(self):self.bridge = CvBridge()self.depth_image = Noneself.bounding_boxes = Noneself.probability = 0self.Class = Noneself.distance = 0self.centerx = 0self.centery = 0self.x_h = 0self.y_h = 0self.w_h = 0cv2.destroyAllWindows()'''get depth distance from found object rect'''def depthDistanceFromCoordinate(self, data):try:self.depth_image = self.bridge.imgmsg_to_cv2(data, "passthrough")depth_array = np.array(self.depth_image, dtype=np.float32)filter_depth_array = np.zeros_like(depth_array)if self.bounding_boxes != None:for bounding_box in self.bounding_boxes:# bounding box coordinates # less than 0 and larger than width or heightxmin = 0 if bounding_box.xmin < 0 else bounding_box.xminxmax = bounding_box.xmax if bounding_box.xmax < len(depth_array[0]) else len(depth_array[0])ymin = 0 if bounding_box.ymin < 0 else bounding_box.yminymax = bounding_box.ymax if bounding_box.ymax < len(depth_array) else len(depth_array)dep_aver = 0filter_depth_array = median_filter(depth_array, size=(3, 3))dep_aver = filter_depth_array[int((ymin + ymax) / 2), int((xmin + xmax) / 2)]self.probability = bounding_box.probabilityself.Class = bounding_box.Classself.distance = dep_averself.centerx = (xmin + xmax) / 2self.centery = (ymin + ymax) / 2rospy.loginfo("Class=%s, Probability=%f, Distance=%f", self.Class, self.probability, self.distance)pub = rospy.Publisher('/darknet_ros/distance', self.distance, queue_size = 100)pub.publish(self.distance)except Exception as e:print(e)def bbox_callback(self, msg):self.bounding_boxes = msg.bounding_boxesif __name__ == '__main__':od = ObjectLocation()rospy.init_node('ObjectLocation', anonymous=True)rospy.Subscriber('/darknet_ros/bounding_boxes', BoundingBoxes, od.bbox_callback)rospy.Subscriber('/camera/depth/image_rect_raw', Image, od.depthDistanceFromCoordinate)rate = rospy.Rate(10)rate.sleep()rospy.spin()
三、目标方位解算与导航点设定
1、相机成像原理
我们需要根据相机内外参去解算目标的方位,相机内参外参原理参照下面链接,依据成像原理我们可以将在像素坐标系下的目标映射到相机坐标系
https://zhuanlan.zhihu.com/p/389653208
2、Python实现目标定位
运行标定相机的demo就可以得到相机的内参外参矩阵,我的是出厂就标定好的附带内参矩阵,放在
home/wheeltec/.ros/camera_info/camera.yaml 文件里,内参矩阵是相机出厂时就决定了的
image_width: 640
image_height: 480
camera_name: camera
camera_matrix:rows: 3cols: 3data: [ 581.88585, 0. , 314.2472 ,0. , 592.27138, 210.27091,0. , 0. , 1. ]
camera_model: plumb_bob
distortion_model: plumb_bob
distortion_coefficients:rows: 1cols: 5data: [0.221666, -0.575455, -0.014215, 0.003895, 0.000000]
rectification_matrix:rows: 3cols: 3data: [ 1., 0., 0.,0., 1., 0.,0., 0., 1.]
projection_matrix:rows: 3cols: 4data: [ 591.88599, 0. , 315.96148, 0. ,0. , 603.39893, 205.72873, 0. ,0. , 0. , 1. , 0. ]
相机的外参矩阵则要确定机器人坐标系下的相机位姿,才能将目标方位解算到机器人bse_link坐标系下。用Python程序设定导航目标点的主要通过ROS中名为"move_base"的动作服务器(Action Server),负责接收和处理导航目标,我们将导航目标点位姿信息解算好,发送到move_base节点即可。
在原有的ObjectLocation.py上导入actionlib、tf、move_base_msgs等包,使用矩阵求逆加内积来将像素坐标系下的目标位置映射到相机坐标系,再通过tf坐标变换映射到机器人坐标系,实例化导航目标点,将目标点位姿发送到move_base节点,等待动作服务器响应即可
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
from darknet_ros_msgs.msg import BoundingBoxes
import numpy as np
from scipy.ndimage import median_filter
import actionlib
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
import tf.transformations as tr
import mathclass ObjectLocation:def __init__(self):self.bridge = CvBridge()self.depth_image = Noneself.bounding_boxes = Noneself.probability = 0self.Class = Noneself.distance = 0self.centerx = 0self.centery = 0self.x_h = 0self.y_h = 0self.w_h = 0cv2.destroyAllWindows()'''get depth distance from found object rect'''def depthDistanceFromCoordinate(self, data):try:self.depth_image = self.bridge.imgmsg_to_cv2(data, "passthrough")depth_array = np.array(self.depth_image, dtype=np.float32)filter_depth_array = np.zeros_like(depth_array)if self.bounding_boxes != None:for bounding_box in self.bounding_boxes:# bounding box coordinates # less than 0 and larger than width or heightxmin = 0 if bounding_box.xmin < 0 else bounding_box.xminxmax = bounding_box.xmax if bounding_box.xmax < len(depth_array[0]) else len(depth_array[0])ymin = 0 if bounding_box.ymin < 0 else bounding_box.yminymax = bounding_box.ymax if bounding_box.ymax < len(depth_array) else len(depth_array)dep_aver = 0filter_depth_array = median_filter(depth_array, size=(3, 3))dep_aver = filter_depth_array[int((ymin + ymax) / 2), int((xmin + xmax) / 2)]self.probability = bounding_box.probabilityself.Class = bounding_box.Classself.distance = dep_averself.centerx = (xmin + xmax) / 2self.centery = (ymin + ymax) / 2rospy.loginfo("Class=%s, Probability=%f, Distance=%f", self.Class, self.probability, self.distance)if self.Class == "pottedplant":fx = 581.88585fy = 592.27138cx = 314.2472cy = 210.27091K = np.array([[fx, 0., cx], [0., fy, cy], [0., 0., 1.]])point_pixel = np.array([self.centerx, self.centery, 1])point_camera = np.dot(np.linalg.inv(K), point_pixel) * self.distanceself.y_h = - point_camera[0] - 460self.x_h = point_camera[2] + 110orientation = tr.quaternion_from_euler(0, 0, math.atan2(self.y_h, self.x_h))self.w_h = orientation[3]rospy.loginfo("%s Goal location is x_h = %f, y_h = %f, w_h=%f", "pottedplant", self.x_h, self.y_h, self.w_h)self.movebase_callback()pub = rospy.Publisher('/darknet_ros/distance', self.distance, queue_size = 100)pub.publish(self.distance)except Exception as e:print(e)def movebase_callback(self):try:client = actionlib.SimpleActionClient('move_base', MoveBaseAction)client.wait_for_server()goal = MoveBaseGoal()goal.target_pose.header.frame_id = "base_link"goal.target_pose.pose.position.x = self.x_h * 4 / 5000goal.target_pose.pose.position.y = self.y_h * 4 / 5000goal.target_pose.pose.orientation.w = self.w_hclient.send_goal(goal)rospy.loginfo("move_base set goal success!")client.wait_for_result()except Exception as e:print("movebase_callback service failed")def bbox_callback(self, msg):self.bounding_boxes = msg.bounding_boxesif __name__ == '__main__':od = ObjectLocation()rospy.init_node('ObjectLocation', anonymous=True)rospy.Subscriber('/darknet_ros/bounding_boxes', BoundingBoxes, od.bbox_callback)rospy.Subscriber('/camera/depth/image_rect_raw', Image, od.depthDistanceFromCoordinate)rate = rospy.Rate(10)rate.sleep()rospy.spin()
下面是演示结果,其实还可以用其他滤波方法让深度估计更加精确,用重采样方法让方位估计更加精准

总结
darknet_ros软件包将ROS和YOLO很好的融合在一起,为机器人视觉任务开发提供了更多可能性。通过实时目标检测和识别,机器人能够感知和理解环境,实现人机交互,提高安全性,并在各种应用中发挥更智能和自主的作用。通过实时目标检测和识别,可以帮助机器人识别不同类型的物体,并根据目标物体的位置和特征来理解当前场景。这对于机器人在导航、路径规划和任务执行中具有重要意义。
相关文章:
Jetson Nano之ROS入门 -- YOLO目标检测与定位
文章目录 前言一、yolo板端部署推理二、目标深度测距三、目标方位解算与导航点设定1、相机成像原理2、Python实现目标定位 总结 前言 Darknet_ros是一个基于ROS(机器人操作系统)的开源深度学习框架,它使用YOLO算法进行目标检测和识别。YOLO算…...
【移动机器人运动规划】01 —— 常见地图基础 |图搜索基础
文章目录 前言相关代码整理:相关文章: 可视化网址:常用地图基础Occupancy grid mapOcto-mapVoxel hashingPoint cloud mapTSDF mapESDF mapFree-space RoadmapVoronoi Diagram Map 图搜索基础配置空间图搜索基本概念DijkstraAStarAstar的一些变种&#x…...
mongotop跟踪Mongodb集合读取和写入数据
版本控制 从 MongoDB 4.4 开始,MongoDB 数据库工具现在与 MongoDB 服务器分开发布,并使用自己的版本控制,初始版本为100.0.0. 此前,这些工具与 MongoDB 服务器一起发布,并使用匹配的版本控制。 兼容性 mongotop 版本…...
Linux中使用du命令来查看目录的大小
在Linux中,你可以使用du命令来查看目录的大小。下面是一些常用的du命令选项: -h:以人类可读的格式显示文件大小。-s:仅显示总大小,而不显示每个子目录的大小。-c:显示总大小,并在最后一行显示总…...
【Linux】进程篇Ⅰ:进程信息、进程状态、环境变量、进程地址空间
文章目录 一、概述二、查看进程信息1. 系统文件夹 /proc2. 用户级工具 ps3. getpid() 函数:查看进程 PID4. 用 kill 杀进程5. 进程优先级 二、进程状态分析0. 1. R (running) 运行状态2. S (sleeping) 休眠状态3. D (disk sleep) 不可中断的休眠状态4. T (stopped) …...
保护 TDengine 查询性能——3.0 如何大幅降低乱序数据干扰?
在时序数据库(Time Series Database)场景下,乱序数据的定义为:“时间戳(timestamp)不按照递增顺序到达数据库的数据。”虽然它的定义很简单,但时序数据库需要有相应的处理逻辑来保证数据存储时的…...
状态机实现N位按键消抖
状态机实现N位按键消抖 1、原理 利用状态机实现按键的消抖,具体的原理可参考 (50条消息) 基于FPGA的按键消抖_fpga 按键消抖_辣子鸡味的橘子的博客-CSDN博客 状态机简介: 状态机分类可以主要分为两类:moore和mealy 根据三段式状态机最后…...
uniapp自定义消息语音
需求是后端推送的消息APP要响自定义语音,利用官方插件,总结下整体流程 uniapp后台配置 因为2.0只支持uniapp自己的后台发送消息,所以要自己的后台发送消息只能用1.0 插件地址和代码 插件地址: link let isIos (plus.os.name "iOS&qu…...
k8s安装Jenkins
目录 编辑 一、环境准备 1.1 环境说明 二、安装nfs 2.1 安装NFS 2.2 创建NFS共享文件夹 2.3 配置共享文件夹 2.4 使配置生效 2.5 查看所有共享目录 2.6 启动nfs 2.7 其他节点安装nfs-utils 三、创建PVC卷 3.1 创建namespace 3.2 创建nfs 客户端sa授权 3.3 创建…...
共筑开源新长城 龙蜥社区走进开放原子校源行-清华大学站
6 月 28 日,以“聚缘于校,开源共行”为主题的 2023 年开放原子校源行活动在清华大学成功举行。本次活动由开放原子开源基金会和清华大学共同主办,来自各行业的 22 位大咖共聚校园共话开源。龙蜥社区技术专家边子政受邀进行技术分享࿰…...
Jgit 工具类 (代码检出、删除分支(本地、远程)、新建分支、切换分支、代码提交)
https://blog.csdn.net/qq_37203082/article/details/120327084 Jgit 工具类 (代码检出、删除分支(本地、远程)、新建分支、切换分支、代码提交)_jgit删除远程分支_CJ点的博客-CSDN博客 <!--JAVA操作GIT--><dependency><groupId>org.…...
什么是redux?如何在react 项目中使用redux?
redux 概念 redux是一种用于管理JavaScript应用程序的状态管理库。它可以与React、Augular、Vue等前端框架结合使用,但也可以纯在JavaScript应用程序中独立使用。redux遵循单项数据流的原则,通过一个全局的状态树来管理应用程序的状态,从而使…...
mysql的json处理
写在前面 需要注意,5.7以上版本才支持,但如果是生产环境需要使用的话,尽量使用8.0版本,因为8.0版本对json处理做了比较大的性能优化。你你可以使用select version();来查看版本信息。 本文看下MySQL的json处理。在正式开始让我们先…...
前端学习——Vue (Day8)
Vue3 create-vue搭建Vue3项目 注意要使用nodejs16.0版本以上,windows升级node可以西安使用where node查看本地node位置,然后到官网下载msi文件,在本地路径下安装即可 安装完可以使用node -v检查版本信息 项目目录和关键文件 组合式API - s…...
Windows环境下安装及部署Nginx
一、安装Nginx教程 1、官网下载地址:https://nginx.org/en/download.html 2、下载教程:选择Stable version版本下载到本地 3、下载完成后,解压放入本地非中文的文件夹中: 4、启动nginx:双击nginx.exe,若双击…...
使用AOP切面对返回的数据进行脱敏的问题
1.注解类 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** Author: xiaoxin* Date: 2023/7/21 17:15*/ Retention(RetentionPolicy.RUNTIME) Targe…...
TDengine时区设置
一般来说,时序数据就是带有时间序列属性的数据。在处理时序数据时,TDengine有着自己独特的方式。但是如果没有正确理解TDengine在写入和查询上的行为,极可能会因为配置了错误的时区(timezone),而导致写入和…...
站外引流效果差?一文带你搞懂解海外主流社交媒体算法!
在流量成本越来越高的当下,无论是平台卖家还是独立站卖家都在努力拓展流量渠道。站外引流是推动业务增长的关键策略,很多卖家会把重点放在内容营销上,但其实除了做好内容之前,了解社交媒体的算法才能让营销效果最大化。 01.Faceb…...
css 动画之旋转视差
序:网上看到的一个例子,做一下 效果图: 代码: <style>.content{width: 300px;height: 300px;margin: 139px auto;display: grid;grid-template-columns: repeat(3,1fr);grid-template-rows: repeat(3,1fr);grid-template:…...
maven项目、springboot项目复制文件进来后没反应、不编译解决方法
问题如下 把文件复制进springboot项目后,没反应,不编译。 解决 在maven工具框中选择compile工具,运行即可。...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
