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
from find_wall_pkg.srv import FindWall, FindWallResponse
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
import numpy as np
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 > 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()
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?