简介:
首先在ubuntu创建yolov8环境,yolov8负责识别物体,再部署ros系统,ros系统负责通信板块,创建自己需要的自定义消息类型,发布和接受所检测到物体的坐标位置。
注意:本篇代码均使用python代码。
配置环境:
创建yolov8环境:
在Ubuntu下载anaconda,然后创建一个yolov8的环境后进入该环境,下载pytorch。
我下载的是cpu版本的pytorch,注意pytorch要和anaconda兼容。
具体可参考:https://blog.csdn.net/Arcofcosmos/article/details/112859567
创建ros空间:
在Ubuntu上打开终端,我是cd到home目录后进行创建。
在终端运行:
mkdir -p demo03_ws/src
进入工作空间:
cd demo03_ws
对工作空间初始化:
catkin_make
安装vscode:
参考:023集成开发环境_VScode下载与安装_Chapter1-ROS概述与环境搭建_哔哩哔哩_bilibili
安装完成后,激活yolov8环境,进入工作空间后,用vscode打开。
在终端内运行:
conda activate yolov8
cd demo03_ws/
code .
安装yolov8的包。
在集成终端内运行:
pip install ultralytics
到这里环境已经搭好了。
编写代码:
创建功能包:
首先点击src,右键点击create catkin package。
输入你要创建的包名。
按回车键后,导入依赖的包,从左到右依次为c++,python,消息类型的包。
在功能包下新建一个scripts文件夹,专门为python文件存放;src文件夹专门存放c++文件。
注意python文件以p.py结尾,而c++文件以.cpp结尾。
创建自定义消息类型:
创建文件:
因为我们发布接受的消息需要四个坐标点,所以我们需要自定义这样一个消息类型。
在功能包下新建msg目录,添加文件selfmsg.msg,可以自定义。
如图为我们需要的四个坐标。
配置文件:
注意:可以在需要修改的文件按ctrl+f进行搜索查找。
点进package.xml。
添加以下两行代码:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
message_generation是用于编译msg文件。
message_runtime是用于运行msg文件。
点进CMakeLists.txt。
添加message_generation。
表明你编译plumbing_pub_sub这个功能包需要依赖于message_generation
放开add_message_files下的注释,添加我们新建的消息文件,即selfmsg.msg。
注意:这里的Person.msg忽略。
把generate_messages以下几行的注释解开,无需修改。
这几行的作用是编译我们的selfmsg.msg功能包也需要依赖与std_msgs标准消息,因为我们复合的自定义消息的每个字段是依赖于标准消息的。
放开catkin_package下第三行的注释,并添加message_runtime
下面解释catkin_package的作用。
前面所说,编译plumbing_sub_pub功能包需要依赖于前面find_package下的包,而find_package下的包是依赖于catkin_package下的这些功能包。
总结:find_package是编译依赖,catkin_package是运行依赖。
编译:
直接编译文件,运行成功后会产生两个中间文件。
1.这个头文件是用c++所调用的。
2.这个头文件是用python所调用的。
注意:调用文件要使用绝对路径。
实现发布方:
发布方框架参考:045话题通信(python)1_发布方框架_Chapter2-ROS通信机制_哔哩哔哩_bilibili
在scripts新建python文件,我这里为demo05_pub_p.py,顺便一起把待会订阅方的文件创建了,为demo06_sub_p.py。
代码板块(含代码详细解析):
#! /usr/bin/env python
#第一行不能省
#1.导包
import rospy
from ultralytics import YOLO
import cv2
from plumbing_pub_sub.msg import selfmsg
#导入yolov8的权重文件,需自行下载放入虚拟机
model = YOLO("/home/kirby/yolov8_ws/yolov8n.pt")
#从摄像头读取
result = model.predict(source=0,show=True,stream=True)
#可以通过""内加如资源的绝对路径读取
# result = model.predict(source="",show=True)
if __name__ == "__main__":
#初始化ros节点
rospy.init_node("yolo_pub")
#实例化发布者对象,location为话题,用于发布方和订阅方连接
pub = rospy.Publisher("location", selfmsg , queue_size=10)
#设置循环
while not rospy.is_shutdown():
#对每一帧进行分析
for r in result:
i = 0
a= list()
b= list()
#a列表存储一帧的每个物体的置信度
a = r.boxes.conf.tolist()
#b列表存储每一帧的每个物体的四个坐标点信息
b = r.boxes.xyxy.tolist()
#目的是选组置信度最大的物体
while i < len(a):
Max = max(a)
#获取置信度最大物体的下标索引
MaxI = a.index(Max)
#创建消息对象
msg = selfmsg()
#赋值
msg.x1 = int(b[MaxI][0])
msg.x2 = int(b[MaxI][1])
msg.y1 = int(b[MaxI][2])
msg.y1 = int(b[MaxI][3])
#发布
pub.publish(msg)
i+=1
实现订阅方:
订阅方框架参考:047话题通信(python)3_订阅方实现_Chapter2-ROS通信机制_哔哩哔哩_bilibili
代码板块(含代码详细解析):
#! /usr/bin/env python
#第一行不可省
#导包
#from ultralytics import YOLO
#import cv2
import rospy
from plumbing_pub_sub.msg import selfmsg
#回调函数(处理订阅消息)
def doYolo(msg):
rospy.loginfo("receive:%s,%s,%s,%s",msg.x1,msg.x2,msg.y1,msg.y2)
if __name__ == "__main__":
#初始化ros节点
rospy.init_node("yolo_sub")
#实例化订阅者对象
sub = rospy.Subscriber("location", selfmsg , doYolo ,queue_size=10)
#设置循环调用回调函数
rospy.spin()
实现和结果:
实现:
打开三个终端,每个终端都要source环境变量:
source devel/setup.bash
第一个终端输入:
roscore
第二个终端输入:
rosrun plumbing_pub_sub demo05_pub_p.py
第三个终端输入:
rosrun plumbing_pub_sub demo06_sub_p.py
输入发布方前确保摄像头打开。
从左到右第四个图标右键连接。
结果:
这里摄像头就不进行展示了。