项目场景:

在室内服务机器人项目中,需要先通过目标检测获取目标点的位置,之后控制机器人移动到目标点,进而完成后续抓取的任务。因此,通过调用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 文件

  1. 在文件开头做如下修改:
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
  sensor_msgs
)
find_package(OpenCV REQUIRED)
  1. 在 ## Declare ROS messages, services and actions ## 部分里添加如下代码,来调用刚才创建的srv文件。
add_service_files(
  FILES
  detect.srv
  move.srv
)

generate_messages(
  DEPENDENCIES
  std_msgs
  sensor_msgs
)
  1. 在 ## 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.编译/运行程序:
  1. 切换到工作空间目录,编译工作空间
cd catkin_ws/
catkin_make

之后会在 / catkin_ws / devel / include 中对应的功能包中生成srv的 .h 文件。

python 文件不需要编译可直接运行,但要先修改python 的权限,选择python文件右键点击选择属性 -> 权限 -> 执行,在方框上打勾,允许作为程序执行文件。如图:

client server runtime process 占用显存_数据

  1. 启动ROS
roscore
  1. 另外打开三个终端,通过执行以下命令,运行相应的 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

最后运行结果如图所示:

client server runtime process 占用显存_数据_02