======= 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.