Hi there,
I am doing the first rosject with service. We need to rotate the robot to the correct direction according to laser data from “ranges”. But the rotation, I think, should be done in Service Server, and the corresponding laser data is from subscriber with topic “/scan”. So this is the question: how can I give the information from a subsciber into a service server?
As what I have learned in the course, we can only process information from “msg” of a subscriber when the “callback()” is called. There is no specific return to individually offer the “msg” to other usage. So I decide to use “class”. Inside a “class” I can save the “msg” from a subscriber into an attribute of class. But I still meet with problems. Here is my code:
#! /usr/bin/env python
import rospy
from find_wall_pkg.srv import FindWall, FindWallResponse
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
import numpy as np
import time
class find_wall_service_server_class():
def __init__(self):
self.vel = Twist()
def callback(self, msg):
self.laser_data = msg.ranges
def my_callback(self, request):
# get laser data
self.my_sub = rospy.Subscriber("/scan", LaserScan, self.callback)
# 1 find the direction with shortest distance
min_idx = np.argmin(self.laser_data)
# define the angle need to be rotated
angle = min_idx - 360
# 2 rotation
if angle > 0:
# the ranges divided one round with 720 angular grids, each grid is 0.00872
self.vel.angular.z = 0.00872 * angle
self.my_pub.publish(self.vel)
# rotate 1 second
time.sleep(1)
elif angle <= 0:
self.vel.angular.z = 0.00872 * angle
self.my_pub.publish(self.vel)
time.sleep(1)
self.vel.linear.z = 0
self.my_pub.publish(self.vel)
# 3 move forward to the wall
self.my_sub = rospy.Subscriber("/scan", LaserScan, self.callback)
while self.laser_data[360] > 0.3:
self.vel.linear.x = 0.1
self.my_pub.publish(self.vel)
time.sleep(1)
self.my_sub = rospy.Subscriber("/scan", LaserScan, self.callback)
self.vel.linear.x = 0
self.my_pub.publish(self.vel)
# 4 rotate to be along with the wall
# roatate 90 degree anticlockwise, making the wall on the right side of the bot
self.vel.angular.z = 0.00872 * 90
self.my_pub.publish(self.vel)
time.sleep(1)
self.vel.linear.z = 0
self.my_pub.publish(self.vel)
# 5 return message
my_response = FindWallResponse()
my_response.wallfound = True
return my_response
def main(self):
rospy.init_node("find_wall_service_server_node")
self.rate = rospy.Rate(1)
self.my_pub = rospy.Publisher("/cmd_vel", Twist, queue_size=10)
self.my_Service = rospy.Service(
"/find_wall", FindWall, self.my_callback)
rospy.loginfo("The service: /find_wall is ready")
rospy.spin()
if name == ‘main’:
find_wall_instance = find_wall_service_server_class()
find_wall_instance.main()
The service node can be successfully launched. But when I call the service, a.k.a type in “rosservice call find_wall”, it gives error:
ERROR: service [/find_wall] responded with an error: b"error processing request: ‘find_wall_service_server_class’ object has no attribute ‘laser_data’"
[ERROR] [1663856409.121108, 5435.988000]: Error processing request: ‘find_wall_service_server_class’ object has no attribute ‘laser_data’
[‘Traceback (most recent call last):\n’, ’ File “/opt/ros/noetic/lib/python3/dist-packages/rospy/impl/tcpros_service.py”, line 632, in _handle_request\n response = convert_return_to_response(self.handler(request), self.response_class)\n’, ’ File “/home/user/catkin_ws/src/find_wall_pkg/scripts/find_wall_service_server.py”, line 25, in my_callback\n min_idx = np.argmin(self.laser_data)\n’, “AttributeError: ‘find_wall_service_server_class’ object has no attribute ‘laser_data’\n”]
Can anyone help me, what is going on here?