基于turtlebot的智能机器人物体识别及目标追踪系统
摘要
智能机器人的发展已经渗透到人们日常生活的各方各面,日益在人们日常生活中发挥着重要的作用,并且智能机器人跟踪技术是机器人研究领域的一个重要研究方向。云计算正不断应用到各种场景,传统机器人的计算存储等能力受限于其板载设备,将云计算与机器人结合用于提升机器人能力是机器人未来发展的趋势之一。
本毕业设计课题基于turtlebot实现机器人目标追踪,需要将物体识别迁移到云服务器,云服务实时的通过对图像计算做出移动指令,最终实现目标追踪。
采用机器人操作系统(ROS)与Client/Server(客户端/服务端)通信相结合来实现本课题。首先客户端用来接受kinenct所采集的图像,将物体识别到服务器;其次服务器端实时的对图像进行计算处理,利用机器人跟踪技术,并将产生的控制命令返回给客户端,最终远程实现对机器人的跟踪控制。
关键词:目标跟踪;ROS机器人程序设计;C/S通信框架;远程控制;云机器人
Research and Prototype Realization of Object Recognition and Tracking Technology for Intelligent
Abstract
The development of intelligent robots has penetrated into the daily aspects of people’s daily life, and increasingly plays an important role in people’s daily life, and intelligent robot tracking technology is an important research direction in the field of robot research. Cloud computing is being applied to a variety of scenes, the traditional robot computing storage capacity is limited by its onboard equipment, cloud computing and robot combination for the promotion of robot capability is one of the future development trend of the robot.
Based on turtlebot to achieve the robot target tracking, the need to migrate object recognition to the cloud server, cloud service real-time through the image calculation to make mobile instructions, and ultimately achieve the target tracking.
I use the robot operating system (ROS) and Client / Server (client / server) communication to achieve this problem. First, the client is used to accept the image collected by kinenct, and the object is recognized to the server. Secondly, the server realizes the mobile instruction by using the robot tracking technology and returns the result to the server to do the logical processing and generate the control command, The final remote implementation of the robot tracking control.
Key words: target tracking; ROS robot programming; C/S communication framework; remote control; cloud robot
目 录
基于turtlebot的智能机器人物体识别及目标追踪系统 1
摘要 1
Research and Prototype Realization of Object Recognition and Tracking Technology for Intelligent 2
Abstract 2
目 录 3
1 绪 论 5
1.1研究背景 5
1.2智能机器人(turtlebot)与云机器人 7
1.3机器人操作系统(ROS) 9
1.3.1 什么是机器人操作系统(ROS) 9
1.3.2 ROS的核心概念 9
1.3.3 ROS的核心模块 11
2 相关环境的搭建 12
2.1硬件和软件环境的搭建 12
2.1.1硬件环境的搭建 12
2.1.2软件环境的搭建 12
2.2 Ubuntu操作系统和ROS的安装 12
2.3 Kinect2驱动安装 13
2.3.1 kinect2驱动包版本 13
2.3.2 kinect2驱动安装步骤 13
2.4 测试环境是否搭建成功 17
3 基于ROS的控制移动 17
3.1 基于ROS的坐标系 17
3.2 运动控制水平 18
3.3运动命令Twist 18
4 基于ROS图像采集 19
4.1 ROS中图像处理的相关类库 19
4.1 在ROS中使用Kinect摄像头 19
4.2 使用rviz显示图像 20
4.3 ROS中sensor_msgs/Image的消息格式 22
5 ROS中的Nodelet节点 22
5.1 Nodelet节点的特点 22
5.2 nodelet基类 23
6 项目整体架构设计 23
6.1 项目整体架构 23
6.1.1 云应用框架 23
6.1.2 图象识别云应用 24
6.1.3 项目各函数的功能介绍 25
6.2 客户端/服务器模块 26
6.2.1环境说明 26
6.2.2客户端TCP协议通信的步骤 26
6.2.3服务器端TCP协议通信的步骤 27
6.3 机器人实时跟踪模块 29
6.4 配置项目的CMakeLists.txt文件 31
8 项目结果测试 35
8.1硬件设备连接测试 35
8.2测试结果 35
8.3项目运行ROS节点状态图 36
9 结论与展望 37
参考文献 39
致 谢 40
附 录 41
原文 41
译文 54
3 基于ROS的控制移动
3.1 基于ROS的坐标系
给机器人发送运动命令指挥机器人运动之前,了解在ROS中机器人运动使用的测量单位和坐标系统规则。
ROS使用右手约定来定位坐标轴。食指、中指和拇指分别代表指向x、y、z的正轴,对于轴的旋转方向为逆时针方向。如果将拇指指向任何轴的正方向,则手指会沿着正旋转的方向卷曲。对于移动机器人应用ROS,x轴代表前方,y轴代表左侧,z轴代表上方。基于右手定则,机器人围绕z轴的正旋转是逆时针方向,而负旋转是顺时针方向。
ROS使用国际公制系统,线速度始终以米/秒(m/s)为单位,角速度以弧度/秒(rad/s)为单位。
3.2 运动控制水平
控制一个可移动机器人可以在一系列级别下完成,并且ROS为这些不同级别的控制都提供了响应的方法。
在本项目中,我们选择的是基座控制器级别(Base Controller)。驱动程序和PID控制程序一般被组合在一起,封装成一个节点,称作基座控制器Base controller。在抽象的下一个级别,机器人的期望速度是以真实世界的单位来指定的,例如每米的米和弧度。通常也会运用某些形式的PID(Proportional Integral Derivative 比例积分导数)控制。这些方面体现了ROS尽可能地使机器人按照我们期待的行为方式去运动。
基座控制器程序必需始终运行在一个安装有引擎驱动控制程序的计算机上,而且在启动机器人时,它会是第一个被启动的节点。如果我们的机器人配有了基座控制程序,ROS会提供一些工具是操作者向机器人来发布运动命令,可以使用命令行发布或者是写在ROS节点中运行命令。在这个级别上,与基座控制器相连接的硬件设备是什么并不重要,我们在编程时可以仅关注了在机器人物理世界中的线速度与角速度,编写的任何代码都可以在具有ROS接口的任何基座控制器上工作。
基座控制器节点通常向称为/odom的话题上发布里程数据,然后监听/cmd_vel话题接收运动命令。所以在实验中,我们需要利用ROS提供的接口,往/cmd_vel话题上发送相应的运动命令。
3.3运动命令Twist
ROS向基座控制器发送运动命令使用的是Twist消息类型。话题的名称可以使用自定义的任何字母组成,但是通常我们使用/cmd_vel来命名与Twist相关的命令话题,/cmd_vel是“command velocities”的缩写形式。基座控制器节点订阅/cmd_vel话题,然后将话题上的Twist消息转换为机电信号,驱动机器人轮子转动。
如果我们想要发送命令控制机器人运动,更重要的就是要了解发送的消息消息类型,即Twsit,下面展示了Twsit消息详细的定义。
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
可以看出的是,Twist消息由两部分的子消息构成,每一个子消息都是一个三维向量。一个代表线速度分量,一个代表角速度分量。对于一个在二位平面(如地板)中操作的差速驱动机器人,我们只需要线速度的x分量和角速度的z分量。这是因为对于只能在二位平面运动的这类机器人,他只能沿着纵轴前后运动,或者围绕其垂直轴旋转。所以,机器人的线速度分量y和z永远都为零,角速度的x轴和y轴也都为零。
假设我们想让机器人以每秒0.1米的速度向前运动,那么我们可以在命令行指定Twist命令如下格式:‘{linear: {x: 0.1, y: 0, z: 0}, angular: {x: 0, y: 0, z: 0}}’;
如果我们想让机器人以每秒1弧度的速度逆时针旋转,那么我们可以在命令行指定Twist命令如下格式:‘{linear: {x: 0, y: 0, z: 0}, angular: {x: 0, y: 0, z: 1.0}}’
如果让机器人直行的同时左旋,同时设置x和z两个参数即可。
//基于OpenCV和Socket的图像传输(发送)模块
#ifndef __SOCKETMATTRANSMISSIONCLIENT_H__
#define __SOCKETMATTRANSMISSIONCLIENT_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"turtlebot_follower.h"
#define MESSAGE "--------receive data from client success--------"
class SocketMatTransmissionClient
{
public:
SocketMatTransmissionClient(){}
~SocketMatTransmissionClient(){}
private:
int sockClient;
sensor_msgs::Image data;
int connectSuccess = 0;
public:
int socketConnect(const char* IP, int PORT){
struct sockaddr_in servaddr;
if ((sockClient = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if (inet_pton(AF_INET, IP, &servaddr.sin_addr) <= 0)
{
printf("inet_pton error for %s\n", IP);
return -1;
}
if (connect(sockClient, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
printf("connect server success!\n");
connectSuccess = 1;
return 1;
}
void imageCallback(const sensor_msgs::Image msg){
data.header=msg.header;
data.height=msg.height;
data.width=msg.width;
data.encoding=msg.encoding;
data.is_bigendian=msg.is_bigendian;
data.step=msg.step;
data.data[0]=msg.data[0];
if (send(sockClient, (char *)(&data), sizeof(data), 0) < 0)
{
perror("send");
}
if(data.width!=0){
printf("recv over msg_width=%d\n",data.width);
}
else{
printf("depth_msg is empty");
}
}
//图像传输进程函数
void sendThread(int argc, char **argv){
if(connectSuccess)
{
ros::init(argc, argv, "image_listener");//初始化ROS,它允许ROS通过命令行重新命名,现在还不太重要。这里也是我们确切说明节点名字的地方,在运行的系统中,节点的名字必须唯一
ros::NodeHandle nh;
ros::Subscriber sub_ = nh.subscribe("/camera/depth_registered/image_raw", 1, &SocketMatTransmissionClient::imageCallback,this);
ros::spin();
}
}
int receive(){
char *receiveBuf;
receiveBuf = (char*)malloc(strlen(MESSAGE));
memset(receiveBuf,0,strlen(MESSAGE));
if(recv(sockClient, receiveBuf, strlen(MESSAGE), 0) <= 0)
{
perror("recv\n");
close(sockClient);
raise(SIGSTOP);
return -1;
}
printf("接收:%s\n",receiveBuf);
return 1;
}
//断开socket连接
void socketDisconnect(void){
close(sockClient);
}
};
#endif