项目场景:
在室内服务机器人项目中,需要先通过目标检测获取目标点的位置,之后控制机器人移动到目标点,进而完成后续抓取的任务。因此,通过调用ROS中的client/server 来实现目标检测和机器人移动的任务。
在此,将项目目标检测简化为输入为图片,输出为坐标的过程,将机器人移动简化为输入为坐标,输出为成功的执行结果。其中目标检测和机器人移动为两个服务,主程序为客户端。
实现过程:
1. 创建srv文件
在功能包中创建srv文件夹,在srv文件夹中建立检测和移动服务对应的文件:detect.srv 和 move.srv 。
detect服务的输入为图像,类型为Image。 输出为目标点坐标,类型为int.。detect.srv文件内容如下:
sensor_msgs/Image rgb_image
---
uint16 x
uint16 y
move服务的输入为目标点坐标,类型为int。 输出为执行结果,类型为string.。move.srv文件内容如下:
uint16 x
uint16 y
---
string result
“- - -”在服务的数据结构中是用来分割Request和Response两个部分的数据,可以理解为输入数据和输出数据的划分。
2.修改 CMakeList 文件
在功能包里打开 CMakeList.txt 文件
- 在文件开头做如下修改:
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
sensor_msgs
)
find_package(OpenCV REQUIRED)
- 在 ## Declare ROS messages, services and actions ## 部分里添加如下代码,来调用刚才创建的srv文件。
add_service_files(
FILES
detect.srv
move.srv
)
generate_messages(
DEPENDENCIES
std_msgs
sensor_msgs
)
- 在 ## build ## 部分,做如下修改:
include_directories(
include
${catkin_INCLUDE_DIRS}
)
3.修改 package文件
在功能包里打开 package.xml 文件,在文件末尾添加以下两行代码:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
4.添加 service 程序代码:
在功能包中src 文件夹中添加各部分代码,或创建scripts文件夹 单独存放python 文件。src 文件夹中包含:
- target_detection.py ——目标检测server
- robot_move.py ——机器人移动server
- master.py ——主程序client
target_detection.py
#!/usr/bin/env python2
# -*- encoding: utf-8 -*-
import os
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge,CvBridgeError
from robot.srv import detect, detectResponse #robot为功能包名,需要添加检测服务响应的头文件!
import cv2
def detectCallback(req):
# 提取输入数据
data = req.rgb_image
# 图片格式转换
bridge = CvBridge()
cv_image = bridge.imgmsg_to_cv2(data, "bgr8")#转换后的待处理的图片
print("The image is received!")
#################################目标检测算法#####################################
#/----------------------输入待检测图片,输出目标位置坐标。--------------------------/
#################################目标检测算法#####################################
# 反馈数据
x,y=571,107
return detectResponse(x,y)
def detect_server():
# ROS节点初始化
rospy.init_node('detect_server')
# 创建一个server,注册回调函数
s = rospy.Service('/target_detection', detect, detectCallback)
# 循环等待回调函数
print "Ready to show image reception result :"
rospy.spin()
if __name__ == "__main__":
detect_server()
robot_move.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import cv2
import rospy
import numpy as np
from std_msgs.msg import Header
from sensor_msgs.msg import Image
from cv_bridge import CvBridge,CvBridgeError
from robot.srv import move, moveResponse #robot为功能包名,需要添加移动服务响应的头文件!
import time
def moveCallback(req):
# 显示请求数据
rospy.loginfo("The received position is : x :%d y:%d", req.x, req.y)
##################################机器人移动算法#######################################
#/-----------------------输入目标位置坐标,输出执行成功的结果。------------------------/
##################################机器人移动算法#######################################
# 反馈数据
return moveResponse("successful !")
def move_server():
# ROS节点初始化
rospy.init_node('move_server')
# 创建一个server,注册回调函数
s = rospy.Service('/robot_move', move, moveCallback)
# 循环等待回调函数
print "Ready to show data reception result :"
rospy.spin()
if __name__ == "__main__":
move_server()
master.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import cv2
import rospy
import numpy as np
from std_msgs.msg import Header
from sensor_msgs.msg import Image
from cv_bridge import CvBridge,CvBridgeError
from robot.srv import detect, detectRequest #robot为功能包名,需要添加检测服务请求的头文件!
from robot.srv import move, moveRequest #robot为功能包名,需要添加移动服务请求的头文件!
import time
def detect_client():
# 发现服务后,创建一个服务客户端,连接service
rospy.wait_for_service('/target_detection')
detect_client = rospy.ServiceProxy('/target_detection', detect)
###########################数据处理/算法部分###############################
bridge = CvBridge()
cv_img = cv2.imread('/home/zhy/catkin_ws/src/robot/scripts/test.png')
img = bridge.cv2_to_imgmsg(cv_img, "bgr8")
###########################数据处理/算法部分###############################
############请求:输入数据(Image), 响应:输出数据(int,int)###################
response = detect_client(img)
rospy.loginfo("the result is : %d, %d", response.x,response.y)
def move_client():
# 发现服务后,创建一个服务客户端,连接service
rospy.wait_for_service('/robot_move')
move_client = rospy.ServiceProxy('/robot_move', move)
###########################数据处理/算法部分#############################
###########################数据处理/算法部分#############################
#############请求:输入数据(int,int), 响应:输出数据(string)##############
response = move_client(571,107)
rospy.loginfo("the result is : %s", response.result)
if __name__ == "__main__":
# ROS节点初始化
rospy.init_node('master_client')
#调用服务
detect_client()
move_client()
提示:在放代码文件的目录中需要放入需要处理的图片!
5.编译/运行程序:
- 切换到工作空间目录,编译工作空间
cd catkin_ws/
catkin_make
之后会在 / catkin_ws / devel / include 中对应的功能包中生成srv的 .h 文件。
python 文件不需要编译可直接运行,但要先修改python 的权限,选择python文件右键点击选择属性 -> 权限 -> 执行,在方框上打勾,允许作为程序执行文件。如图:
- 启动ROS
roscore
- 另外打开三个终端,通过执行以下命令,运行相应的 python 文件
cd catkin_ws/
source devel/setup.bash
rosrun robot master.py
cd catkin_ws/
source devel/setup.bash
rosrun robot target_detection.py
cd catkin_ws/
source devel/setup.bash
rosrun robot robot_move.py
最后运行结果如图所示: