In the last days, I started the “ROS Basics In 5 Days” Course. Now, I’m in unit 5. Unfortunately, I have been stuck in the topics_quiz. I tried, again and again, debugging my code according to the error messages printed by: roslaunch topics_quiz topics_quiz.launch. Below is my code:
#! /usr/bin/env python
import rospy
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
rospy.init_node('topics_quiz_node')
def give_distances(msg):
global distance_read
distance_read=msg.ranges
return distance_read
class distances:
def __init__(self):
self.distances=[]
def measurer(self,readings):
self.take=self.distances
self.final_array=self.take.append(readings)
self.length=len(self.final_array)
return length
sub = rospy.Subscriber('/kobuki/laser/scan',LaserScan, give_distances)
pub = rospy.Publisher('/cmd_vel',Twist)
rate = rospy.Rate(10)
while not rospy.is_shutdown():
give_distances(LaserScan)
dist=distances()
needed_number=dist.measurer(distance_read)
velocity=Twist()
distance_front=distance_read[needed_number//2]
distance_right=distance_read[needed_number-needed_number]
distance_left=distance_read[needed_number-0]
velocity_linear=velocity.linear.x
velocity_angular=velocity.angular.z
def initialization():
velocity_linear=0
velocity.linear.y=0
velocity.linear.z=0
velocity_angular=0
velocity.angular.x=0
velocity.angular.y=0
return 0
initialization()
while distance_front>1:
velocity_linear=0.5
velocity_angular=0
while distance_front<1:
velocity_linear=0.5
velocity_angular=0.7
while distance_right<1:
velocity_linear=0
velocity_angular=0.7
while distance_left<1:
velocity_linear=0
velocity_angular=-0.7
rate.sleep()
The error message I get, at the moment, is the following:
Traceback (most recent call last):
File "/home/user/catkin_ws/src/topics_quiz/src/topics_quiz.py", line 34, in <module>
needed_number=dist.measurer(distance_read)
File "/home/user/catkin_ws/src/topics_quiz/src/topics_quiz.py", line 21, in measurer
self.length=len(self.final_array)
TypeError: object of type 'NoneType' has no len()
Quick question(s): When you decided to use classes, why do you have most of the functions outside the class? Also, why make a class for just two functions that barely do anything?
After reading through your code, I strongly believe that you need a primer on Python programming.
Please take the Python for Robotics course offered by this website.
Anyways, your solution(s) here:
give_distances(LaserScan):
This line will not work. LaserScan is the laser scanner message and it usually contains an empty dataframe - all of them will be zeros. When you pass this to give_distances() function, you are basically passing a data with zeros, naturally, it would return distance_read as zeros. EDIT:LaserScan is just the class for laser scan messages, LaserScan() initializes a message.
dist = distances():
You have initialized the distances class with basically no data in it.
needed_number = dist.mesaurer(distance_read):
This line will not work, because you did not store the result in step 1. Therefore, distance_read contains nothing (not even zeros). Therefore, when distances.measurur() function executes, self.distances is an empty list. Therefore when you do self.length = len(self.final_array) you are calculating the length of an empty list. Empty list by definition in python, is a NoneType, hence you get 'NoneType' has no len() error.
@girishkumar.kannan Thank you, for your answer! And it’s nice to be a part of this community!
Initially, I didn’t use classes and didn’t have any reason to do that. As for why I made a class, I searched through the internet for a solution to my problems and some answers suggested the use of classes. I woudn’t do that by my own.
The truth is that I’m fairly new to Python programming and I need more hours and interaction to get used to it. I hope you understand that. I took the “Python for Robotics” Course and I may go through it again.
Here, below, is my original code. Is this any better:
#! /usr/bin/env python
import rospy
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
rospy.init_node('topics_quiz_node')
sub = rospy.Subscriber('/kobuki/laser/scan',LaserScan)
pub = rospy.Publisher('/cmd_vel',Twist,queue_size=1)
rate = rospy.Rate(10)
while not rospy.is_shutdown():
distance_read=LaserScan().ranges
velocity=Twist()
distance_front=distance_read[len(distance_read)//2]
distance_right=distance_read[len(distance_read)-len(distance_read)]
distance_left=distance_read[len(distance_read)-0]
velocity_linear=velocity.linear.x
velocity_angular=velocity.angular.z
def initialization():
velocity_linear=0
velocity.linear.y=0
velocity.linear.z=0
velocity_angular=0
velocity.angular.x=0
velocity.angular.y=0
return 0
initialization()
while distance_front>1:
velocity_linear=0.5
velocity_angular=0
while distance_front<1:
velocity_linear=0.5
velocity_angular=0.7
while distance_right<1:
velocity_linear=0
velocity_angular=0.7
while distance_left<1:
velocity_linear=0
velocity_angular=-0.7
rate.sleep()
?
Now, I get this error:
Traceback (most recent call last):
File "/home/user/catkin_ws/src/topics_quiz/src/topics_quiz.py", line 20, in <module>
distance_front=distance_read[len(distance_read)//2]
IndexError: list index out of range
Honestly, this code is better than the earlier one that you posted, but still bad.
My observations:
You are missing the subscriber callback. Therefore you will never receive laser scan messages.
LaserScan() just initializes a laser scan empty message. If you try to read data from initialized message, you will only get zeros and empty strings (strings with no characters).
You do all initialization(s) before your loop.
Do not define functions within loops - these functions are called inner functions - they are used for abstractions. You do not want to do that unless you really know what you are doing!
For robot movement, instead of using 4 while loops, you can use one while loop with 4 if(else) conditions. If you use 4 consecutive while loops, once the loop finishes, it will exit. So your robot might move just 4 times or probably get stuck in one of the loops.
Is this any better? I’m really sorry to bother you, but I’m really stuck. I suppose there are some things, technical and functional, that I do not yet know. Could you provide any detailed feedback? I won’t push you, but I’d really appreciate it if you did. I won’t bother anymore after this. I will work in order to get better at programming etc. Thanks, in advance.
#! /usr/bin/env python
import rospy
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
rospy.init_node('topics_quiz_node')
def give_distances(msg):
global distance_read=LaserScan().ranges
return distance_read
sub = rospy.Subscriber('/kobuki/laser/scan',LaserScan,give_distances)
pub = rospy.Publisher('/cmd_vel',Twist,queue_size=1)
give_distances()
velocity=Twist()
distance_front=distance_read[len(distance_read)//2]
distance_right=distance_read[len(distance_read)-len(distance_read)]
distance_left=distance_read[len(distance_read)-0]
velocity_linear=velocity.linear.x
velocity_angular=velocity.angular.z
def initialization():
velocity_linear=0
velocity.linear.y=0
velocity.linear.z=0
velocity_angular=0
velocity.angular.x=0
velocity.angular.y=0
return 0
initialization()
while distance_read!=[]:
if distance_front>1:
velocity_linear=0.5
velocity_angular=0
give_distances()
elif distance_front<1:
velocity_linear=0.5
velocity_angular=0.7
give_distances()
if distance_right<1:
velocity_linear=0
velocity_angular=0.7
give_distances()
if distance_left<1:
velocity_linear=0
velocity_angular=-0.7
give_distances()
give_distances()
rospy.spin()
Now, I get this:
Traceback (most recent call last):
File "/home/user/catkin_ws/src/topics_quiz/src/topics_quiz.py", line 18, in <module>
give_distances()
TypeError: give_distances() missing 1 required positional argument: 'msg'
Here is one way to solve it. I am only giving this to you to get you motivated and learn from this.
#! /usr/bin/env python
# the above line is called a "shebang"
# if you forget to include that line, your code will not run!
# imports for the program
import rospy
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
# define scan callback before initializing scan subscriber
# this is required only if you do not use classes
# if you use classes then you can have the function within your class
def scan_callback(msg):
global range_left, range_front, range_right
range_left = msg.ranges[719]
range_front = msg.ranges[360]
range_right = msg.ranges[0]
return None
# initialize rospy and relevant rates, publishers and subscribers
rospy.init_node("topics_quiz_node")
rate = rospy.Rate(2)
pub = rospy.Publisher("/cmd_vel", Twist, queue_size=1)
sub = rospy.Subscriber("/kobuki/laser/scan", LaserScan, scan_callback)
# initialize your process variables (and constants)
linear_speed = 0.15
angular_speed = 0.30
range_left = 0.0
range_front = 0.0
range_right = 0.0
# program your main function
# try-except block is used for exception handling
while not rospy.is_shutdown():
try:
# initialize a twist command to hold the values
twist_cmd = Twist()
# change the data of twist command appropriately
# with respect to the movement of the robot
if (range_front > 1.0):
twist_cmd.linear.x = linear_speed
twist_cmd.angular.z = 0.0
print("No Obstacle : Moving Straight")
else:
twist_cmd.linear.x = linear_speed
twist_cmd.angular.z = angular_speed
print("Obstacle Ahead : Turning Left")
if (range_right < 1.0):
twist_cmd.linear.x = linear_speed
twist_cmd.angular.z = angular_speed
print("Obstacle on Right : Turning Left")
else:
pass
if (range_left < 1.0):
twist_cmd.linear.x = linear_speed
twist_cmd.angular.z = -angular_speed # notice the (-) sign!
print("Obstacle on Left : Turning Right")
else:
pass
# publish the twist command to the cmd_vel topic
pub.publish(twist_cmd)
# sleep for specified rate for the robot to move
rate.sleep()
except:
pass
# End of Code
Go through code and let me know if you understood it.
Don’t feel bad to ask any question! Just make sure to search the forum to see if a similar question is asked already (by someone else).
No problem at all! I am happy to help! I would appreciate if you get a bit strong in basics.
These are the bare basics to get the subscriber and the publisher working using rospy.
If you do not know why subscribers need a callback function and why publishers use a publish function, then you must definitely take the course and learn ROS from beginning!
These are the concepts used in ROS and if you can’t understand these or don’t not know about these then that is bad.