Hello, I am having trouble with getting the subscriber and the service to communicate as I am very new to python (really only experienced with MATLAB unfortunately). My main issue is finding a way to get the ‘msg’ from the subscriber and ‘request’ from the service in the same function, or find a way to get two separate functions to work together nicely. This is my attempt, but whenever I call the service the turtlebot spins into oblivion never to stop. Not sure what I am doing wrong here! Appreciate all the help.
Blockquote
#! /usr/bin/env python
import rospy
from rosject_1.srv import FindWall, FindWallResponse
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
minDist = 0
laser_ranges = []
found_wall = False
def findClosestWall(msg):
minDist = msg.range_min
laser_ranges = msg.ranges
while laser_ranges[360] > minDist + 0.1:
move.angular.z = 0.2
pub.publish(move)
rate.sleep()
laser_ranges = msg.ranges
move.angular.z = 0.0
pub.publish(move)
if msg.ranges[360] > 0.3:
while msg.ranges[360] > 0.3:
move.angular.z = 0.0
move.linear.x = 0.1
pub.publish(move)
rate.sleep()
move.linear.x = 0.0
pub.publish(move)
global found_wall
found_wall = True
return 0
def callback(request):
rospy.loginfo("The Service /findWall has been called")
global found_wall
response = FindWallResponse()
if found_wall:
response.wallfound = True
return response
rospy.init_node('findWall_server')
sub = rospy.Subscriber('/scan', LaserScan, findClosestWall)
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
move = Twist()
rate = rospy.Rate(5)
findwall_service = rospy.Service('/findWall', FindWall, callback)
rospy.spin()
You can take our free Python course to learn more (if you have not taken it already).
You are already doing well in this. You can make request
available just as you made msg
available using a global variable. You just need some little adjustments.
In your subscriber callback,
laser_ranges = msg.ranges
should be
global laser_ranges
laser_ranges = msg.ranges
since global_ranges
is a global variable and you want to modify it (I think).
However, in your service callback,
global found_wall
response = FindWallResponse()
if found_wall:
response.wallfound = True
return response
should be
response = FindWallResponse()
if found_wall:
response.wallfound = True
return response
because you don’t need to use the global
keyword to access a global variable within a function - you only need it when you want to modify it.
PS: even if you use global
unnecessarily when you just need to access a global variable, it still works. But you must use it if you want to modify the variable (even if you are also accessing it within the same function).
As far as I can see here, if the robot is not stopping, it’s because your logic to stop it in the subscriber is not working. I recommend that you examine laser_ranges
to ensure you are getting the expected values.
On the other hand, I suppose that when you call the service, it is not returning a result because:
found_wall
will not be true until the robot is stopped towards the end of the subscriber logic.
Hi again! thanks for the tips, but it seems like I am having some of the same issues. When I run the server node the robot starts searching for the wall (rotating) before the service is called. I believe its because I have the subscriber call outside of the callback function, so when the node starts it starts as well. Is it possible to put the subscriber inside of the callback function?
I added the subscriber to the server callback function and it does appear to start searching when the service is called. However, it has been throwing the following error whenever I ‘rosservice call /findWall’:
ERROR: service [/findWall] responded with an error: b’service cannot process request: service handler returned None’
I believe this is because I need to import an Empty request type? I will try this and update this topic.
One last thing, it appears that the msg.ranges is not updating, i.e. staying a static value, making the code run in an infinite while loop. I am not sure how to fix this. Thank!
Blockquote
#! /usr/bin/env python
import rospy
from rosject_1.srv import FindWall, FindWallResponse
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
minDist = 0
found_wall = False
def findClosestWall(msg):
global found_wall
global minDist
if minDist == 0:
minDist = msg.range_min
while msg.ranges[360] > minDist + 0.1:
move.angular.z = 0.2
pub.publish(move)
print('minDist: ', minDist)
print('laser_ranges: ', msg.ranges[360])
# rate.sleep()
move.angular.z = 0.0
pub.publish(move)
print('wall found!')
if msg.ranges[360] > 0.3:
while msg.ranges[360] > 0.3:
move.angular.z = 0.0
move.linear.x = 0.1
pub.publish(move)
# rate.sleep()
move.linear.x = 0.0
pub.publish(move)
found_wall = True
return 0
def callback(request):
rospy.loginfo("The Service /findWall has been called")
sub = rospy.Subscriber('/scan', LaserScan, findClosestWall)
response = FindWallResponse()
if found_wall:
response.wallfound = True
return str(response)
rospy.init_node('findWall_server')
rospy.loginfo("The Service is ready to be called")
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
move = Twist()
rate = rospy.Rate(5)
findwall_service = rospy.Service('/findWall', FindWall, callback)
rospy.spin()
Hello again, sorry about all these updates but I have figured out the msg.ranges updating issue! here is my new code:
Blockquote
#! /usr/bin/env python
import rospy
from rosject_1.srv import FindWall, FindWallResponse
from std_srvs.srv import Empty
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
minDist = 0
found_wall = False
def findClosestWall(msg):
global found_wall
global minDist
if minDist == 0:
minDist = min(msg.ranges)
if msg.ranges[360] > minDist + 0.1:
move.angular.z = 0.2
pub.publish(move)
print('minDist: ', minDist)
print('laser_ranges: ', msg.ranges[360])
# rate.sleep()
if msg.ranges[360] < minDist + 0.1:
move.angular.z = 0.0
pub.publish(move)
print('wall found!')
if msg.ranges[360] > 0.3 and msg.ranges[360] < minDist + 0.1:
print('Approaching wall')
move.angular.z = 0.0
move.linear.x = 0.1
pub.publish(move)
# rate.sleep()
if msg.ranges[360] < 0.3 and msg.ranges[360] < minDist + 0.1:
move.linear.x = 0.0
pub.publish(move)
found_wall = True
print('At the wall')
return 0
def callback(request):
rospy.loginfo("The Service /findWall has been called")
sub = rospy.Subscriber('/scan', LaserScan, findClosestWall)
response = FindWallResponse()
if found_wall:
response.wallfound = True
return str(response)
rospy.init_node('findWall_server')
rospy.loginfo("The Service is ready to be called")
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
move = Twist()
rate = rospy.Rate(5)
findwall_service = rospy.Service('/findWall', FindWall, callback)
rospy.spin()
I am still having that error from the previous reply though, but it seems like the service is still called and the robot finds the wall, moves toward it and stops at 0.3m from it which is great. Now my only problem is that the service doesn’t give a response and the service continues to print out ‘found wall’ and ‘At the wall’ repeatedly. I am not sure how to exit the subscriber callback and update the ‘wallfound’ object in the service callback because that seems to be the issue alongside the error from my earlier reply.
If someone could take a look at my previous reply I would greatly appreciate it. I am still having this issue. Thanks!
NVM! I have finally solved it! for all those who are having trouble and reading this thread:
- write laser data and min distance in the subscriber callback as global variables (no logic here)
- write all the logic in the server call back
- server and subscriber init need to be in global scope
I’d post my code but that’d ruin the fun of figuring it out
Thanks!
1 Like
This topic was automatically closed after 20 hours. New replies are no longer allowed.