[ROS][refact] Parse CSV
Goal
The CSV reader needs to be improved.
Before, loop closure indices are provided by a csv file. It's difficult to know loop closure indices before a slam map is built. So we want to save trajectory with index information so that one can get loop closure indices with saved trajectory. So that users can:
- Play slam and stop the bag when a loop closure is observed.
- Save trajectory
- Open trajectory with a visual tool and get the loop closure indices
- Create a csv file of loop closure indices. More than one loop can be added in the file
Changes
-
Save trajectory with index term
-
Add helper function
ParseSentence
- Input: a string of currentLine, the delimiter
- Output: a vector of words
- Function:
- remove the extra spaces before and after the delimiter
- extract words in the currentLine
- if the delimiter is not
,
, check for comma decimal separator and change it to point
-
Add helper function
ParseCSV
- Input: CSV file path, startLineIdx which indicates data position, the delimiter
- Output: a vector of sentences (sentence = a vector of strings)
- Function:
- Read each line of CSV file started from line startLineIdx and parse it into sentence by calling
ParseSentence
function - Check each element in a sentence has a numerical value
- Read each line of CSV file started from line startLineIdx and parse it into sentence by calling
-
Overload ReadCSV. Globally, it does two things, find the delimiter and parse CSV (by calling
ParseCSV
function).-
ReadCSV(path, nbHeaderLines, nbFields)
is the previous function. Given a csv path and number of header lines, this function get the first data line, and try to separate this line into several fields with delimiters in a list of delimiters. If one delimiter can separate the line into nbFields, we use this delimiter to parse csv. Then it check whether or not each sentence has the nbFields, if not reject the line. -
ReadCSV(path, nbHeaderLines, fieldsToCheck)
is added to check whether or not the required fields exist in the CSV file (headerline)- First, we look for the position of a field of fieldsToCheck in the headerline. Then the delimiter is found by looking to the left and to the right of the position of this field. The extra spaces case is considered.
- Then it reorders the lines in the same order of required fieldsToCheck.
-
-
Refact
ReadPose
function to check csv fields. Sinceindex
term is added when saving slam trajectory and this term is not needed when we want to load pose, we check only the fields we need when reading pose from a csv field.
Results
Data to test
- I used car_loop
- data : weird csv files for the test of parse csvCSV_test.zip
Build
catkin_make -j --cmake-args -DCMAKE_BUILD_TYPE=Release
Run
roslaunch lidar_slam slam_velodyne.py \
rosbag play --clock path/to/bag
Then use Reset trajectory
or Load loop indices
command to read csv files
Output
Test of read CSV function
- test1
[ INFO] [1701864832.482835285, 1698334274.503147239]: time = 0.00000000000000
1.00000000000000, 1.00000000000000, 0.00000000000000, 1.00000000000000
0.00000000000000, 2.00000000000000, 0.00000000000000, 2.00000000000000
0.00000000000000, 0.00000000000000, 1.00000000000000, 3.00000000000000
0.00000000000000, 0.00000000000000, 0.00000000000000, 1.00000000000000
- test2
[ INFO] [1701865137.454313067, 1698334274.692999599]: time = 2.00000000000000
3.00000000000000, 7.00000000000000, 11.00000000000000, 2.00000000000000
8.00000000000000, 4.00000000000000, 12.00000000000000, 5.00000000000000
9.00000000000000, 10.00000000000000, 1.00000000000000, 6.00000000000000
0.00000000000000, 0.00000000000000, 0.00000000000000, 1.00000000000000
- test3
[ INFO] [1701865273.291824755, 1698334274.891894407]: time = 1.00000000000000
5.00000000000000, 8.00000000000000, 11.00000000000000, 2.00000000000000
6.00000000000000, 9.00000000000000, 12.00000000000000, 3.00000000000000
7.00000000000000, 10.00000000000000, 13.00000000000000, 4.00000000000000
0.00000000000000, 0.00000000000000, 0.00000000000000, 1.00000000000000
- test4
[ INFO] [1701867612.904658175, 1698334274.799694286]: time = 1.00000000000000
5.00000000000000, 8.00000000000000, 11.00000000000000, 2.00000000000000
6.00000000000000, 9.00000000000000, 12.00000000000000, 3.00000000000000
7.00000000000000, 10.00000000000000, 13.00000000000000, 4.00000000000000
0.00000000000000, 0.00000000000000, 0.00000000000000, 1.00000000000000
- test5
[ INFO] [1702044445.861313466, 1698334282.595179461]: time = 6.000000000000
4.000000000000,7.000000000000,10.000000000000,1.100000023842
5.000000000000,8.000000000000,11.000000000000,2.500000000000
1.000000000000,9.000000000000,12.000000000000,3.700000047684
0.000000000000,0.000000000000,0.000000000000,1.000000000000
What remains to solve
- Bring features in ros2_wrapping
Checklist
-
Camel case everywhere except for ROS variables/parameters -
Lower case for local variables and lambda functions -
Upper case for pour members, methods and tool functions (in Utils) -
Precise namespace when calling a function (or this->X or classe.X) -
Align code (for multiline if and while, "&&" or "||" go in upper line to ensure alignement) -
Space between if, while, for and parenthesis -
Space between operators and variables: e.g. a + b -
Space after "," -
Mind your commit titles/desc (plurals, he/she + "s", correct tags, title should begin by a verb...) -
Function names should start with a verb, variable names should start with a name -
Macros should be between {} -
Do not use negative boolean (i.e. noJoe) -
Check minimal size of the types (double -> float -> int -> uint) -
Check const and ref in functions arguments -
References should be written "type& name", not "type &name" -
Update documentation if needed -
Add MR labels [ROS]/[ROS2]/[PV] -
If ros/ros2, update task table here -
Add a comment over each non trivial function in header files -
Adda header to each new file