======= Homework 01 ======= Your task will be to explore a {{ :courses:aro:tutorials:2019-02-20-11-00-56.zip | bagfile }} containing data from a laser scanner (obtained from a real turtlebot). Once you have familiarized yourself with the contents of the bagfile, you should create a node that will collect and process the laser scanner data. After collecting the specified number of samples, the node will publish the collected data in batch using a ROS message. You can find a more detailed description of the individual sub-tasks below. ===== Reading messages from the bagfile ===== - Download the {{ :courses:aro:tutorials:2019-02-20-11-00-56.zip | bagfile }} from the labs web page. Link should be next to the link to this document or: $ wget https://cw.fel.cvut.cz/b202/_media/courses/aro/tutorials/2019-02-20-11-00-56.zip $ unzip 2019-02-20-11-00-56.zip - Check the contents of the bagfile: rosbag info rqt_bag - Find topic name and message type corresponding to data from a laser scanner. This is a device that takes range measurements using laser ranging technique. The laser is incrementally (but very quickly) rotated and a measurement is taken after each increment. Thus, a single scan contains multiple range measurements taken at different angles.Based on the data (ROS message) type, try to find documentation for the laser scanner data (e.g. {{http://wiki.ros.org/sensor_msgs|http://wiki.ros.org/sensor_msgs}}). - Create a package named ''aro_scan'' containing python script ''scancollector.py'' and nescessary ROS package configuration files "CMakeList.txt", "package.xml". - Create a node in file ''scancollector.py'' that will listen for the messages from the laser scanner and process them in the following way: - Filter out possibly erroneous data (i.e. outside of the normal value range – see the message documentation) - Discard measurements taken at an angle greater than 30° or lower than -30° (i.e. abs(angle) < 30°) - Compute the mean of the remaining values and store it into a buffer (you can use __Python list__ or __numpy array__) - Store the message timestamp as well (you can store it as a single float using the __to_sec()__ function) - If the number of stored values had reached the number specified in the __batch_length__ global parameter: - Stop accumulating the data - Publish the data to the ''scan_filtered'' topic as __std_msgs/Float32MultiArray__ containing computed means - Run all the nodes and then play the bagfile (rosbag play). ===== Plotting ===== You can plot the data to check it using the __plot(x, y)__ function of the [[https://matplotlib.org/api/pyplot_api.html|pyplot module]] from the //matplotlib// package. You might also need to use the __show()__ function to show the plot. ===== Setting up the parameters ===== - Next, you will need to set a couple of parameters. Hint: use ''rospy.get_param()''. - First, get a global parameter with the name __batch_length__ specifying the number of values that shall be collected. - Set a second global parameter called __start_time__ that will hold the starting timestamp of the ROS bag recording. ===== Hints ===== * You can find most of the necessary information within the presentations from Lab 01. * The rest could be found using the mentioned commands or by following the provided links. * Check [[http://wiki.ros.org/rospy/Overview/Time|http://wiki.ros.org/rospy/Overview/Time]] if you need help with the timestamps. * If you have problem with plotting, search for //matplotlib// plot examples or documentation * When dealing with more complex nodes and persistent variables, it is useful to create a class that will handle all of the data processing. In the case of the listener node, the structure of your script ''scancollector.py'' should look like this: #!/usr/bin/env python3 import rospy import numpy as np # TODO other imports class ScanCollector(): def __init__(self): # Initialize the node here # retrieve the necessary parameters from the parameter server rospy.get_param( ... ) # and store them into variables # create the listener object and assign a class method as the callback # possibly do some additional stuff def scan_callback(self, msg): # process the message # if enough data has been collected, publish the data if __name__ == '__main__': sc = ScanCollector() rospy.spin() ===== Example ===== Here is an example of a data plot (extracted from the bag with plot_length set to 500): {{ :courses:aro:tutorials:figure_1_hw.png?nolink&800 |}} Your plot might differ a little, depending on the parameters. You also don't need to tune value ranges of the plot axis and the labels (but the plot will look nicer if you do!) ===== Evaluation ===== Please, submit your solution to the [[https://cw.felk.cvut.cz/upload/|upload system]]. Upload the whole package ''aro_scan'' (as a folder with matching name, that contains the script and the config files "CMakeList.txt", "package.xml"). Please, do not upload the entire workspace or just the files. 5 points will be awarded for valid submission. * The solution must work as described above. * The submitted package must be "buildable" by catkin build in a ROS Noetic distro. * The script ''scancollector.py'' must be "runnable" by calling rosrun after building and sourcing the workspace, and its parameters settable from rosparam server. Check if this is true before submission.