Ros_posible_python_mistake
guys I am making basic run and stop program for ROS simulation and I found a problem. I don't know why, when the call back function runs the self.l_scan = scan_data -> updates like it should. But when the is_obstacle member function runs. The self.l_scan is empty. I have probably some spell mistake, but I tried to look for it like for hour and I can not find the mistake. The topic /scan is from Turtlebot and it runs like it should. I tried via echo.
Code
#!/usr/bin/env python
import rospy
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
import math
class Robot(object):
def __init__(self):
# Params
self.l_scan = LaserScan()
self.loop_rate = rospy.Rate(10)
self.velocity = Twist()
self.pub = rospy.Publisher("/cmd_vel", Twist, queue_size=10)
self.sub = rospy.Subscriber("/scan", LaserScan, self.callback)
def callback(self,scan_data):
self.l_scan = scan_data
print("readed")
def is_obstacle(self,distance):
print(self.l_scan)
slice_of_array = self.l_scan.ranges[174: 184+1]
if min(slice_of_array) < distance:
return True
else:
return False
def stop(self):
print("stop")
self.velocity = Twist()
self.pub.publish(self.velocity)
## move until find obstacle closer than 0.6, laser [-5,+5] degrees
def move(self):
self.velocity.linear.x = 1
while not self.is_obstacle(0.6):
print("moving")
self.pub.publish(velocity)
self.loop_rate.sleep()
self.stop()
## rotate until find obstacle greater then 3
##def rotate():
## global l_scan
## laser_sub = rospy.Subscriber("/scan", LaserScan, scan_callback)
## vel_pub = rospy.Publisher("/cmd_vel", Twist)
if __name__ == '__main__':
try:
rospy.init_node('Turtle_robot_control', anonymous=True)
my_robot = Robot()
my_robot.move()
except rospy.ROSInterruptException:
rospy.loginfo("node terminated.")
Output
header:
seq: 0
stamp:
secs: 0
nsecs: 0
frame_id: ''
angle_min: 0.0
angle_max: 0.0
angle_increment: 0.0
time_increment: 0.0
scan_time: 0.0
range_min: 0.0
range_max: 0.0
ranges: []
intensities: []
readed
Traceback (most recent call last):
File "/home/trahery/catkin_ws/src/ros_essentials_cpp/src/topic04_perception02_laser/robot_control.py", line 54, in <module>
print(my_robot.is_obstacle(0.2))
File "/home/trahery/catkin_ws/src/ros_essentials_cpp/src/topic04_perception02_laser/robot_control.py", line 24, in is_obstacle
if min(slice_of_array) < distance:
ValueError: min() arg is an empty sequence
Your issue is because you're immediately calling move
after finishing the constructor; where you setup the subscriber. This means there is relatively 0 chance that any data has been received. Instead, you should be validating that you have enough data before trying to slice the list and other operations on the data; because these operations assume you do have data. Something like this:
def is_obstacle(self,distance):
if len(self.l_scan.ranges) < 185:
rospy.logwarn(f'Not enough data for calculation. {self.l_scan.ranges} points read')
return False
slice_of_array = self.l_scan.ranges[174: 184+1]
if min(slice_of_array) < distance:
return True
else:
return False
Note that this causes issues with other parts of your code. Now it will immediate drop out of the loop and stop, but also log an error message. To fix this, and given your current code setup you will need to verify there has been data received to enter the loop:
while len(self.l_scan.ranges) == 0:
self.loop_rate.sleep()
while not self.is_obstacle(0.6):
#...
One final note, in feature sparse environments your code may also break if it doesn't detect enough laserscan points.