├── ReadMe.html
├── ReadMe.txt
├── Summary.txt
├── data
├── l90.tar.gz
├── lmov.tar.gz
└── lstraight.tar.gz
├── reference-output
├── l90.tuple
├── l90_0.tuple
├── l90_0_results.json
├── l90_0_results.m
├── l90_1.tuple
├── l90_1_results.json
├── l90_1_results.m
├── l90_2.tuple
├── l90_2_results.json
├── l90_2_results.m
├── l90_results.json
├── l90_results.m
├── lmov.tuple
├── lmov_0.tuple
├── lmov_0_results.json
├── lmov_0_results.m
├── lmov_1.tuple
├── lmov_1_results.json
├── lmov_1_results.m
├── lmov_2.tuple
├── lmov_2_results.json
├── lmov_2_results.m
├── lmov_results.json
├── lmov_results.m
├── lstraight.tuple
├── lstraight_0.tuple
├── lstraight_0_results.json
├── lstraight_0_results.m
├── lstraight_1.tuple
├── lstraight_1_results.json
├── lstraight_1_results.m
├── lstraight_2.tuple
├── lstraight_2_results.json
├── lstraight_2_results.m
├── lstraight_results.json
├── lstraight_results.m
└── version_string
├── scripts
├── copy_results.sh
├── create_pictures.m
├── create_pictures_iteration.m
├── create_tuples.sh
├── errorbar_tick.m
├── format_ticks.m
├── my_figure.m
├── my_fonts.m
├── results.json
├── run_all.sh
├── script_variables.sh
└── table_test.tex
└── src
├── CMakeLists.txt
├── analyzer.cpp
├── analyzer.h
├── aux_functions.cpp
├── aux_functions.h
├── calib_tuple.cpp
├── calib_tuple.h
├── gsl_jacobian.cpp
├── gsl_jacobian.h
├── gsl_jacobian_test.cpp
├── solver.cpp
├── solver2.cpp
├── solver2_meat.cpp
├── solver_options.cpp
├── solver_options.h
├── solver_utils.cpp
├── solver_utils.h
├── synchronizer.cpp
├── synchronizer_options.cpp
├── synchronizer_options.h
├── test_json.c
├── verifier.cpp
├── verifier_options.cpp
├── verifier_options.h
├── verifier_utils.cpp
└── verifier_utils.h
/ReadMe.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
Supplemental materials for Simultaneous calibration of odometry and sensor parameters for mobile robots
7 |
8 | Supplemental materials for “Simultaneous calibration of odometry and sensor parameters for mobile robots”
9 |
10 | This archive contains C++ source code for the calibration method described in the paper, plus the raw data and scripts to reproduce the experiments, in the spirit of reproducible research.
11 |
12 | Please contact Andrea Censi (andrea at cds.caltech.edu) for any concern regarding installation and usage of this package.
13 |
14 | An up-to-date version of this package can be found at the website:
15 |
16 | http://purl.org/censi/2011/calibration
17 |
18 | Package contents
19 |
20 | The following is an overview of the contents.
21 |
22 | Directory src/
23 |
24 | This directory contains the C++ source files for implementing the method.
25 |
26 | The main executables created are:
27 |
28 |
29 | -
30 |
synchronizer
: Synchronizes laser data and odometry to obtain the tuple files (input to the algorithm).
31 |
32 |
33 | -
34 |
solver
: Given the tuple files, solves for the calibration parameters. This is the “meat” of the method.
35 |
36 |
37 |
38 | Directory scripts/
39 |
40 | This directory contains the data files and the scripts for running the experiments and visualizing the data.
41 |
42 | The main scripts are:
43 |
44 |
45 | scripts/run_all.sh
: Runs the complete calibration procedure.
46 |
47 | scripts/script_variables.sh
: This file contains the environment variables, executable paths, and parameters common to all the scripts.
48 |
49 |
50 | Directory data/
51 |
52 | This directory contains the raw data logs. The raw logs are called lstraight
, l90
, lmov
; these correspond to the configurations A,B,C in the paper.
53 |
54 | Inside each .tar.gz
, there are multiple experiments. See below for a description of the data format.
55 |
56 | Directory reference-output/
57 |
58 | This directory contains the output of the synchronization procedure and the results of calibration, as well as the intermediate results (in case one is not able to run the scan matching software).
59 |
60 | The intermediate result of the method is the creation of “tuple files”: the odometry and scan matching data is integrated to obtain a series of tuples, each containing average wheel velocities and scan matching result for the interval.
61 |
62 | For each configuration X:
63 |
64 |
65 | X.tuple
are the complete tuples
66 |
67 | X_i.tuple
are the tuples for the i-th subset
68 |
69 | X_results.json
are the calibration results in JSON
70 |
71 | X_results.m
… and in Matlab format
72 |
73 |
74 | Installation instructions
75 |
76 | The installation process has been tried on Mac OS X (10.5-10.6) and various versions of Ubuntu. With perhaps a few modifications, the software should run on all flavors of Unix.
77 |
78 | The first step is installing CSM. Please see the instructions at the website http://purl.org/censi/2007/csm.
79 |
80 | The minimal steps are as follows:
81 |
82 | $ git clone git://github.com/AndreaCensi/csm.git
83 | $ cd csm
84 | $ cmake .
85 | $ make
86 | $ make install
87 |
88 | Remember to point PKG_CONFIG_PATH
where you installed CSM. In the default case, this is /usr/local
:
89 |
90 | export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/:$PKG_CONFIG_PATH
91 |
92 | Compiling the calibration software does not require more dependencies than CSM itself (e.g., GSL).
93 |
94 | The installation is simple:
95 |
96 | $ cd src/
97 | $ cmake .
98 | $ make install
99 |
100 | Execution instructions
101 |
102 | In the directory scripts/
there is a file run_all.sh
that does the complete calibration process from the logged data.
103 |
104 | $ cd logs/
105 | $ ./run_all.sh
106 |
107 | Note that it might take some time. It is normal to see a few scan matching errors displayed; that is just bad data (synchronization issues between odometry and laser.)
108 |
109 | The script create_tuples.sh
is called by run_all.sh
and is the one responsible for processing the data with the scan matcher and running the synchronization between scan matching and odometry. It creates “tuple files” which correspond to a series of what in the paper are called “samples”. Basically, the tuples correspond to the input of the algorithm.
110 |
111 | Note that the reference-output/
directory contains the generated tuple files, so that the results can be reproduced even if the scan matcher cannot be installed.
112 |
113 |
114 |
115 | These are a few notes about the data formats used.
116 |
117 | All logs and intermediate results are in the JSON format. See the website http://www.json.org/ for more information (including libraries for reading the format easily for many different languages).
118 |
119 |
120 |
121 | The raw log files have this format:
122 |
123 | { "timestamp": [949, 943101],
124 | "readings": [ ...],
125 | "theta": [ ... ],
126 | "right": 0,
127 | "left": 0,
128 | "leftTimestamp": [ 949, 940807],
129 | "rightTimestamp": [ 949, 942685] }
130 |
131 | where:
132 |
133 |
134 | readings
is the array of range-finder readings.
135 |
136 | theta
is the direction of each reading.
137 |
138 | left
and right
are the encoder readings, in ticks.
139 |
140 | timestamp
is a two-shorts UNIX timestamp of when the laser data was taken;
141 |
142 | leftTimestamp
, rightTimestamp
are the timestamps for when the the encoder data was taken.
143 |
144 |
145 | (there are also other fields, not relevant for calibration)
146 |
147 |
148 |
149 | The tuples files are the result of running scan matching, and synchronization of scan matching and odometry data.
150 |
151 | The field T
is the interval; the fields phi_r
and phi_r
are the average wheel velocities, and sm
is the scan matching estimate.
152 |
180 |
--------------------------------------------------------------------------------
/ReadMe.txt:
--------------------------------------------------------------------------------
1 | Supplemental materials for "Simultaneous calibration of odometry and sensor parameters for mobile robots"
2 | ==========================================================================
3 |
4 | This archive contains C++ source code for the calibration method described
5 | in the paper, plus the raw data and scripts to reproduce the experiments,
6 | in the spirit of [reproducible research](http://reproducibleresearch.net/).
7 |
8 | Please contact Andrea Censi (andrea at cds.caltech.edu) for any concern
9 | regarding installation and usage of this package.
10 |
11 | An up-to-date version of this package can be found at the website:
12 |
13 |
14 |
15 |
16 |
17 | Package contents
18 | ---------------------------------------------------------------------------
19 |
20 | The following is an overview of the contents.
21 |
22 | ### Directory ``src/``
23 |
24 | This directory contains the C++ source files for implementing the method.
25 |
26 | The main executables created are:
27 |
28 | * ``synchronizer``: Synchronizes laser data and odometry to obtain
29 | the tuple files (input to the algorithm).
30 |
31 | * ``solver``: Given the tuple files, solves for the calibration parameters.
32 | This is the "meat" of the method.
33 |
34 |
35 |
36 | ### Directory ``scripts/``
37 |
38 | This directory contains the data files and the scripts for running
39 | the experiments and visualizing the data.
40 |
41 | The main scripts are:
42 |
43 | * ``scripts/run_all.sh``: Runs the complete calibration procedure.
44 | * ``scripts/script_variables.sh``: This file contains the
45 | environment variables, executable paths, and parameters common
46 | to all the scripts.
47 |
48 | ### Directory ``data/``
49 |
50 | This directory contains the raw data logs. The raw logs are called
51 | ``lstraight``, ``l90``, ``lmov``; these correspond to the configurations
52 | A,B,C in the paper.
53 |
54 | Inside each ``.tar.gz``, there are multiple experiments. See below for
55 | a description of the data format.
56 |
57 |
58 | ### Directory ``reference-output/``
59 |
60 | This directory contains the output of the synchronization
61 | procedure and the results of calibration, as well as the
62 | intermediate results (in case one is not able to run the
63 | scan matching software).
64 |
65 | The intermediate result of the method is the creation of
66 | "tuple files": the odometry and scan matching data is integrated
67 | to obtain a series of tuples, each containing average wheel
68 | velocities and scan matching result for the interval.
69 |
70 | For each configuration X:
71 |
72 | * ``X.tuple`` are the complete tuples
73 | * ``X_i.tuple`` are the tuples for the i-th subset
74 | * ``X_results.json`` are the calibration results in JSON
75 | * ``X_results.m`` ... and in Matlab format
76 |
77 |
78 | Installation instructions
79 | ---------------------------------------------------------------------------
80 |
81 | The installation process has been tried on Mac OS X (10.5-10.6) and various
82 | versions of Ubuntu. With perhaps a few modifications, the software should run
83 | on all flavors of Unix.
84 |
85 | The first step is installing CSM. Please see the instructions at the website
86 | .
87 |
88 | The minimal steps are as follows:
89 |
90 | $ git clone git://github.com/AndreaCensi/csm.git
91 | $ cd csm
92 | $ cmake .
93 | $ make
94 | $ make install
95 |
96 | Remember to point ``PKG_CONFIG_PATH`` where you installed CSM. In the default
97 | case, this is ``/usr/local``:
98 |
99 | export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/:$PKG_CONFIG_PATH
100 |
101 | Compiling the calibration software does not require more dependencies than
102 | CSM itself (e.g., GSL).
103 |
104 | The installation is simple:
105 |
106 | $ cd src/
107 | $ cmake .
108 | $ make install
109 |
110 |
111 | Execution instructions
112 | ---------------------------------------------------------------------------
113 |
114 | In the directory ``scripts/`` there is a file ``run_all.sh`` that does
115 | the complete calibration process from the logged data.
116 |
117 | $ cd logs/
118 | $ ./run_all.sh
119 |
120 | Note that it might take some time. It is normal to see a few scan matching
121 | errors displayed; that is just bad data (synchronization issues between
122 | odometry and laser.)
123 |
124 | The script ``create_tuples.sh`` is called by ``run_all.sh`` and is the
125 | one responsible for processing the data with the scan matcher and running
126 | the synchronization between scan matching and odometry. It creates
127 | "tuple files" which correspond to a series of what in the paper are called
128 | "samples". Basically, the tuples correspond to the input of the algorithm.
129 |
130 | Note that the ``reference-output/`` directory contains the generated tuple
131 | files, so that the results can be reproduced even if the scan matcher
132 | cannot be installed.
133 |
134 |
135 | Data formats
136 | ---------------------------------------------------------------------------
137 |
138 | These are a few notes about the data formats used.
139 |
140 | All logs and intermediate results are in the JSON format. See the website
141 | for more information (including libraries for reading
142 | the format easily for many different languages).
143 |
144 | ### Raw log files format
145 |
146 | The raw log files have this format:
147 |
148 | { "timestamp": [949, 943101],
149 | "readings": [ ...],
150 | "theta": [ ... ],
151 | "right": 0,
152 | "left": 0,
153 | "leftTimestamp": [ 949, 940807],
154 | "rightTimestamp": [ 949, 942685] }
155 |
156 | where:
157 |
158 | * ``readings`` is the array of range-finder readings.
159 | * ``theta`` is the direction of each reading.
160 | * ``left`` and ``right`` are the encoder readings, in ticks.
161 | * ``timestamp`` is a two-shorts UNIX timestamp of when the laser data was taken;
162 | * ``leftTimestamp``, ``rightTimestamp`` are the timestamps for when the
163 | the encoder data was taken.
164 |
165 | (there are also other fields, not relevant for calibration)
166 |
167 |
168 | ### Tuples files format
169 |
170 | The *tuples files* are the result of running scan matching, and
171 | synchronization of scan matching and odometry data.
172 |
173 | The field ``T`` is the interval; the fields ``phi_r`` and
174 | ``phi_r`` are the average wheel velocities, and ``sm`` is
175 | the scan matching estimate.
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
215 |
--------------------------------------------------------------------------------
/Summary.txt:
--------------------------------------------------------------------------------
1 | This archive contains C++ source code for the calibration method described
2 | in the paper, plus the raw data and scripts to reproduce the experiments,
3 | in the spirit of "Reproducible Research".
4 |
5 | Please contact Andrea Censi for any concern
6 | regarding installation and usage of this package.
7 |
8 | An up-to-date version of this package can be found at the website:
9 |
10 | http://purl.org/censi/2011/calibration
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/data/l90.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndreaCensi/calibration/026c7c3b21392e6143eea25c424dba69cc29614e/data/l90.tar.gz
--------------------------------------------------------------------------------
/data/lmov.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndreaCensi/calibration/026c7c3b21392e6143eea25c424dba69cc29614e/data/lmov.tar.gz
--------------------------------------------------------------------------------
/data/lstraight.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndreaCensi/calibration/026c7c3b21392e6143eea25c424dba69cc29614e/data/lstraight.tar.gz
--------------------------------------------------------------------------------
/reference-output/l90_0_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0878146, "l_diam": 0.0410529, "r_diam": 0.041384, "l_x": -0.00265427, "l_y": 0.00583491, "l_theta": -1.55197, "E_d": 1.00807, "E_b": 0.975718, "covariance": [ [ 1.53263e-06, 1.49619e-06, 6.45365e-06, -8.45585e-09, -7.06869e-08, 1.34922e-06 ], [ 1.49619e-06, 1.5725e-06, 6.53649e-06, -7.53002e-09, 4.93707e-08, 1.19557e-06 ], [ 6.45365e-06, 6.53649e-06, 2.78659e-05, -3.99052e-08, -3.49801e-08, 5.42463e-06 ], [ -8.45585e-09, -7.53002e-09, -3.99052e-08, 5.23236e-06, 1.55149e-07, -4.1681e-05 ], [ -7.06869e-08, 4.93707e-08, -3.49801e-08, 1.55149e-07, 2.78263e-06, -1.85146e-05 ], [ 1.34922e-06, 1.19557e-06, 5.42463e-06, -4.1681e-05, -1.85146e-05, 0.00689921 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/l90_0_results.m:
--------------------------------------------------------------------------------
1 | function res = l90_0_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0878146, ...
5 | 'l_diam', 0.0410529, ...
6 | 'r_diam', 0.041384, ...
7 | 'l_x', -0.00265427, ...
8 | 'l_y', 0.00583491, ...
9 | 'l_theta', -1.55197, ...
10 | 'E_d', 1.00807, ...
11 | 'E_b', 0.975718, ...
12 | 'covariance', [1.53263e-06, 1.49619e-06, 6.45365e-06, -8.45585e-09, -7.06869e-08, 1.34922e-06; 1.49619e-06, 1.5725e-06, 6.53649e-06, -7.53002e-09, 4.93707e-08, 1.19557e-06; 6.45365e-06, 6.53649e-06, 2.78659e-05, -3.99052e-08, -3.49801e-08, 5.42463e-06; -8.45585e-09, -7.53002e-09, -3.99052e-08, 5.23236e-06, 1.55149e-07, -4.1681e-05; -7.06869e-08, 4.93707e-08, -3.49801e-08, 1.55149e-07, 2.78263e-06, -1.85146e-05; 1.34922e-06, 1.19557e-06, 5.42463e-06, -4.1681e-05, -1.85146e-05, 0.00689921])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/l90_1_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0881706, "l_diam": 0.0412731, "r_diam": 0.0414925, "l_x": -0.00252347, "l_y": 0.00580311, "l_theta": -1.56708, "E_d": 1.00531, "E_b": 0.979673, "covariance": [ [ 8.96027e-07, 8.62063e-07, 3.7459e-06, -3.01418e-09, -4.18678e-08, 6.34109e-07 ], [ 8.62063e-07, 9.17343e-07, 3.7909e-06, -2.33899e-09, 5.33692e-08, 5.15209e-07 ], [ 3.7459e-06, 3.7909e-06, 1.62049e-05, -1.57192e-08, 3.36938e-08, 2.44855e-06 ], [ -3.01418e-09, -2.33899e-09, -1.57192e-08, 7.96771e-06, 1.81379e-07, -6.31006e-05 ], [ -4.18678e-08, 5.33692e-08, 3.36938e-08, 1.81379e-07, 1.63964e-06, -2.76441e-05 ], [ 6.34109e-07, 5.15209e-07, 2.44855e-06, -6.31006e-05, -2.76441e-05, 0.0109162 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/l90_1_results.m:
--------------------------------------------------------------------------------
1 | function res = l90_1_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0881706, ...
5 | 'l_diam', 0.0412731, ...
6 | 'r_diam', 0.0414925, ...
7 | 'l_x', -0.00252347, ...
8 | 'l_y', 0.00580311, ...
9 | 'l_theta', -1.56708, ...
10 | 'E_d', 1.00531, ...
11 | 'E_b', 0.979673, ...
12 | 'covariance', [8.96027e-07, 8.62063e-07, 3.7459e-06, -3.01418e-09, -4.18678e-08, 6.34109e-07; 8.62063e-07, 9.17343e-07, 3.7909e-06, -2.33899e-09, 5.33692e-08, 5.15209e-07; 3.7459e-06, 3.7909e-06, 1.62049e-05, -1.57192e-08, 3.36938e-08, 2.44855e-06; -3.01418e-09, -2.33899e-09, -1.57192e-08, 7.96771e-06, 1.81379e-07, -6.31006e-05; -4.18678e-08, 5.33692e-08, 3.36938e-08, 1.81379e-07, 1.63964e-06, -2.76441e-05; 6.34109e-07, 5.15209e-07, 2.44855e-06, -6.31006e-05, -2.76441e-05, 0.0109162])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/l90_2_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0880557, "l_diam": 0.0412267, "r_diam": 0.0414503, "l_x": -0.0025152, "l_y": 0.00592963, "l_theta": -1.55253, "E_d": 1.00542, "E_b": 0.978396, "covariance": [ [ 1.45666e-06, 1.40625e-06, 6.09942e-06, -2.58693e-08, -9.35208e-08, 3.90479e-06 ], [ 1.40625e-06, 1.49069e-06, 6.16911e-06, -2.48622e-08, 5.00381e-08, 3.73912e-06 ], [ 6.09942e-06, 6.16911e-06, 2.63552e-05, -1.14575e-07, -8.06965e-08, 1.62854e-05 ], [ -2.58693e-08, -2.48622e-08, -1.14575e-07, 1.01842e-05, 3.50495e-07, -8.59871e-05 ], [ -9.35208e-08, 5.00381e-08, -8.06965e-08, 3.50495e-07, 2.63702e-06, -3.5011e-05 ], [ 3.90479e-06, 3.73912e-06, 1.62854e-05, -8.59871e-05, -3.5011e-05, 0.0137884 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/l90_2_results.m:
--------------------------------------------------------------------------------
1 | function res = l90_2_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0880557, ...
5 | 'l_diam', 0.0412267, ...
6 | 'r_diam', 0.0414503, ...
7 | 'l_x', -0.0025152, ...
8 | 'l_y', 0.00592963, ...
9 | 'l_theta', -1.55253, ...
10 | 'E_d', 1.00542, ...
11 | 'E_b', 0.978396, ...
12 | 'covariance', [1.45666e-06, 1.40625e-06, 6.09942e-06, -2.58693e-08, -9.35208e-08, 3.90479e-06; 1.40625e-06, 1.49069e-06, 6.16911e-06, -2.48622e-08, 5.00381e-08, 3.73912e-06; 6.09942e-06, 6.16911e-06, 2.63552e-05, -1.14575e-07, -8.06965e-08, 1.62854e-05; -2.58693e-08, -2.48622e-08, -1.14575e-07, 1.01842e-05, 3.50495e-07, -8.59871e-05; -9.35208e-08, 5.00381e-08, -8.06965e-08, 3.50495e-07, 2.63702e-06, -3.5011e-05; 3.90479e-06, 3.73912e-06, 1.62854e-05, -8.59871e-05, -3.5011e-05, 0.0137884])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/l90_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0880134, "l_diam": 0.0411796, "r_diam": 0.0414408, "l_x": -0.00262327, "l_y": 0.00584952, "l_theta": -1.55772, "E_d": 1.00634, "E_b": 0.977926, "covariance": [ [ 3.91817e-07, 3.79263e-07, 1.643e-06, -3.83492e-09, -2.03582e-08, 6.33479e-07 ], [ 3.79263e-07, 4.01431e-07, 1.66301e-06, -3.56338e-09, 1.66528e-08, 5.87702e-07 ], [ 1.643e-06, 1.66301e-06, 7.10154e-06, -1.75235e-08, -4.5618e-09, 2.60234e-06 ], [ -3.83492e-09, -3.56338e-09, -1.75235e-08, 2.40973e-06, 7.24481e-08, -1.93703e-05 ], [ -2.03582e-08, 1.66528e-08, -4.5618e-09, 7.24481e-08, 7.15567e-07, -8.53942e-06 ], [ 6.33479e-07, 5.87702e-07, 2.60234e-06, -1.93703e-05, -8.53942e-06, 0.00323274 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/l90_results.m:
--------------------------------------------------------------------------------
1 | function res = l90_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0880134, ...
5 | 'l_diam', 0.0411796, ...
6 | 'r_diam', 0.0414408, ...
7 | 'l_x', -0.00262327, ...
8 | 'l_y', 0.00584952, ...
9 | 'l_theta', -1.55772, ...
10 | 'E_d', 1.00634, ...
11 | 'E_b', 0.977926, ...
12 | 'covariance', [3.91817e-07, 3.79263e-07, 1.643e-06, -3.83492e-09, -2.03582e-08, 6.33479e-07; 3.79263e-07, 4.01431e-07, 1.66301e-06, -3.56338e-09, 1.66528e-08, 5.87702e-07; 1.643e-06, 1.66301e-06, 7.10154e-06, -1.75235e-08, -4.5618e-09, 2.60234e-06; -3.83492e-09, -3.56338e-09, -1.75235e-08, 2.40973e-06, 7.24481e-08, -1.93703e-05; -2.03582e-08, 1.66528e-08, -4.5618e-09, 7.24481e-08, 7.15567e-07, -8.53942e-06; 6.33479e-07, 5.87702e-07, 2.60234e-06, -1.93703e-05, -8.53942e-06, 0.00323274])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lmov_0_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.08816, "l_diam": 0.0413154, "r_diam": 0.0414503, "l_x": -0.00601753, "l_y": -0.0387702, "l_theta": -1.86185, "E_d": 1.00327, "E_b": 0.979555, "covariance": [ [ 2.37214e-07, 2.23826e-07, 9.82558e-07, -1.04654e-07, -4.20344e-09, -2.73681e-06 ], [ 2.23826e-07, 2.25471e-07, 9.57127e-07, -1.06902e-07, 1.23114e-08, -2.79502e-06 ], [ 9.82558e-07, 9.57127e-07, 4.20888e-06, -4.5575e-07, -1.64045e-08, -1.17844e-05 ], [ -1.04654e-07, -1.06902e-07, -4.5575e-07, 3.37223e-06, -4.99209e-07, 3.57154e-05 ], [ -4.20344e-09, 1.23114e-08, -1.64045e-08, -4.99209e-07, 1.20135e-06, -5.59695e-06 ], [ -2.73681e-06, -2.79502e-06, -1.17844e-05, 3.57154e-05, -5.59695e-06, 0.000933108 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lmov_0_results.m:
--------------------------------------------------------------------------------
1 | function res = lmov_0_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.08816, ...
5 | 'l_diam', 0.0413154, ...
6 | 'r_diam', 0.0414503, ...
7 | 'l_x', -0.00601753, ...
8 | 'l_y', -0.0387702, ...
9 | 'l_theta', -1.86185, ...
10 | 'E_d', 1.00327, ...
11 | 'E_b', 0.979555, ...
12 | 'covariance', [2.37214e-07, 2.23826e-07, 9.82558e-07, -1.04654e-07, -4.20344e-09, -2.73681e-06; 2.23826e-07, 2.25471e-07, 9.57127e-07, -1.06902e-07, 1.23114e-08, -2.79502e-06; 9.82558e-07, 9.57127e-07, 4.20888e-06, -4.5575e-07, -1.64045e-08, -1.17844e-05; -1.04654e-07, -1.06902e-07, -4.5575e-07, 3.37223e-06, -4.99209e-07, 3.57154e-05; -4.20344e-09, 1.23114e-08, -1.64045e-08, -4.99209e-07, 1.20135e-06, -5.59695e-06; -2.73681e-06, -2.79502e-06, -1.17844e-05, 3.57154e-05, -5.59695e-06, 0.000933108])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lmov_1_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0884639, "l_diam": 0.0414784, "r_diam": 0.0416365, "l_x": -0.00607186, "l_y": -0.0386417, "l_theta": -1.86028, "E_d": 1.00381, "E_b": 0.982932, "covariance": [ [ 5.21005e-07, 4.8981e-07, 2.15235e-06, -4.76076e-07, 3.27168e-08, -1.24119e-05 ], [ 4.8981e-07, 4.93932e-07, 2.09404e-06, -4.82409e-07, 7.15354e-08, -1.25756e-05 ], [ 2.15235e-06, 2.09404e-06, 9.2213e-06, -2.05246e-06, 1.42665e-07, -5.31916e-05 ], [ -4.76076e-07, -4.82409e-07, -2.05246e-06, 1.08737e-05, -1.99243e-06, 0.000114184 ], [ 3.27168e-08, 7.15354e-08, 1.42665e-07, -1.99243e-06, 2.69927e-06, -1.80433e-05 ], [ -1.24119e-05, -1.25756e-05, -5.31916e-05, 0.000114184, -1.80433e-05, 0.00297924 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lmov_1_results.m:
--------------------------------------------------------------------------------
1 | function res = lmov_1_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0884639, ...
5 | 'l_diam', 0.0414784, ...
6 | 'r_diam', 0.0416365, ...
7 | 'l_x', -0.00607186, ...
8 | 'l_y', -0.0386417, ...
9 | 'l_theta', -1.86028, ...
10 | 'E_d', 1.00381, ...
11 | 'E_b', 0.982932, ...
12 | 'covariance', [5.21005e-07, 4.8981e-07, 2.15235e-06, -4.76076e-07, 3.27168e-08, -1.24119e-05; 4.8981e-07, 4.93932e-07, 2.09404e-06, -4.82409e-07, 7.15354e-08, -1.25756e-05; 2.15235e-06, 2.09404e-06, 9.2213e-06, -2.05246e-06, 1.42665e-07, -5.31916e-05; -4.76076e-07, -4.82409e-07, -2.05246e-06, 1.08737e-05, -1.99243e-06, 0.000114184; 3.27168e-08, 7.15354e-08, 1.42665e-07, -1.99243e-06, 2.69927e-06, -1.80433e-05; -1.24119e-05, -1.25756e-05, -5.31916e-05, 0.000114184, -1.80433e-05, 0.00297924])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lmov_2_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.088588, "l_diam": 0.0414757, "r_diam": 0.0416759, "l_x": -0.00571871, "l_y": -0.0387299, "l_theta": -1.85961, "E_d": 1.00483, "E_b": 0.984312, "covariance": [ [ 2.05636e-07, 1.90665e-07, 8.44684e-07, -9.14543e-08, -5.72653e-09, -2.37538e-06 ], [ 1.90665e-07, 1.92663e-07, 8.16749e-07, -9.39495e-08, 1.28215e-08, -2.43963e-06 ], [ 8.44684e-07, 8.16749e-07, 3.62734e-06, -4.00567e-07, -2.29259e-08, -1.02598e-05 ], [ -9.14543e-08, -9.39495e-08, -4.00567e-07, 2.9417e-06, -4.28687e-07, 3.08202e-05 ], [ -5.72653e-09, 1.28215e-08, -2.29259e-08, -4.28687e-07, 1.04124e-06, -4.61074e-06 ], [ -2.37538e-06, -2.43963e-06, -1.02598e-05, 3.08202e-05, -4.61074e-06, 0.000800985 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lmov_2_results.m:
--------------------------------------------------------------------------------
1 | function res = lmov_2_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.088588, ...
5 | 'l_diam', 0.0414757, ...
6 | 'r_diam', 0.0416759, ...
7 | 'l_x', -0.00571871, ...
8 | 'l_y', -0.0387299, ...
9 | 'l_theta', -1.85961, ...
10 | 'E_d', 1.00483, ...
11 | 'E_b', 0.984312, ...
12 | 'covariance', [2.05636e-07, 1.90665e-07, 8.44684e-07, -9.14543e-08, -5.72653e-09, -2.37538e-06; 1.90665e-07, 1.92663e-07, 8.16749e-07, -9.39495e-08, 1.28215e-08, -2.43963e-06; 8.44684e-07, 8.16749e-07, 3.62734e-06, -4.00567e-07, -2.29259e-08, -1.02598e-05; -9.14543e-08, -9.39495e-08, -4.00567e-07, 2.9417e-06, -4.28687e-07, 3.08202e-05; -5.72653e-09, 1.28215e-08, -2.29259e-08, -4.28687e-07, 1.04124e-06, -4.61074e-06; -2.37538e-06, -2.43963e-06, -1.02598e-05, 3.08202e-05, -4.61074e-06, 0.000800985])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lmov_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0883953, "l_diam": 0.0414217, "r_diam": 0.0415888, "l_x": -0.00587095, "l_y": -0.0387078, "l_theta": -1.86026, "E_d": 1.00403, "E_b": 0.98217, "covariance": [ [ 8.8498e-08, 8.25986e-08, 3.64517e-07, -6.25941e-08, 1.51585e-09, -1.63083e-06 ], [ 8.25986e-08, 8.33491e-08, 3.53411e-07, -6.36723e-08, 8.81045e-09, -1.65869e-06 ], [ 3.64517e-07, 3.53411e-07, 1.56324e-06, -2.71119e-07, 7.03626e-09, -7.00584e-06 ], [ -6.25941e-08, -6.36723e-08, -2.71119e-07, 1.59008e-06, -2.69296e-07, 1.67128e-05 ], [ 1.51585e-09, 8.81045e-09, 7.03626e-09, -2.69296e-07, 4.53146e-07, -2.55494e-06 ], [ -1.63083e-06, -1.65869e-06, -7.00584e-06, 1.67128e-05, -2.55494e-06, 0.000435694 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lmov_results.m:
--------------------------------------------------------------------------------
1 | function res = lmov_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0883953, ...
5 | 'l_diam', 0.0414217, ...
6 | 'r_diam', 0.0415888, ...
7 | 'l_x', -0.00587095, ...
8 | 'l_y', -0.0387078, ...
9 | 'l_theta', -1.86026, ...
10 | 'E_d', 1.00403, ...
11 | 'E_b', 0.98217, ...
12 | 'covariance', [8.8498e-08, 8.25986e-08, 3.64517e-07, -6.25941e-08, 1.51585e-09, -1.63083e-06; 8.25986e-08, 8.33491e-08, 3.53411e-07, -6.36723e-08, 8.81045e-09, -1.65869e-06; 3.64517e-07, 3.53411e-07, 1.56324e-06, -2.71119e-07, 7.03626e-09, -7.00584e-06; -6.25941e-08, -6.36723e-08, -2.71119e-07, 1.59008e-06, -2.69296e-07, 1.67128e-05; 1.51585e-09, 8.81045e-09, 7.03626e-09, -2.69296e-07, 4.53146e-07, -2.55494e-06; -1.63083e-06, -1.65869e-06, -7.00584e-06, 1.67128e-05, -2.55494e-06, 0.000435694])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lstraight_0_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.088735, "l_diam": 0.0415778, "r_diam": 0.041715, "l_x": -0.00583202, "l_y": 0.000371476, "l_theta": 0.00999903, "E_d": 1.0033, "E_b": 0.985945, "covariance": [ [ 7.31795e-09, 7.182e-09, 3.08937e-08, 2.6008e-12, -7.8049e-11, -1.57847e-09 ], [ 7.182e-09, 7.36907e-09, 3.10052e-08, 3.05479e-12, 2.7255e-10, -2.6096e-09 ], [ 3.08937e-08, 3.10052e-08, 1.33598e-07, -1.00028e-10, 4.24694e-10, -8.91678e-09 ], [ 2.6008e-12, 3.05479e-12, -1.00028e-10, 1.71904e-08, -2.75095e-10, -9.86937e-10 ], [ -7.8049e-11, 2.7255e-10, 4.24694e-10, -2.75095e-10, 3.89139e-08, -4.44359e-08 ], [ -1.57847e-09, -2.6096e-09, -8.91678e-09, -9.86937e-10, -4.44359e-08, 7.44888e-06 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lstraight_0_results.m:
--------------------------------------------------------------------------------
1 | function res = lstraight_0_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.088735, ...
5 | 'l_diam', 0.0415778, ...
6 | 'r_diam', 0.041715, ...
7 | 'l_x', -0.00583202, ...
8 | 'l_y', 0.000371476, ...
9 | 'l_theta', 0.00999903, ...
10 | 'E_d', 1.0033, ...
11 | 'E_b', 0.985945, ...
12 | 'covariance', [7.31795e-09, 7.182e-09, 3.08937e-08, 2.6008e-12, -7.8049e-11, -1.57847e-09; 7.182e-09, 7.36907e-09, 3.10052e-08, 3.05479e-12, 2.7255e-10, -2.6096e-09; 3.08937e-08, 3.10052e-08, 1.33598e-07, -1.00028e-10, 4.24694e-10, -8.91678e-09; 2.6008e-12, 3.05479e-12, -1.00028e-10, 1.71904e-08, -2.75095e-10, -9.86937e-10; -7.8049e-11, 2.7255e-10, 4.24694e-10, -2.75095e-10, 3.89139e-08, -4.44359e-08; -1.57847e-09, -2.6096e-09, -8.91678e-09, -9.86937e-10, -4.44359e-08, 7.44888e-06])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lstraight_1_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0891065, "l_diam": 0.0418219, "r_diam": 0.0419639, "l_x": -0.00570384, "l_y": -2.59458e-05, "l_theta": 0.0117653, "E_d": 1.0034, "E_b": 0.990072, "covariance": [ [ 7.76667e-09, 7.54915e-09, 3.25734e-08, 7.57012e-13, -1.00874e-10, -1.72091e-09 ], [ 7.54915e-09, 7.81927e-09, 3.2693e-08, 5.92027e-13, 4.27048e-10, -3.2205e-09 ], [ 3.25734e-08, 3.2693e-08, 1.41369e-07, -1.59473e-10, 7.01897e-10, -1.05113e-08 ], [ 7.57012e-13, 5.92027e-13, -1.59473e-10, 1.86649e-08, -3.55955e-10, 3.51451e-09 ], [ -1.00874e-10, 4.27048e-10, 7.01897e-10, -3.55955e-10, 4.06934e-08, -4.78241e-08 ], [ -1.72091e-09, -3.2205e-09, -1.05113e-08, 3.51451e-09, -4.78241e-08, 8.11254e-06 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lstraight_1_results.m:
--------------------------------------------------------------------------------
1 | function res = lstraight_1_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0891065, ...
5 | 'l_diam', 0.0418219, ...
6 | 'r_diam', 0.0419639, ...
7 | 'l_x', -0.00570384, ...
8 | 'l_y', -2.59458e-05, ...
9 | 'l_theta', 0.0117653, ...
10 | 'E_d', 1.0034, ...
11 | 'E_b', 0.990072, ...
12 | 'covariance', [7.76667e-09, 7.54915e-09, 3.25734e-08, 7.57012e-13, -1.00874e-10, -1.72091e-09; 7.54915e-09, 7.81927e-09, 3.2693e-08, 5.92027e-13, 4.27048e-10, -3.2205e-09; 3.25734e-08, 3.2693e-08, 1.41369e-07, -1.59473e-10, 7.01897e-10, -1.05113e-08; 7.57012e-13, 5.92027e-13, -1.59473e-10, 1.86649e-08, -3.55955e-10, 3.51451e-09; -1.00874e-10, 4.27048e-10, 7.01897e-10, -3.55955e-10, 4.06934e-08, -4.78241e-08; -1.72091e-09, -3.2205e-09, -1.05113e-08, 3.51451e-09, -4.78241e-08, 8.11254e-06])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lstraight_2_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0892719, "l_diam": 0.0418956, "r_diam": 0.0419852, "l_x": -0.00595008, "l_y": 9.61081e-05, "l_theta": 0.00639555, "E_d": 1.00214, "E_b": 0.99191, "covariance": [ [ 6.81667e-09, 6.65954e-09, 2.86838e-08, 2.20819e-12, -1.17014e-10, -7.37342e-10 ], [ 6.65954e-09, 6.84662e-09, 2.87499e-08, 2.34903e-12, 2.56226e-10, -1.83452e-09 ], [ 2.86838e-08, 2.87499e-08, 1.24015e-07, -1.07416e-10, 3.00778e-10, -5.47042e-09 ], [ 2.20819e-12, 2.34903e-12, -1.07416e-10, 1.48734e-08, -1.39472e-10, 6.24179e-10 ], [ -1.17014e-10, 2.56226e-10, 3.00778e-10, -1.39472e-10, 3.49991e-08, -4.01593e-08 ], [ -7.37342e-10, -1.83452e-09, -5.47042e-09, 6.24179e-10, -4.01593e-08, 6.57068e-06 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lstraight_2_results.m:
--------------------------------------------------------------------------------
1 | function res = lstraight_2_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0892719, ...
5 | 'l_diam', 0.0418956, ...
6 | 'r_diam', 0.0419852, ...
7 | 'l_x', -0.00595008, ...
8 | 'l_y', 9.61081e-05, ...
9 | 'l_theta', 0.00639555, ...
10 | 'E_d', 1.00214, ...
11 | 'E_b', 0.99191, ...
12 | 'covariance', [6.81667e-09, 6.65954e-09, 2.86838e-08, 2.20819e-12, -1.17014e-10, -7.37342e-10; 6.65954e-09, 6.84662e-09, 2.87499e-08, 2.34903e-12, 2.56226e-10, -1.83452e-09; 2.86838e-08, 2.87499e-08, 1.24015e-07, -1.07416e-10, 3.00778e-10, -5.47042e-09; 2.20819e-12, 2.34903e-12, -1.07416e-10, 1.48734e-08, -1.39472e-10, 6.24179e-10; -1.17014e-10, 2.56226e-10, 3.00778e-10, -1.39472e-10, 3.49991e-08, -4.01593e-08; -7.37342e-10, -1.83452e-09, -5.47042e-09, 6.24179e-10, -4.01593e-08, 6.57068e-06])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/lstraight_results.json:
--------------------------------------------------------------------------------
1 | { "axle": 0.0890519, "l_diam": 0.0417709, "r_diam": 0.0418957, "l_x": -0.00581279, "l_y": 0.000185606, "l_theta": 0.00949588, "E_d": 1.00299, "E_b": 0.989465, "covariance": [ [ 2.40635e-09, 2.35815e-09, 1.0142e-08, 6.94695e-13, -2.83484e-11, -4.68241e-10 ], [ 2.35815e-09, 2.42122e-09, 1.01746e-08, 7.69756e-13, 9.22658e-11, -8.18211e-10 ], [ 1.0142e-08, 1.01746e-08, 4.38323e-08, -3.48432e-11, 1.38396e-10, -2.73703e-09 ], [ 6.94695e-13, 7.69756e-13, -3.48432e-11, 5.62752e-09, -8.53495e-11, 1.44416e-10 ], [ -2.83484e-11, 9.22658e-11, 1.38396e-10, -8.53495e-11, 1.26646e-08, -1.45311e-08 ], [ -4.68241e-10, -8.18211e-10, -2.73703e-09, 1.44416e-10, -1.45311e-08, 2.44109e-06 ] ] }
2 |
--------------------------------------------------------------------------------
/reference-output/lstraight_results.m:
--------------------------------------------------------------------------------
1 | function res = lstraight_results
2 | res = ...
3 | { ...
4 | struct('axle', 0.0890519, ...
5 | 'l_diam', 0.0417709, ...
6 | 'r_diam', 0.0418957, ...
7 | 'l_x', -0.00581279, ...
8 | 'l_y', 0.000185606, ...
9 | 'l_theta', 0.00949588, ...
10 | 'E_d', 1.00299, ...
11 | 'E_b', 0.989465, ...
12 | 'covariance', [2.40635e-09, 2.35815e-09, 1.0142e-08, 6.94695e-13, -2.83484e-11, -4.68241e-10; 2.35815e-09, 2.42122e-09, 1.01746e-08, 7.69756e-13, 9.22658e-11, -8.18211e-10; 1.0142e-08, 1.01746e-08, 4.38323e-08, -3.48432e-11, 1.38396e-10, -2.73703e-09; 6.94695e-13, 7.69756e-13, -3.48432e-11, 5.62752e-09, -8.53495e-11, 1.44416e-10; -2.83484e-11, 9.22658e-11, 1.38396e-10, -8.53495e-11, 1.26646e-08, -1.45311e-08; -4.68241e-10, -8.18211e-10, -2.73703e-09, 1.44416e-10, -1.45311e-08, 2.44109e-06])...
13 | };
14 |
--------------------------------------------------------------------------------
/reference-output/version_string:
--------------------------------------------------------------------------------
1 | sets=l90 lmov lstraight\ndecimate_period=4\nsm_options=-restart 0 -recover_from_error 1 -max_iterations 1000 -min_reading 0.3 -max_angular_correction_deg 10 -max_linear_correction 0.05 -epsilon_xy 0.000001 -epsilon_theta 0.000001 \nsynchronizer_options=-tk_threshold 5 -perc_threshold 0.95 -time_tolerance 0.5\nsolver_options=-mode 0 -outliers_iterations 4
2 |
--------------------------------------------------------------------------------
/scripts/copy_results.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | src=last_tuples
3 | dest=../submitted/experiments
4 | mkdir -p $dest
5 |
6 | cp -a $src/var*.eps $dest
7 | cp -a $src/*correlation*.eps $dest
8 | cp -a $src/lstraight_res*.eps $dest
9 | cp -a $src/*.tex $dest
10 |
11 | for a in $dest/*.eps; do
12 | echo "epstopdf $a"
13 | epstopdf $a;
14 | done
15 |
--------------------------------------------------------------------------------
/scripts/create_pictures.m:
--------------------------------------------------------------------------------
1 | function res = create_pictures(tuple_dir)
2 |
3 | clear functions
4 | addpath(tuple_dir)
5 | tuple_files = dir(sprintf('%s/*.tuple', tuple_dir));
6 |
7 | res = {};
8 |
9 | for i=1:numel(tuple_files)
10 | [pathstr, basename, ext, versn] = fileparts(tuple_files(i).name);
11 |
12 | results_file = sprintf('%s_results', basename);
13 | l = eval(results_file); l = l{1};
14 | l.basename = basename;
15 | res{end+1} = l;
16 | end
17 |
18 |
19 |
20 | % compute Jij as params 7-10
21 |
22 | for i=1:numel(res)
23 | % Original: res{i}.x = [res{i}.l_diam res{i}.r_diam res{i}.axle res{i}.l_x res{i}.l_y res{i}.l_theta];
24 | res{i}.x = [res{i}.l_diam/2 res{i}.r_diam/2 res{i}.axle res{i}.l_x res{i}.l_y res{i}.l_theta];
25 |
26 | % J11 = r_l /2
27 | % Original: res{i}.x(7) = res{i}.x(1) / 4;
28 | res{i}.x(7) = res{i}.x(1) / 2;
29 |
30 | df_dx = [1/4 0 0 0 0 0 ];
31 | res{i}.covariance(1:6,7) = res{i}.covariance(1:6,1:6) * df_dx';
32 | res{i}.covariance(7,1:6) = res{i}.covariance(1:6,7)';
33 | res{i}.covariance(7,7) = df_dx * res{i}.covariance(1:6,1:6) * df_dx';
34 |
35 | % J12
36 | % Original: res{i}.x(8) = res{i}.x(2) / 4;
37 | res{i}.x(8) = res{i}.x(2) / 2;
38 |
39 | df_dx = [0 1/4 0 0 0 0 0];
40 | res{i}.covariance(1:7,8) = res{i}.covariance(1:7,1:7) * df_dx';
41 | res{i}.covariance(8,1:7) = res{i}.covariance(1:7,8)';
42 | res{i}.covariance(8,8) = df_dx * res{i}.covariance(1:7,1:7) * df_dx';
43 |
44 |
45 | % J21
46 | a = res{i}.x(1);
47 | b = res{i}.x(3);
48 | f = - 0.5*a / b;
49 | df_da = - 0.5/b;
50 | df_db = + 0.5*a/b^2;
51 | df_dx = [df_da 0 df_db 0 0 0 0 0];
52 |
53 | res{i}.x(9) = f;
54 | res{i}.covariance(1:8,9) = res{i}.covariance(1:8,1:8) * df_dx';
55 | res{i}.covariance(9,1:8) = res{i}.covariance(1:8,9)';
56 | res{i}.covariance(9,9) = df_dx * res{i}.covariance(1:8,1:8) * df_dx';
57 |
58 | % J22
59 | a = res{i}.x(2);
60 | b = res{i}.x(3);
61 | f = 0.5 * a / b;
62 | df_da = 0.5 /b;
63 | df_db = -0.5*a/b^2;
64 | df_dx = [df_da df_db];
65 | covx = res{i}.covariance([2 3],[2 3]);
66 | covf = df_dx * covx * df_dx';
67 |
68 | res{i}.x(10) = f;
69 |
70 | df_dx = [0 df_da df_db 0 0 0 0 0 0];
71 |
72 | res{i}.x(10) = f;
73 | res{i}.covariance(1:9,10) = res{i}.covariance(1:9,1:9) * df_dx';
74 | res{i}.covariance(10,1:9) = res{i}.covariance(1:9,10)';
75 | res{i}.covariance(10,10) = df_dx * res{i}.covariance(1:9,1:9) * df_dx';
76 |
77 |
78 | [s,R] = cov2corr(res{i}.covariance);
79 | res{i}.corr = R;
80 | end
81 |
82 |
83 |
84 |
85 |
86 | figure;
87 |
88 | nr=3;nc=4;
89 |
90 | titles = { 'r_L','r_R','b','l_x','l_y','l_\theta','J11','J12','J21','J22'};
91 | simpletitlestex = { 'r_L','r_R','b','l_x','l_y','l_\theta','J_{11}','J_{12}','J_{21}','J_{22}'};
92 | titlestex = { 'r_{\mathrm{L}}','r_{\mathrm{R}}','b','\ell_x','\ell_y','\ell_\theta','J_{11}','J_{12}','J_{21}','J_{22}'};
93 |
94 | titlestexstr = {}; for i=1:numel(titlestex); titlestexstr{i} = sprintf('$\\rule{0pt}{4mm}%s\\rule{2mm}{0pt}$', titlestex{i}); end
95 |
96 | scales = { 1000, 1000, 1000, 1000, 1000, 180/pi, 1000, 1000, 180/pi, 180/pi};
97 | units = { 'mm','mm','mm','mm','mm', 'deg','mm/s','mm/s','deg/s','deg/s'};
98 |
99 | names={};
100 | for i=1:numel(res)
101 | names{i} = res{i}.basename;
102 | end
103 |
104 | for v=1:10
105 | subplot(nr,nc,v)
106 | hold on
107 |
108 | for i=1:numel(res)
109 | val = res{i}.x(v) ;
110 |
111 | % if (i == 1) | (i==2)
112 | % % quick fix for radius/diameter problem
113 | % val = val / 2;
114 | % end
115 |
116 | sigma = sqrt( res{i}.covariance(v,v) );
117 | errorbar(i, scales{v}*val, scales{v}* 3*sigma);
118 | end
119 | ylabel(units{v})
120 | set(gca,'XTick',1:numel(res))
121 | set(gca,'XTickLabel',names);
122 |
123 | title(titles{v})
124 | end
125 |
126 |
127 |
128 | names={};
129 | for i=1:numel(res)
130 | names{i} = res{i}.basename;
131 | end
132 | names
133 |
134 | bigx=6.5; bigy=2.5;
135 | % smallx=4.5; smally=2.5;
136 | % all same size
137 | smallx=6.5; smally=2.5;
138 | sizex = {bigx,bigx,bigx,bigx,bigx,bigx,smallx,smallx,smallx,smallx};
139 | sizey = {bigy,bigy,bigy,bigy,bigy,bigy,smally,smally,smally,smally};
140 |
141 | names = {'A','A1','A2','A3','B','B1','B2','B3','C','C1','C2','C3'}
142 | namestex = {'A','A_1','A_2','A_3','B','B_1','B_2','B_3','C','C_1','C_2','C_3'};
143 | for i=1:numel(namestex); namestex{i} = sprintf('$\\rule{0pt}{3mm}%s$', namestex{i}); end
144 | %for i=1:numel(namestex); namestex{i} = sprintf('$%s$', namestex{i}); end
145 |
146 | tables_vars = { 1:6, 7:10, 1:10 };
147 |
148 | for t=1:numel(tables_vars)
149 | f = fopen(sprintf('%s/bigtable%d.tex',tuple_dir, t), 'w');
150 | fprintf(f, '\\begin{tabular}{|r|c|c|c|c|c|c|c|c|c|c|}\n')
151 | fprintf(f, '\\hline\n')
152 | fprintf(f, ' ')
153 |
154 | tvars = tables_vars{t};
155 |
156 | for tv=1:numel(tvars)
157 | v = tables_vars{t}(tv);
158 | fprintf(f, '& %s (%s)', titlestexstr{v}, units{v});
159 | end
160 | fprintf(f, '\\\\ \n')
161 | fprintf(f, '\\hline\n')
162 |
163 | for i=1:numel(res)
164 |
165 | if mod(i,4) == 1
166 | fprintf(f, '\\hline\n')
167 | end
168 |
169 | fprintf(f, '%s & ', namestex{i});
170 |
171 | for tv=1:numel(tvars)
172 | v = tvars(tv);
173 | val = scales{v}* res{i}.x(v) ;
174 | sigma = scales{v}* sqrt( res{i}.covariance(v,v) );
175 | fprintf(f, '$%.2f \\pm %.2f$', val, sigma );
176 | if tv b
240 | pc = floor(res{i}.corr(a,b) * 100);
241 | if abs(pc) == 100
242 | pc = 99 *sign(pc);
243 | end
244 | if pc > 0
245 | s = sprintf('+.%02d', abs(pc));
246 | else
247 | s = sprintf('-.%02d', abs(pc));
248 | end
249 | my_fonts(text(a+0.1,b+0.5,s));
250 | end
251 | end
252 | end
253 |
254 | set(gca,'XTick',(1:10) + 0.6)
255 | set(gca,'XTickLabel',titles);
256 | set(gca,'YTick',(1:10) + 0.6)
257 | set(gca,'YTickLabel',titles);
258 |
259 | format_ticks(gca, titlestexstr, titlestexstr, [],[],[],[], 0, 0);
260 |
261 | my_fonts(gca)
262 |
263 | print('-depsc', sprintf('%s/%s_correlation.eps',tuple_dir,res{i}.basename))
264 |
265 | close(f)
266 | end
267 |
268 |
269 | %%%%%%%% Only the numbers
270 | for i=1:numel(res)
271 | f = my_figure(8,8);
272 |
273 | % M = [res{i}.corr res{i}.corr(:,end); res{i}.corr(end,:) 0];
274 | M = zeros(11,11);
275 | % all white
276 | colormap([1 1 1])
277 | pcolor(M);
278 |
279 | for a=1:10
280 | for b=1:10
281 | if a > b
282 | pc = floor(res{i}.corr(a,b) * 100);
283 | if abs(pc) == 100
284 | pc = 99 *sign(pc);
285 | end
286 | if pc > 0
287 | s = sprintf('+.%02d', abs(pc));
288 | else
289 | s = sprintf('-.%02d', abs(pc));
290 | end
291 | my_fonts(text(a+0.1,b+0.5,s));
292 | end
293 | end
294 | end
295 |
296 | set(gca,'XTick',(1:10) + 0.6)
297 | set(gca,'XTickLabel',titles);
298 | set(gca,'YTick',(1:10) + 0.6)
299 | set(gca,'YTickLabel',titles);
300 |
301 | format_ticks(gca, titlestexstr, titlestexstr, [],[],[],[], 0, 0);
302 |
303 | my_fonts(gca)
304 |
305 | print('-depsc', sprintf('%s/%s_correlation_bw.eps',tuple_dir,res{i}.basename))
306 |
307 | close(f)
308 | end
309 |
310 |
311 |
312 |
313 |
314 | fprintf('And now the long part (press enter)...\n')
315 | pause
316 |
317 |
318 | for i=1:numel(res)
319 | iterations = dir(sprintf('%s/%s_results_iter*.asc', tuple_dir, res{i}.basename));
320 | for a=1:numel(iterations)
321 | file = sprintf('%s/%s',tuple_dir,iterations(a).name);
322 | [pathstr, basename, ext] = fileparts(file);
323 | prefix = sprintf('%s/%s',tuple_dir, basename);
324 |
325 | create_pictures_iteration(file,prefix);
326 | end
327 |
328 | end
329 |
330 |
331 |
332 |
333 |
334 |
335 |
--------------------------------------------------------------------------------
/scripts/create_pictures_iteration.m:
--------------------------------------------------------------------------------
1 | function create_pictures_iteration(iteration_file, prefix)
2 |
3 |
4 | if exist(sprintf('%s_sm.eps', prefix))
5 | fprintf('Already did %s -- remove files if you want to do it again\n', prefix);
6 | return
7 | end
8 |
9 | fprintf('Drawing %s\n', prefix);
10 |
11 | fclose = @(f) close(f);
12 | fsizex = 5;
13 | fsizey = 3;
14 |
15 |
16 | d = load(iteration_file)';
17 |
18 | T = d(1,:);
19 | phi_r = d(2,:);
20 | phi_l = d(3,:);
21 |
22 | sm = d(4:6,:);
23 | o = d(7:9,:);
24 |
25 | err = d(10:12,:);
26 |
27 | est_sm = d(13:15,:);
28 | err_sm = d(16:18,:);
29 |
30 |
31 | time = [T(1)];
32 | for i=2:numel(T)
33 | time(i) = time(i-1) + T(i);
34 | end
35 |
36 |
37 | f=my_figure(fsizex*2,fsizey); nr=1;nc=2;
38 | subplot(nr,nc,1);
39 | h=plot(sm(1,:)*1000,sm(2,:)*1000,'.');
40 | set(h,'MarkerSize',1)
41 | my_fonts(xlabel('mm'))
42 | my_fonts(ylabel('mm'))
43 | axis('equal')
44 | my_fonts(title('scan matching x,y'));
45 | my_fonts(gca);
46 |
47 | subplot(nr,nc,2);
48 | hist(rad2deg(sm(3,:)),100);
49 | my_fonts(xlabel('deg'))
50 | my_fonts(title('scan matching theta'));
51 | my_fonts(gca);
52 |
53 | print('-depsc2', sprintf('%s_sm.eps', prefix))
54 | fclose(f)
55 |
56 |
57 | f=my_figure(fsizex,fsizey);
58 | plot(time, phi_l,'b-'); hold on;
59 | plot(time, phi_r,'r-')
60 | my_fonts(xlabel('time (s)'))
61 | my_fonts(ylabel('speed (rad/s)'))
62 | my_fonts(legend('\omega_l','\omega_r'))
63 | my_fonts(title('velocity profile'))
64 | my_fonts(gca);
65 | print('-depsc2', sprintf('%s_vel.eps', prefix))
66 | fclose(f)
67 |
68 |
69 | f=my_figure(fsizex*2,fsizey); nr=1;nc=2;
70 | subplot(nr,nc,1);
71 | h=plot(o(1,:)*1000,o(2,:)*1000,'.');
72 | set(h,'MarkerSize',1)
73 | my_fonts(xlabel('mm'))
74 | my_fonts(ylabel('mm'))
75 | axis('equal')
76 | my_fonts(title('motion x,y'));
77 | my_fonts(gca);
78 |
79 | subplot(nr,nc,2);
80 | hist(rad2deg(o(3,:)),100);
81 | my_fonts(xlabel('deg'))
82 | my_fonts(ylabel('samples'));
83 | my_fonts(title('motion theta'));
84 | my_fonts(gca);
85 |
86 | print('-depsc2', sprintf('%s_motion.eps', prefix))
87 | fclose(f)
88 |
89 |
90 |
91 | f=my_figure(fsizex*4,fsizey); nr=1;nc=4;
92 |
93 | subplot(nr,nc,1);
94 | h=plot(err(1,:)*1000,err(2,:)*1000,'.');
95 | set(h,'MarkerSize',1)
96 | my_fonts(xlabel('mm'))
97 | my_fonts(ylabel('mm'))
98 | axis('equal')
99 | my_fonts(title('error x,y'));
100 | my_fonts(gca);
101 |
102 | subplot(nr,nc,2);
103 | hist(err(1,:)*1000,100);
104 | my_fonts(xlabel('mm'))
105 | my_fonts(title('error x'));
106 | my_fonts(gca);
107 |
108 | subplot(nr,nc,3);
109 | hist(err(2,:)*1000,100);
110 | my_fonts(xlabel('mm'))
111 | my_fonts(title('error y'));
112 | my_fonts(gca);
113 |
114 | subplot(nr,nc,4);
115 | hist(rad2deg(err(3,:)),100);
116 | my_fonts(xlabel('deg'))
117 | my_fonts(title('error theta'));
118 | my_fonts(gca);
119 |
120 | print('-depsc2', sprintf('%s_errors.eps', prefix))
121 | fclose(f)
122 |
123 |
124 |
125 | f=my_figure(fsizex*2,fsizey); nr=1;nc=2;
126 |
127 | subplot(nr,nc,1);
128 | h=plot(est_sm(1,:)*1000,est_sm(2,:)*1000,'.');
129 | set(h,'MarkerSize',1)
130 | my_fonts(xlabel('mm'))
131 | my_fonts(ylabel('mm'))
132 | axis('equal')
133 | my_fonts(title('estimated sm x,y'));
134 | my_fonts(gca);
135 |
136 | subplot(nr,nc,2);
137 | hist(rad2deg(est_sm(3,:)),100);
138 | my_fonts(xlabel('deg'))
139 | my_fonts(title('estimated sm theta'));
140 | my_fonts(gca);
141 |
142 | print('-depsc2', sprintf('%s_estsm.eps', prefix))
143 | fclose(f)
144 |
145 |
146 |
147 |
148 | f=my_figure(fsizex,fsizey);
149 | my_fonts(title('scan matching \theta vs estimated'))
150 | plot(rad2deg(est_sm(3,:)), rad2deg(sm(3,:)), 'r.')
151 |
152 | hold on;
153 | m = max(abs(rad2deg(est_sm(3,:))));
154 | plot([-m m],[-m m],'k--');
155 | axis('equal')
156 | my_fonts(xlabel('scan matching (deg)'))
157 | my_fonts(ylabel('estimated from odo + calib (deg)'))
158 | my_fonts(gca);
159 |
160 | print('-depsc2', sprintf('%s_es.eps', prefix))
161 | fclose(f)
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/scripts/create_tuples.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e # exit on error
4 | set -o pipefail
5 | source script_variables.sh
6 |
7 |
8 | #Verify input
9 | if [ "$1" = "" ] || [ "$2" = "" ]; then
10 | echo "Usage:
11 | ./create_tuples.sh [data_path] [Calibration_path] [Scan_Matcher_path]"
12 | exit 1
13 | fi
14 |
15 | if [ "$3" = "" ]; then
16 | DATA=""
17 | else
18 | DATA="${3}/"
19 | fi
20 |
21 | if [ "$4" = "" ]; then
22 | PATH_CALIB="`pwd`/"
23 | else
24 | PATH_CALIB="${4}/"
25 | fi
26 |
27 | if [ "$5" = "" ]; then
28 | PATH_SM=""
29 | else
30 | PATH_SM="${5}/"
31 | fi
32 |
33 | #FILES
34 | LAS_FILE_BZ2="${DATA}${1}"
35 | ODO_FILE_BZ2="${DATA}${2}"
36 | LAS_FILE=`dirname ${LAS_FILE_BZ2}`/`basename $LAS_FILE_BZ2 .bz2`
37 | ODO_FILE=`dirname ${ODO_FILE_BZ2}`/`basename $ODO_FILE_BZ2 .bz2`
38 | SM_STATS_FILE="${LAS_FILE}_stats"
39 | SM_OUTPUT_FILE="${LAS_FILE}_out"
40 | TUPLE_FILE="${LAS_FILE}_tuple"
41 | OUT_CALIB_PARAM_FILE="${LAS_FILE}_calibParams"
42 |
43 |
44 |
45 | #funzione per rimuovere file già esistenti
46 | checkrm() {
47 | local path="$1"
48 | if [ -e $path ]; then
49 | echo "Removing old file: $path"
50 | rm $path
51 | fi
52 | }
53 |
54 | check_exec "bunzip2"
55 | check_existence ${LAS_FILE_BZ2}
56 | check_existence ${ODO_FILE_BZ2}
57 | checkrm ${SM_STATS_FILE}
58 | checkrm ${TUPLE_FILE}
59 | checkrm ${OUT_CALIB_PARAM_FILE}
60 | checkrm ${LAS_FILE}
61 | checkrm ${ODO_FILE}
62 |
63 |
64 | # Decompress files
65 | echo -n "$0: Uncompressing files..."
66 | `bunzip2 -k "$LAS_FILE_BZ2"`
67 | if [ ! ${LAS_FILE_BZ2} == ${ODO_FILE_BZ2} ]; then
68 | `bunzip2 -k "$ODO_FILE_BZ2"`
69 | fi
70 | echo "done."
71 |
72 | #Scan Matcher
73 |
74 | echo "$0: Decimating file..."
75 |
76 | # cat $LAS_FILE | ld_remove_doubles -epsilon 0.4 > $LAS_FILE.sel
77 |
78 | cat ${LAS_FILE} | ${json_decimate} -period ${decimate_period} > ${LAS_FILE}.sel
79 |
80 |
81 | echo "$0: Scan Matcher... "
82 | ${sm2} -in ${LAS_FILE}.sel -out ${SM_OUTPUT_FILE} -out_stats ${SM_STATS_FILE} ${sm_options}
83 |
84 | echo "$0: Syncronization..."
85 | ${synchronizer} -las_file ${SM_STATS_FILE} -odo_file ${ODO_FILE} -output ${TUPLE_FILE} ${synchronizer_options}
86 | echo "done"
87 |
88 | ## THAT'S ALL FOLKS ##
89 |
--------------------------------------------------------------------------------
/scripts/errorbar_tick.m:
--------------------------------------------------------------------------------
1 | function errorbar_tick(h,w,xtype)
2 | %ERRORBAR_TICK Adjust the width of errorbars
3 | % ERRORBAR_TICK(H) adjust the width of error bars with handle H.
4 | % Error bars width is given as a ratio of X axis length (1/80).
5 | % ERRORBAR_TICK(H,W) adjust the width of error bars with handle H.
6 | % The input W is given as a ratio of X axis length (1/W). The result
7 | % is independent of the x-axis units. A ratio between 20 and 80 is usually fine.
8 | % ERRORBAR_TICK(H,W,'UNITS') adjust the width of error bars with handle H.
9 | % The input W is given in the units of the current x-axis.
10 | %
11 | % See also ERRORBAR
12 | %
13 |
14 | % Author: Arnaud Laurent
15 | % Creation : Jan 29th 2009
16 | % MATLAB version: R2007a
17 | %
18 | % Notes: This function was created from a post on the french forum :
19 | % http://www.developpez.net/forums/f148/environnements-developpement/matlab/
20 | % Author : Jerome Briot (Dut)
21 | % http://www.mathworks.com/matlabcentral/newsreader/author/94805
22 | % http://www.developpez.net/forums/u125006/dut/
23 | % It was further modified by Arnaud Laurent and Jerome Briot.
24 |
25 | % Check numbers of arguments
26 | error(nargchk(1,3,nargin))
27 |
28 | % Check for the use of V6 flag ( even if it is depreciated ;) )
29 | flagtype = get(h,'type');
30 |
31 | % Check number of arguments and provide missing values
32 | if nargin==1
33 | w = 80;
34 | end
35 |
36 | if nargin<3
37 | xtype = 'ratio';
38 | end
39 |
40 | % Calculate width of error bars
41 | if ~strcmpi(xtype,'units')
42 | dx = diff(get(gca,'XLim')); % Retrieve x limits from current axis
43 | w = dx/w; % Errorbar width
44 | end
45 |
46 | % Plot error bars
47 | if strcmpi(flagtype,'hggroup') % ERRORBAR(...)
48 |
49 | hh=get(h,'children'); % Retrieve info from errorbar plot
50 | x = get(hh(2),'xdata'); % Get xdata from errorbar plot
51 |
52 | x(4:9:end) = x(1:9:end)-w/2; % Change xdata with respect to ratio
53 | x(7:9:end) = x(1:9:end)-w/2;
54 | x(5:9:end) = x(1:9:end)+w/2;
55 | x(8:9:end) = x(1:9:end)+w/2;
56 |
57 | set(hh(2),'xdata',x(:)) % Change error bars on the figure
58 |
59 | else % ERRORBAR('V6',...)
60 |
61 | x = get(h(1),'xdata'); % Get xdata from errorbar plot
62 |
63 | x(4:9:end) = x(1:9:end)-w/2; % Change xdata with respect to the chosen ratio
64 | x(7:9:end) = x(1:9:end)-w/2;
65 | x(5:9:end) = x(1:9:end)+w/2;
66 | x(8:9:end) = x(1:9:end)+w/2;
67 |
68 | set(h(1),'xdata',x(:)) % Change error bars on the figure
69 |
70 | end
71 |
--------------------------------------------------------------------------------
/scripts/format_ticks.m:
--------------------------------------------------------------------------------
1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 | %% BEGIN HEADER
4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 | %Name: format_tick.m
7 | %
8 | %Usage: [hx,hy] = ...
9 | % format_tick(h,tickx,ticky,tickposx,tickposy,rotx,roty,offset,...
10 | % varargin);
11 | %
12 | %Description: Replace or appends XTickLabels and YTickLabels of axis handle
13 | % h with input tickx and ticky array
14 | %
15 | %***NOTE!***: BE SURE TO DELETE ANY PREVIOUS TEXT OBJECTS CREATED BY THIS
16 | % FUNCTION BEFORE RUNNING THIS ON THE SAME FIGURE TWICE
17 | %
18 | %Required Inputs:
19 | % h : handle of axis to change tick labels (can use gca)
20 | % tickx : cell array of tick labels or string to append to current
21 | % labels
22 | % (Defaults to appending degree symbols if not input)
23 | %
24 | %Optional Inputs
25 | % ticky : cell array of tick labels or string to append to current
26 | % labels (Can use [] or not specify to ignore)
27 | % tickposx : Vector of x positions where you want the tick labels
28 | % (Can use [] or not specify to ignore)
29 | % tickposy : Vector of y positions where you want the tick labels
30 | % (Can use [] or not specify to ignore)
31 | % rotx : Number of degrees to rotate x tick labels
32 | % (Can use [] or not specify to ignore) Default = 0.0
33 | % roty : Number of degrees to rotate y tick labels
34 | % (Can use [] or not specify to ignore) Default = 0.0
35 | % offset : Label offsets from axis in fraction of total range
36 | % (Can use [] or not specify to ignore) Default = 0.0
37 | %
38 | %Optional Inputs:%
39 | % Any standard text formatting parameters such as
40 | % 'FontSize','FontWeight',etc.
41 | % Use the same way you would in a set command after putting
42 | % in the required input values.
43 | %
44 | %Outputs:
45 | % hx: handle of text objects created for XTickLabels
46 | % hy: handle of text objects created for YTickLabels
47 | %
48 | %Function Calls:
49 | % None
50 | %
51 | %Required Data Files:
52 | % None
53 | %
54 | %
55 | %Example:
56 | % ;Example 1: Append Degree Symbols to X-Axis of a Plot
57 | % figure;
58 | % plot(1:10,1:10);
59 | % [hx,hy] = format_ticks(gca);
60 | %
61 | % ;Example 2: Append Degree Symbolts to X and Y Axes of a Plot
62 | % figure;
63 | % plot(1:10,1:10);
64 | % [hx,hy] = format_ticks(gca,'^{\circ}','^{\circ}');
65 | %
66 | % ;Example 2: Append Degree Symbolts to X and Y Axes of a Plot and
67 | % ; put a 45 degree tilt on them
68 | % figure;
69 | % plot(1:10,1:10);
70 | % [hx,hy] = format_ticks(gca,'^{\circ}','^{\circ}',[],[],45,45);
71 | %
72 | % ;Example 3: Make a plot with fractions on the x tick labels
73 | % figure
74 | % plot(1:10,1:10);
75 | % [hx,hy] = format_ticks(gca,{'$1$','$2\frac{1}{2}$','$9\frac{1}{2}$'},...
76 | % [],[1,2.5,9.5]);
77 | %
78 | % ;Example 4: Make a plot with degrees on y tick label and fractions
79 | % ; on x
80 | % figure
81 | % plot(0:10,0:10);
82 | % [hx,hy] = format_ticks(gca,...
83 | % {'$0$','$2\frac{1}{2}$','$5$','$7\frac{1}{2}$','$10$'},...
84 | % '$^{\circ}$',[0,2.5,5,7.5,10],[],0,45,[],...
85 | % 'FontSize',16,'FontWeight','Bold');
86 | %
87 | %Change Log:
88 | % 08/19/2007: Origin Version Created by Alex Hayes
89 | % (hayes@gps.caltech.edu)
90 | %
91 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 | %% BEGIN FUNCTION
94 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 | function [hx,hy] = ...
97 | format_ticks(h,tickx,ticky,tickposx,tickposy,rotx,roty,offset,varargin)
98 |
99 | %define axis text offset (percentage of total range)
100 | if ~exist('offset','var');
101 | offset = 0.02;
102 | elseif length(offset) == 0;
103 | offset = 0.02;
104 | end;
105 |
106 | %make sure the axis handle input really exists
107 | if ~exist('h','var');
108 | h = gca;
109 | warning(['Axis handle NOT Input, Defaulting to Current Axes, '...
110 | num2str(h)]);
111 | elseif length(h) == 0;
112 | h = gca;
113 | warning(['Axis Handle NOT Input, Defaulting to Current Axes, '...
114 | num2str(h)]);
115 | elseif ~ishandle(h(1))
116 | warning(['Input (' num2str(h(1)) ') is NOT an axis handle, ' ...
117 | 'defaulting to current axis, ' num2str(h)]);
118 | h = gca;
119 | end;
120 |
121 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122 | %%BEGIN: FIRST THE X-AXIS TICK LABELS
123 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 | %fix the XTickLabels if they have been erased in the past
125 | if length(get(h,'XTickLabel'))==0;
126 | set(h,'XTickLabel',get(h,'XTick'));
127 | end;
128 | %set the xtick positions if entered
129 | if exist('tickposx','var');
130 | if length(tickposx) > 0;
131 | set(h,'XTick',tickposx);
132 | end;
133 | tickposx = get(h,'XTick');
134 | set(h,'XTickLabel',tickposx);
135 | end;
136 | %make sure the xtick positions are in the xlimit range
137 | if exist('tickposx','var');
138 | if length(tickposx) > 0;
139 | lim = get(h,'XLim');
140 | if lim(1) > min(tickposx);
141 | lim(1) = min(tickposx);
142 | end;
143 | if lim(2) < max(tickposx);
144 | lim(2) = max(tickposx);
145 | end;
146 | set(h,'XLim',lim);
147 | end;
148 | end;
149 | %get the tick labels and positions if the user did not input them
150 | if ~exist('tickx','var');
151 | tickx = get(h,'XTickLabel');
152 | if ischar(tickx);
153 | temp = tickx;
154 | tickx = cell(1,size(temp,1));
155 | for j=1:size(temp,1);
156 | tickx{j} = strtrim( temp(j,:) );
157 | end;
158 | end;
159 | append = '^{\circ}';
160 | for j=1:length(tickx);
161 | tickx{j} = [tickx{j} append];
162 | end;
163 | elseif length(tickx) == 0;
164 | tickx = get(h,'XTickLabel');
165 | if ischar(tickx);
166 | temp = tickx;
167 | tickx = cell(1,size(temp,1));
168 | for j=1:size(temp,1);
169 | tickx{j} = strtrim( temp(j,:) );
170 | end;
171 | end;
172 | append = '^{\circ}';
173 | for j=1:length(tickx);
174 | tickx{j} = [tickx{j} append];
175 | end;
176 | elseif isstr(tickx);
177 | append = tickx;
178 | tickx = get(h,'XTickLabel');
179 | if ischar(tickx);
180 | temp = tickx;
181 | tickx = cell(1,size(temp,1));
182 | for j=1:size(temp,1);
183 | tickx{j} = strtrim( temp(j,:) );
184 | end;
185 | end;
186 | if strcmp(append(1),'$');
187 | for j=1:length(tickx);
188 | tickx{j} = ['$' tickx{j} append(2:end)];
189 | end;
190 | else;
191 | for j=1:length(tickx);
192 | tickx{j} = [tickx{j} append];
193 | end;
194 | end;
195 | elseif ~iscell(tickx );
196 | warning(['Input TICKX variable is not a compatible string ' ...
197 | 'or cell array! Returning...']);
198 | return;
199 | end;
200 | %find out if we have to use the LaTex interpreter
201 | temp = tickx{1};
202 | if strcmp(temp(1),'$');
203 | latex_on = 1;
204 | else;
205 | latex_on = 0;
206 | end;
207 | %erase the current tick label
208 | set(h,'XTickLabel',{});
209 | %get the x tick positions if the user did not input them
210 | if ~exist('tickposx','var');
211 | tickposx = get(h,'XTick');
212 | elseif length(tickx) == 0;
213 | tickposx = get(h,'XTick');
214 | end;
215 | %get the y tick positions if the user did not input them
216 | if ~exist('tickposy','var');
217 | tickposy = get(h,'YTick');
218 | elseif length(tickposy) == 0;
219 | tickposy = get(h,'YTick');
220 | end;
221 | %set the new tick positions
222 | set(h,'YTick',tickposy);
223 | set(h,'XTick',tickposx);
224 | %check the lengths of the xtick positions and xtick labels
225 | l1 = length(tickx);
226 | l2 = length(tickposx);
227 | if l1==0;
228 | set(h,'XTickLabel',tickx);
229 | end;
230 | if l1~=l2;
231 | disp(['Length of XTick = ' num2str(length(tickposx))]);
232 | disp(['Length of XTickLabel = ' num2str(length(tickx))]);
233 | if l2 < l1;
234 | warning(['Reducing Length of XTickLabel!']);
235 | else;
236 | warning(['Reducing Length of XTick!']);
237 | end;
238 | l3 = min([l1,l2]);
239 |
240 |
241 | tickx = tickx{1:l3};
242 | tickposx = tickposx(1:l3);
243 | end;
244 | %set rotation to 0 if not input
245 | if ~exist('rotx','var');
246 | rotx = 0;
247 | elseif length(rotx) == 0;
248 | rotx = 0;
249 | end;
250 | %Convert the cell labels to a character string
251 | %tickx = char(tickx);
252 | tickx = cellstr(tickx);
253 | %Make the XTICKS!
254 | lim = get(h,'YLim');
255 | if min(tickposy) < lim(1);
256 | lim(1) = min(tickposy);
257 | end;
258 | if max(tickposy) > lim(2);
259 | lim(2) = max(tickposy);
260 | end;
261 | if rotx == 0;
262 | if latex_on;
263 | hx = text(tickposx,...
264 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposx),1),...
265 | tickx,'HorizontalAlignment','center',...
266 | 'VerticalAlignment','top','rotation',rotx,'interpreter','LaTex');
267 | else;
268 | hx = text(tickposx,...
269 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposx),1),...
270 | tickx,'HorizontalAlignment','center',...
271 | 'VerticalAlignment','top','rotation',rotx);
272 | end;
273 | elseif rotx < 0;
274 | if latex_on;
275 | hx = text(tickposx,...
276 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposx),1),...
277 | tickx,'HorizontalAlignment','left','interpreter','LaTex',...
278 | 'VerticalAlignment','middlefi','rotation',rotx);
279 | else;
280 | hx = text(tickposx,...
281 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposx),1),...
282 | tickx,'HorizontalAlignment','left',...
283 | 'VerticalAlignment','middle','rotation',rotx);
284 | end;
285 | else;
286 | if latex_on;
287 | hx = text(tickposx,...
288 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposx),1),...
289 | tickx,'HorizontalAlignment','right','interpreter','LaTex',...
290 | 'VerticalAlignment','middle','rotation',rotx);
291 | else;
292 | hx = text(tickposx,...
293 | repmat(lim(1)-offset*(lim(2)-lim(2)),length(tickposx),1),...
294 | tickx,'HorizontalAlignment','right',...
295 | 'VerticalAlignment','middle','rotation',rotx);
296 | end;
297 | end;
298 | %Get and set the text size and weight
299 | set(hx,'FontSize',get(h,'FontSize'));
300 | set(hx,'FontWeight',get(h,'FontWeight'));
301 |
302 | %Set the additional parameters if they were input
303 | if length(varargin) > 2;
304 | command_string = ['set(hx'];
305 | for j=1:2:length(varargin);
306 | command_string = [command_string ',' ...
307 | '''' varargin{j} ''',varargin{' num2str(j+1) '}'];
308 | end;
309 | command_string = [command_string ');'];
310 | eval(command_string);
311 | end;
312 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 | %%END: FIRST THE X-AXIS TICK LABELS
314 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315 |
316 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317 | %%BEGIN: NOW THE Y-AXIS TICK LABELS
318 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 | %only move forward if we are doing anything to the yticks
320 | if ~exist('ticky');
321 | hy = -1;
322 | elseif length(ticky)==0;
323 | hy = -1;
324 | else;
325 | %fix the YTickLabels if they have been erased in the past
326 | if length(get(h,'YTickLabel'))==0;
327 | set(h,'YTickLabel',get(h,'YTick'));
328 | end;
329 | %set the ytick positions if entered
330 | if exist('tickposy','var');
331 | if length(tickposy) > 0;
332 | set(h,'YTick',tickposy);
333 | set(h,'YTickLabel',tickposy);
334 | end;
335 | end;
336 | %make sure the xtick positions are in the xlimit range
337 | if exist('tickposy','var');
338 | if length(tickposy) > 0;
339 | lim = get(h,'YLim');
340 | if lim(1) > min(tickposy);
341 | lim(1) = min(tickposy);
342 | end;
343 | if lim(2) < max(tickposy);
344 | lim(2) = max(tickposy);
345 | end;
346 | set(h,'YLim',lim);
347 | end;
348 | end;
349 | %get the tick labels and positions if the user did not input them
350 | if ~exist('ticky','var');
351 | ticky = get(h,'YTickLabel');
352 | if ischar(ticky);
353 | temp = ticky;
354 | ticky = cell(1,size(temp,1));
355 | for j=1:size(temp,1);
356 | ticky{j} = strtrim( temp(j,:) );
357 | end;
358 | end;
359 | append = '^{\circ}';
360 | for j=1:length(ticky);
361 | ticky{j} = [ticky{j} append];
362 | end;
363 | elseif length(ticky) == 0;
364 | ticky = get(h,'YTickLabel');
365 | if ischar(ticky);
366 | temp = ticky;
367 | ticky = cell(1,size(temp,1));
368 | for j=1:size(temp,1);
369 | ticky{j} = strtrim( temp(j,:) );
370 | end;
371 | end;
372 | append = '^{\circ}';
373 | for j=1:length(ticky);
374 | ticky{j} = [ticky{j} append];
375 | end;
376 | elseif isstr(ticky);
377 | append = ticky;
378 | ticky = get(h,'YTickLabel');
379 | if ischar(ticky);
380 | temp = ticky;
381 | ticky = cell(1,size(temp,1));
382 | for j=1:size(temp,1);
383 | ticky{j} = strtrim( temp(j,:) );
384 | end;
385 | end;
386 | if strcmp(append(1),'$');
387 | for j=1:length(ticky);
388 | ticky{j} = ['$' ticky{j} append(2:end)];
389 | end;
390 | else;
391 | for j=1:length(ticky);
392 | ticky{j} = [ticky{j} append];
393 | end;
394 | end;
395 | elseif ~iscell(ticky );
396 | warning(['Input TICKY variable is not a compatible string ' ...
397 | 'or cell array! Returning...']);
398 | return;
399 | end;
400 | %find out if we have to use the LaTex interpreter
401 | temp = ticky{1};
402 | if strcmp(temp(1),'$');
403 | latex_on = 1;
404 | else;
405 | latex_on = 0;
406 | end;
407 | %erase the current tick label
408 | set(h,'YTickLabel',{});
409 | %get the x tick positions if the user did not input them
410 | if ~exist('tickposy','var');
411 | tickposy = get(h,'YTick');
412 | elseif length(ticky) == 0;
413 | tickposy = get(h,'YTick');
414 | end;
415 | %get the x tick positions if the user did not input them
416 | if ~exist('tickposx','var');
417 | tickposx = get(h,'YTick');
418 | elseif length(tickposx) == 0;
419 | tickposx = get(h,'XTick');
420 | end;
421 | %set the new tick positions
422 | set(h,'YTick',tickposy);
423 | % set(h,'XTick',tickposx);
424 | %check the lengths of the xtick positions and xtick labels
425 | l1 = length(ticky);
426 | l2 = length(tickposy);
427 | if l1==0;
428 | set(h,'YTickLabel',ticky);
429 | end;
430 | if l1~=l2;
431 | disp(['Length of YTick = ' num2str(length(tickposy))]);
432 | disp(['Length of YTickLabel = ' num2str(length(ticky))]);
433 | if l2 < l1;
434 | warning(['Reducing Length of YTickLabel!']);
435 | else;
436 | warning(['Reducing Length of YTick!']);
437 | end;
438 | l3 = min([l1,l2]);
439 | ticky = ticky{1:l3};
440 | tickposy = tickposy(1:l3);
441 | end;
442 | %set rotation to 0 if not input
443 | if ~exist('roty','var');
444 | roty = 0;
445 | elseif length(roty) == 0;
446 | roty = 0;
447 | end;
448 | %Convert the cell labels to a character string
449 | %ticky = char(ticky);
450 | ticky = cellstr(ticky);
451 | %Make the YTICKS!
452 | lim = get(h,'XLim');
453 | if min(tickposx) < lim(1);
454 | lim(1) = min(tickposx);
455 | end;
456 | if max(tickposx) > lim(2);
457 | lim(2) = max(tickposx);
458 | end;
459 | if roty == 0;
460 | if latex_on;
461 | hy = text(...
462 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposy),1),...
463 | tickposy,...
464 | ticky,'VerticalAlignment','middle',...
465 | 'HorizontalAlignment','right','rotation',roty,'interpreter','LaTex');
466 | else;
467 | hy = text(...
468 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposy),1),...
469 | tickposy,...
470 | ticky,'VerticalAlignment','middle',...
471 | 'HorizontalAlignment','right','rotation',roty);
472 | end;
473 | elseif roty < 180;
474 | if latex_on;
475 | hy = text(...
476 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposy),1),...
477 | tickposy,...
478 | ticky,'VerticalAlignment','middle',...
479 | 'HorizontalAlignment','right','rotation',roty,'interpreter','LaTex');
480 | else;
481 | hy = text(...
482 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposy),1),...
483 | tickposy,...
484 | ticky,'VerticalAlignment','middle',...
485 | 'HorizontalAlignment','right','rotation',roty);
486 | end;
487 | else;
488 | if latex_on;
489 | hy = text(...
490 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposy),1),...
491 | tickposy,...
492 | ticky,'VerticalAlignment','middle',...
493 | 'HorizontalAlignment','right','rotation',roty,'interpreter','LaTex');
494 | else;
495 | hy = text(...
496 | repmat(lim(1)-offset*(lim(2)-lim(1)),length(tickposy),1),...
497 | tickposy,...
498 | ticky,'VerticalAlignment','middle',...
499 | 'HorizontalAlignment','right','rotation',roty);
500 | end;
501 | end;
502 | %Get and set the text size and weight
503 | set(hy,'FontSize',get(h,'FontSize'));
504 | set(hy,'FontWeight',get(h,'FontWeight'));
505 |
506 | %Set the additional parameters if they were input
507 | if length(varargin) > 2;
508 | command_string = ['set(hy'];
509 | for j=1:2:length(varargin);
510 | command_string = [command_string ',' ...
511 | '''' varargin{j} ''',varargin{' num2str(j+1) '}'];
512 | end;
513 | command_string = [command_string ');'];
514 | eval(command_string);
515 | end;
516 | end;
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
--------------------------------------------------------------------------------
/scripts/my_figure.m:
--------------------------------------------------------------------------------
1 | function f= my_figure(fsizex, fsizey)
2 | f= figure;
3 | set(f,'Units','centimeters');
4 | set(f,'Position',[0 0 fsizex fsizey]);
5 | set(f,'PaperUnits','centimeters');
6 | set(f,'PaperPosition',[0 0 fsizex fsizey]);
7 | set(f,'PaperSize',[fsizex fsizey])
--------------------------------------------------------------------------------
/scripts/my_fonts.m:
--------------------------------------------------------------------------------
1 | function my_fonts(h)
2 | set(h, 'fontunits', 'points');
3 | set(h, 'fontsize', 7);
4 | set(h, 'fontname', 'Times');
--------------------------------------------------------------------------------
/scripts/results.json:
--------------------------------------------------------------------------------
1 | { "axle": 9.115259e-02, "l_diam": 4.197573e-02, "r_diam": 4.223467e-02, "l_x": -3.693202e-03, "l_y": -3.782233e-03, "l_theta": -1.530913e+00, "E_d": 1.006169e+00, "E_b": 1.012807e+00 }
2 |
--------------------------------------------------------------------------------
/scripts/run_all.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -x # show commands
3 | set -e # exit on error
4 | set -o pipefail
5 | source script_variables.sh
6 |
7 | mkdir -p ${working_dir}
8 | echo ${version_string} > ${working_dir}/version_string
9 | mkdir -p ${tuple_dir}
10 | echo ${version_string} > ${tuple_dir}/version_string
11 |
12 | for set in ${sets}; do
13 |
14 | archive=${archive_dir}/${set}.tar.gz
15 | wd=${working_dir}/${set}
16 |
17 | check_existence ${archive}
18 |
19 | echo "Extracting contents of ${archive} to ${wd}."
20 | mkdir -p ${wd}
21 |
22 | tar xvzf ${archive} -C ${wd}
23 |
24 | done
25 |
26 | echo "$0: Done preparing."
27 |
28 | echo "$0: Now creating tuples."
29 |
30 | for set in ${sets}; do
31 |
32 | wd=${working_dir}/${set}
33 |
34 | for a in ${wd}/**/log.log.bz2; do
35 | ./create_tuples.sh $a $a
36 | echo
37 | done
38 | done
39 |
40 |
41 | echo "$0: Now collecting tuples in tuple directory."
42 |
43 | rm -rf ${tuple_dir}/*.tuple
44 | mkdir -p ${tuple_dir}/
45 |
46 | for set in ${sets}; do
47 |
48 | wd=${working_dir}/${set}
49 | cat ${wd}/exp*/*.log_tuple > ${tuple_dir}/${set}.tuple
50 | ${json_decimate} -period 3 -phase 0 -in ${tuple_dir}/${set}.tuple -out ${tuple_dir}/${set}_0.tuple
51 | ${json_decimate} -period 3 -phase 1 -in ${tuple_dir}/${set}.tuple -out ${tuple_dir}/${set}_1.tuple
52 | ${json_decimate} -period 3 -phase 2 -in ${tuple_dir}/${set}.tuple -out ${tuple_dir}/${set}_2.tuple
53 | done
54 |
55 | echo "$0: Now solving for all tuples"
56 |
57 | for file in ${tuple_dir}/*.tuple; do
58 | a=`basename ${file} .tuple`
59 | ${solver} -input_file ${tuple_dir}/${a}.tuple -output_file ${tuple_dir}/${a}_results.json ${solver_options}
60 | ${json2matlab} ${tuple_dir}/${a}_results.json
61 | done
62 |
63 |
64 | ln -f -s ${tuple_dir} 'last_tuples'
65 |
66 |
67 |
--------------------------------------------------------------------------------
/scripts/script_variables.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | archive_dir="../data/"
4 |
5 | json_decimate=json_decimate
6 | json2matlab=json2matlab
7 |
8 | #Executables
9 | sm2="sm2"
10 |
11 | calib_bin=../bin/
12 | synchronizer=${calib_bin}/synchronizer
13 | solver=${calib_bin}/solver2
14 |
15 |
16 | # parameters
17 | sets="l90 lmov lstraight"
18 | decimate_period=4
19 | sm_options="-restart 0 -recover_from_error 1 -max_iterations 1000 -min_reading 0.3 -max_angular_correction_deg 10 -max_linear_correction 0.05 -epsilon_xy 0.000001 -epsilon_theta 0.000001 "
20 | synchronizer_options="-tk_threshold 5 -perc_threshold 0.95 -time_tolerance 0.5"
21 | solver_options="-mode 0 -outliers_iterations 4"
22 |
23 |
24 | check_exec() {
25 | local path="$1"
26 | if ! type $path >/dev/null 2>&1; then
27 | echo "ERROR: \"$path\" not found."
28 | echo " This is needed to work. "
29 | exit 2
30 | fi
31 | }
32 |
33 | check_existence() {
34 | local type="$1"
35 | local path="$2"
36 | if [ ! -e $path ]; then
37 | echo "Missing $type: $path"
38 | exit 1
39 | fi
40 | }
41 |
42 |
43 | # Check we can find everything
44 | check_exec md5sum
45 | check_exec awk
46 | check_exec ${json_decimate}
47 | check_exec ${sm2}
48 | check_exec ${json2matlab}
49 | check_exec ${solver}
50 | check_exec ${synchronizer}
51 | check_existence ${archive_dir}
52 |
53 |
54 | version_string="sets=${sets}\ndecimate_period=${decimate_period}\nsm_options=${sm_options}\nsynchronizer_options=${synchronizer_options}\nsolver_options=${solver_options}"
55 | version_id=`echo ${version_string}|md5sum|awk '{print $1}'`
56 |
57 | working_dir="working_dir_${version_id}/"
58 | tuple_dir="tuples_${version_id}/"
59 |
60 | echo version_id: ${version_id}
61 | echo working_dir: ${working_dir}
62 | echo tuple_dir: ${tuple_dir}
63 |
64 |
65 |
--------------------------------------------------------------------------------
/scripts/table_test.tex:
--------------------------------------------------------------------------------
1 | \documentclass{book}
2 | \usepackage{fullpage}
3 | \begin{document}
4 | \footnotesize
5 | \input{last_tuples/bigtable1.tex}
6 |
7 | \input{last_tuples/bigtable2.tex}
8 |
9 | \input{last_tuples/bigtable3.tex}
10 | \end{document}
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.6)
2 |
3 | # Detection of CSM library using CMake routines
4 | find_package(PkgConfig REQUIRED)
5 | pkg_check_modules(GSL REQUIRED gsl)
6 | pkg_check_modules(CSM REQUIRED csm)
7 |
8 | IF(${CSM_FOUND})
9 | MESSAGE("CSM_LIBRARY_DIRS: ${CSM_LIBRARY_DIRS}")
10 | MESSAGE("CSM_LIBRARIES: ${CSM_LIBRARIES}")
11 | MESSAGE("CSM_INCLUDE_DIRS: ${CSM_INCLUDE_DIRS}")
12 |
13 | INCLUDE_DIRECTORIES(${CSM_INCLUDE_DIRS})
14 | LINK_DIRECTORIES(${CSM_LIBRARY_DIRS})
15 |
16 | ELSE(${CSM_FOUND})
17 | MESSAGE(SEND_ERROR "CSM not found. Make sure PKG_CONFIG_PATH contains the directory where the file 'csm.pc' can be found.")
18 | ENDIF(${CSM_FOUND})
19 |
20 |
21 | # Various flags
22 |
23 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
24 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb")
25 | # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 ")
26 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
27 | # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
28 |
29 | #build dirs
30 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../bin)
31 |
32 | # A test for JSON
33 | ADD_EXECUTABLE(test_json test_json.c)
34 | TARGET_LINK_LIBRARIES(test_json ${CSM_LIBRARIES})
35 |
36 |
37 | ADD_EXECUTABLE(synchronizer synchronizer.cpp synchronizer_options.cpp aux_functions.cpp)
38 | TARGET_LINK_LIBRARIES(synchronizer ${CSM_LIBRARIES})
39 |
40 | ADD_EXECUTABLE(solver solver.cpp solver_options.cpp solver_utils.cpp aux_functions.cpp)
41 | TARGET_LINK_LIBRARIES(solver ${CSM_LIBRARIES})
42 |
43 | ADD_EXECUTABLE(solver2 solver2.cpp solver2_meat.cpp solver_options.cpp solver_utils.cpp aux_functions.cpp calib_tuple.cpp gsl_jacobian.cpp)
44 | TARGET_LINK_LIBRARIES(solver2 ${CSM_LIBRARIES})
45 |
46 |
47 | ADD_EXECUTABLE(verifier verifier.cpp verifier_options.cpp verifier_utils.cpp aux_functions.cpp analyzer.cpp)
48 | TARGET_LINK_LIBRARIES(verifier ${CSM_LIBRARIES})
49 |
50 | ADD_EXECUTABLE(gsl_jacobian_test gsl_jacobian_test.cpp gsl_jacobian.cpp )
51 | TARGET_LINK_LIBRARIES(gsl_jacobian_test ${CSM_LIBRARIES})
52 |
--------------------------------------------------------------------------------
/src/analyzer.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file analyzer.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Implements methods of class Analyzer
5 | */
6 |
7 | #include "analyzer.h"
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | // #include
16 | // #include
17 | // #include
18 | using namespace std;
19 |
20 | void Analyzer::set_par(Graph * g, const char * name, const char * title,
21 | const char * x_axis, const char * y_axis, const char * type,
22 | const char * legend, double *mx, double *Mx, double *my, double *My) {
23 | g->name = name;
24 | g->title = title;
25 | g->x_axis = x_axis;
26 | g->y_axis = y_axis;
27 | g->type = type;
28 | g->legend = legend;
29 | g->mx = mx;
30 | g->Mx = Mx;
31 | g->my = my;
32 | g->My = My;
33 | }
34 |
35 |
36 | void Analyzer::add_data_graph(double * x, double * y, int N, Graph * g) {
37 |
38 | // scrive su un file nome_graph.gp i vettori x,y
39 | ofstream gr_os(g->name);
40 |
41 | for (int k = 0; k < N; k++) {
42 | gr_os << y[k];
43 | gr_os << "\t";
44 | gr_os << x[k];
45 | gr_os << "\n";
46 | }
47 | gr_os.close();
48 | }
49 |
50 | void Analyzer::create_plot(Graph * plots, int num_g, const char * file_plot, bool grid, bool legend,
51 | double *mx, double *Mx, double *my, double *My) {
52 |
53 | // creazione del file
54 | ofstream pl_os(file_plot);
55 | int num_row, num_col;
56 | double x_delay, y_delay, x_size, y_size;
57 | // impostaione multiplot
58 | bool multi = (num_g > 1);
59 | if (multi) {
60 | pl_os << "set multiplot\n";
61 |
62 | num_row = (int) floor((double)num_g / 3.0) + 1;
63 | num_col = (int) ceil((double)num_g / (double)num_row);
64 |
65 | x_delay = 1.0 / num_col;
66 | y_delay = 1.0 / num_row;
67 | x_size = x_delay - x_delay * 0.1;
68 | y_size = y_delay - y_delay * 0.1;
69 | }
70 |
71 | if (grid) pl_os << "set grid\n";
72 | if (legend) pl_os << "set key outside\n\n";
73 |
74 | int i = 0;
75 |
76 | double x_origin, y_origin;
77 | for (int r = 0; r < num_row; r++) {
78 | for (int c = 0; c < num_col; c++) {
79 |
80 | i = r * num_col + c;
81 | if ( i < num_g ) {
82 | // setting title for graph[i]
83 | pl_os << "set title \""; pl_os << plots[i].title; pl_os << "\" \n";
84 | // setting origin of graph[i]
85 | x_origin = x_delay * c;
86 | y_origin = y_delay * (num_row - r - 1);
87 | if (multi) {
88 | pl_os << "set origin "; pl_os << x_origin; pl_os << ","; pl_os << y_origin; pl_os << "\n";
89 | // setting size of graph[i]
90 | pl_os << "set size "; pl_os << x_size; pl_os << ","; pl_os << y_size; pl_os << "\n";
91 | }
92 | // setting labels
93 | pl_os << "set xlabel \""; pl_os << plots[i].x_axis; pl_os << "\" 0,0\n";
94 | pl_os << "set ylabel \""; pl_os << plots[i].y_axis; pl_os << "\" 0,0\n";
95 | // plotting graph[i]
96 | if (plots[i].mx != NULL) {
97 | pl_os << "plot [" << mx[0] << " to " << Mx[0] << "] [" << my[0] << " to " << My[0] << "] '";
98 | }
99 | else pl_os << "plot '";
100 | pl_os << plots[i].name;
101 | pl_os << "' using \"%lf%lf\" ";
102 | if (plots[i].type != NULL) {pl_os << "w "; pl_os << plots[i].type; pl_os << " ";}
103 | if (legend) pl_os << "title '" << plots[i].legend << "'\n\n";
104 | else pl_os << "notitle \n\n";
105 | if(!multi) {
106 | pl_os.close();
107 | return;
108 | }
109 | }
110 | }
111 | }
112 |
113 | pl_os.close();
114 | }
115 |
116 | void Analyzer::create_same_plot(const char * title, const char * x_axis, const char * y_axis, Graph * plots, int num_g, const char * file_plot, bool grid, bool legend, double *mx, double *Mx, double *my, double *My) {
117 |
118 | // creazione del file
119 | ofstream pl_os(file_plot);
120 |
121 | // impostaione multiplot
122 | if (grid) pl_os << "set grid\n";
123 | if (legend) pl_os << "set key outside right top nobox\n\n";
124 |
125 | int i = 0;
126 |
127 | // setting title for graph[i]
128 | pl_os << "set title \""; pl_os << title; pl_os << "\" \n";
129 | // setting labels
130 | pl_os << "set xlabel \""; pl_os << x_axis; pl_os << "\" 0,0\n";
131 | pl_os << "set ylabel \""; pl_os << y_axis; pl_os << "\" 0,0\n";
132 | // plotting graph[i]
133 | pl_os << "plot ";
134 | if (mx != NULL) {
135 | pl_os << "[" << mx[0] << " to " << Mx[0] << "] [" << my[0] << " to " << My[0] << "] ";
136 | }
137 | for (int i = 0; i < num_g; i++ ) {
138 | pl_os << "'" << plots[i].name << "'"
139 | << " using \"%lf%lf\" ";
140 | if (plots[i].type != NULL) {pl_os << "w "; pl_os << plots[i].type; pl_os << " ";}
141 | if (legend) pl_os << "title '" << plots[i].legend << "'";
142 | else pl_os << "notitle \n\n";
143 | if (i != num_g-1) pl_os << ", \\\n";
144 | }
145 | pl_os << "\n" << endl;
146 |
147 | pl_os.close();
148 | }
149 |
150 | // execute Gnuplot with file "file_plot"
151 | void Analyzer::plot(const char * file_plot) {
152 | // usato nella chiamta a popen
153 | stringstream cmd;
154 | cmd << "gnuplot -persist " << file_plot << "\0";
155 | system(cmd.str().c_str());
156 | }
157 |
158 |
--------------------------------------------------------------------------------
/src/analyzer.h:
--------------------------------------------------------------------------------
1 | /*!
2 | \file analyzer.h
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Header of class Analyzer
5 | */
6 |
7 |
8 | #ifndef __ANALYZER_H__
9 | #define __ANALYZER_H__
10 |
11 | #include
12 | #include
13 | //#include
14 | //#include
15 |
16 | /*!
17 | used to handle information about plot (not data)
18 | @param name name of data file for graph
19 | @param title title of graph
20 | @param x_axis x-axis label
21 | @param y_axis y-axis label
22 | @param type "impulses" "points" "lines"
23 | @param legend string for legend
24 | @param mx,Mx,my,My pointers to values for bounds
25 | */
26 | typedef struct{
27 | const char * name;
28 | const char * title;
29 | const char * x_axis;
30 | const char * y_axis;
31 | const char * type;
32 | const char * legend;
33 | double *mx, *Mx, *my, *My;
34 | } Graph;
35 |
36 |
37 | /*!
38 | \class Analyzer
39 | \brief class for printing graphs, using Gnuplot
40 |
41 | Create Gnuplot data-file from vectors,
42 | create Gnuplot script to plot data.
43 | Possibility of multiplot.
44 | */
45 | class Analyzer {
46 |
47 | public:
48 | /*!
49 | Assign parameters to Graph object
50 | @param g Graph object
51 | @note For bounds (mx,Mx,my,My) default value is null. You can call this function omitting these parameters.
52 | */
53 | void set_par(Graph * g, const char * name, const char * title,
54 | const char * x_axis, const char * y_axis,
55 | const char * type, const char * legend,
56 | double *mx=NULL, double *Mx=NULL, double *my=NULL, double *My=NULL);
57 |
58 | /*!
59 | Create Gnuplot data-file from vectors x[] and y[]
60 | @param x pointer to a vector of double (x data)
61 | @param y pointer to a vector of double (y data)
62 | @param N number of elements in x[] and y[] (plot y to x)
63 | @param g pointer to Graph object
64 | */
65 | void add_data_graph(double * x, double * y, int N, Graph * g);
66 |
67 |
68 | /*!
69 | Create Gnuplot script to plot (multiplot) data from files
70 | @param file_plot name of Gnuplot script
71 | @param plots vector of Graph objects
72 | @param num_g number of subplots
73 | @param grid grid on/off
74 | @param legend legend on/off
75 | @param mx,Mx,my,My pointers to values for bounds (default is null)
76 | */
77 | void create_plot(Graph * plots, int num_g, const char * file_plot, bool grid, bool legend,
78 | double *mx=NULL, double *Mx=NULL, double *my=NULL, double *My=NULL);
79 |
80 | /*!
81 | Create Gnuplot script to plot multiple data on the same plot
82 | @param file_plot name of Gnuplot script
83 | @param plots vector of Graph objects
84 | @param num_g number of subplots
85 | @param grid grid on/off
86 | @param legend legend on/off
87 | @param mx,Mx,my,My pointers to values for bounds (default is null)
88 | */
89 | void create_same_plot(const char * title, const char * x_axis, const char * y_axis,
90 | Graph * plots, int num_g, const char * file_plot, bool grid, bool legend,
91 | double *mx=NULL, double *Mx=NULL, double *my=NULL, double *My=NULL);
92 |
93 | /*!
94 | Execute Gnuplot with file "file_plot"
95 | @param file_plot name of Gnuplot script
96 | */
97 | void plot(const char * file_plot);
98 |
99 | };
100 |
101 | #endif
102 |
--------------------------------------------------------------------------------
/src/aux_functions.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file aux_functions.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Collection of auxiliary functions (implementation file)
5 | */
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include "aux_functions.h"
16 |
17 | using namespace std;
18 | using namespace CSM;
19 |
20 | int read_jsonlist(const char * filename, vector *list) {
21 | FILE * input = open_file_for_reading(filename);
22 | if(!input) return 0;
23 |
24 | JO tmp;
25 | while (tmp = json_read_stream(input))
26 | list->push_back(tmp);
27 |
28 | if(!feof(input)) {
29 | sm_error("Error reading JSON file, after %d objects.\n", list->size());
30 | return 0;
31 | }
32 |
33 | fclose(input);
34 | return (1);
35 | }
36 |
37 | int write_jsonlist(const char * filename, vector *list) {
38 | FILE * output = open_file_for_writing(filename);
39 | if(!output) return 0;
40 |
41 | for (int i = 0; i < (int)list->size(); i++ ) {
42 | if (i > 0) fprintf(output,"\n");
43 |
44 | fprintf(output, "%s", json_object_to_json_string(list[0][i]) );
45 | }
46 |
47 | fclose(output);
48 | return (1);
49 | }
50 |
51 | int find_closest(double ts, vector odo, int start_at) {
52 | for ( int i = start_at; i < (int)odo.size() - 1; i++ ) {
53 | double ts_i = gettime(odo[i], "timestamp");
54 | double ts_ip = gettime(odo[i+1], "timestamp");
55 | if ( (ts_i < ts) && ( ts_ip > ts) ) {
56 | return(i);
57 | }
58 | if (ts_i > ts) {
59 | sm_error("find_closest: Sorry, could not find match for ts = %f\n", ts);
60 | return(-1);
61 | }
62 | }
63 | return(-1);
64 | }
65 | int find_closest_ref(double ts, vector odo, int bound) {
66 | double ts_i, ts_ip;
67 | if (bound==0) bound = -1;
68 | for ( int i = bound + 1; i < (int)odo.size() - 1; i++ ) {
69 | ts_i = gettime(odo[i], "timestamp");
70 | ts_ip = gettime(odo[i+1], "timestamp");
71 | if ( (ts_i <= ts) && ( ts_ip >= ts) ) return (i);
72 | }
73 | sm_error("find_closest_ref: Sorry, could not find match for ts = %f\n", ts);
74 | return(-1);
75 | }
76 | int find_closest_sens(double ts, vector odo, int bound) {
77 | double ts_i, ts_ip;
78 | for ( int i = bound+1; i < (int)odo.size(); i++ ) {
79 | ts_i = gettime(odo[i], "timestamp");
80 | ts_ip = gettime(odo[i-1], "timestamp");
81 | if ( (ts_i >= ts) && ( ts_ip <= ts) ) return (i);
82 | }
83 | sm_error("find_closest_sens: Sorry, could not find match for ts = %f\n", ts);
84 | return(-1);
85 | }
86 |
87 | void mysort(double *sort, int length) {
88 | int i, j;
89 | double tmp;
90 |
91 | for( i = 0; i < length - 1; i++) {
92 | for(j = i; j < length; j++) {
93 | if(sort[i] > sort[j]) {
94 | tmp = sort[i];
95 | sort[i] = sort[j];
96 | sort[j] = tmp;
97 | }
98 | }
99 | }
100 | }
101 |
102 | void mysort(int *sort, int length) {
103 | int i, j;
104 | int tmp;
105 |
106 | for( i = 0; i < length - 1; i++) {
107 | for(j = i; j < length; j++) {
108 | if(sort[i] > sort[j]) {
109 | tmp = sort[i];
110 | sort[i] = sort[j];
111 | sort[j] = tmp;
112 | }
113 | }
114 | }
115 | }
116 |
117 | int getticks(JO obj, const char* name) {
118 | int tick;
119 | jo_read_int(obj, name, &tick);
120 | return tick;
121 | }
122 |
123 | double getticksD(JO obj, const char* name) {
124 | double tick;
125 | jo_read_double(obj, name, &tick);
126 | return tick;
127 | }
128 |
129 | double gettime(JO obj, const char* name) {
130 | double read_time[2];
131 | jo_read_double_array (obj, name, read_time, 2, 0.0);
132 | return read_time[0] + 0.000001 * read_time[1];
133 | }
134 |
135 | int logSync(vector odo, vector las_stats, int* linit, int* lend, int* oinit, int* oend) {
136 | int nLas = (int)las_stats.size();
137 |
138 | bool found = false;
139 | int ref;
140 | for(int l = 0; (l < nLas) && !found; l++ ) {
141 | double lT = gettime(las_stats[l], "laser_ref_timestamp");
142 | ref = find_closest_ref(lT, odo, 0);
143 | if (ref != -1) {
144 | found = true;
145 | linit[0] = l;
146 | oinit[0] = ref;
147 | }
148 | }
149 | if (!found) {
150 | sm_error("Could not find intersection of logs.\n");
151 | return 0;
152 | }
153 |
154 | found = false;
155 | int sens;
156 | for(int l = (nLas - 1); (l >= 0) && !found; l-- ) {
157 | double lT = gettime(las_stats[l], "laser_sens_timestamp");
158 | sens = find_closest_sens(lT, odo, 0);
159 | if (sens != -1) {
160 | found = true;
161 | lend[0] = l;
162 | oend[0] = sens;
163 | }
164 | }
165 | if (!found) {
166 | sm_error("Could not find intersection of logs.\n");
167 | return 0;
168 | }
169 | return 1;
170 | }
171 |
172 | int matchOdoLas(vector odo, vector smStats, vector * matchedOdo, vector * matchedLas){
173 | cout << "Checking correspondances between laser and odometry files..."<push_back(new_obj);
206 |
207 | for( int i = oinit + 1; i < oend; i++ ) {
208 | new_obj = json_object_new_object();
209 | ts = gettime(odo[i], "timestamp");
210 | timestamp[0] = int(ts);
211 | timestamp[1] = int(ts*1000000 - floor(ts)*1000000);
212 | jo_add_int_array (new_obj, "timestamp", timestamp, 2);
213 | lticks = getticks(odo[i],"left");
214 | rticks = getticks(odo[i],"right");
215 | json_object_object_add(new_obj, "left", json_object_new_double(lticks) );
216 | json_object_object_add(new_obj, "right", json_object_new_double(rticks) );
217 | jo_read_double_array (odo[i], "odometry", os, 3, 0.0);
218 | jo_add_double_array (new_obj, "odometry", os, 3);
219 | matchedOdo->push_back(new_obj);
220 | }
221 |
222 | ts = gettime(smStats[lend],"laser_sens_timestamp");
223 | t1 = gettime(odo[oend-1], "timestamp");
224 | t2 = gettime(odo[oend], "timestamp");
225 | double sens_alpha = (t2-ts)/(t2-t1);
226 | lticks = (1-sens_alpha)*getticks(odo[oend-1],"left") + sens_alpha*getticks(odo[oend], "left");
227 | rticks = (1-sens_alpha)*getticks(odo[oend-1],"right") + sens_alpha*getticks(odo[oend], "right");
228 | jo_read_double_array (odo[oend-1], "odometry", o1, 3, 0.0);
229 | jo_read_double_array (odo[oend], "odometry", o2, 3, 0.0);
230 | os[0] = (1-sens_alpha)*o1[0] + sens_alpha*o2[0];
231 | os[1] = (1-sens_alpha)*o1[1] + sens_alpha*o2[1];
232 | os[2] = (1-sens_alpha)*o1[2] + sens_alpha*o2[2];
233 |
234 | new_obj = json_object_new_object();
235 | timestamp[0] = int(ts);
236 | timestamp[1] = int(ts*1000000 - floor(ts)*1000000);
237 | jo_add_int_array (new_obj, "timestamp", timestamp, 2);
238 | json_object_object_add(new_obj, "left", json_object_new_double(lticks) );
239 | json_object_object_add(new_obj, "right", json_object_new_double(rticks) );
240 | jo_add_double_array (new_obj, "odometry", os, 3);
241 | matchedOdo->push_back(new_obj);
242 |
243 | double error;
244 | int valid;
245 | int nvalid;
246 | int nLas = lend - linit;
247 | double mean_error[nLas];
248 | double mean_error_sorted[nLas];
249 | int nvalid_sorted[nLas];
250 | double perc = 0.99;
251 | for(int i = linit; i <= lend; i++) {
252 | int nvalid;
253 |
254 | jo_read_double(smStats[i], "error", &error);
255 | jo_read_int(smStats[i], "nvalid", &nvalid);
256 | mean_error[i] = error/nvalid;
257 | mean_error_sorted[i] = mean_error[i];
258 | nvalid_sorted[i] = nvalid;
259 | }
260 | mysort(mean_error_sorted, nLas);
261 | mysort(nvalid_sorted, nLas);
262 | double mean_error_threshold = mean_error_sorted[ (int)round(perc*nLas)];
263 | cout << "mean_error_threshold " << mean_error_threshold << endl;
264 | int nvalid_threshold = nvalid_sorted[ (int)round((1 - perc)*nLas)];
265 | cout << "nvalid_threshold " << nvalid_threshold << endl;
266 |
267 | for (int i = linit; i <= lend; i++) {
268 | jo_read_int (smStats[i], "valid", &valid);
269 | if (valid == 0) {
270 | cout << "VALID N" << i << endl;
271 | continue;
272 | }
273 | // if (mean_error[i] > mean_error_threshold) {
274 | // cout << "MEAN ERROR N" << i << "\t" << mean_error[i] << endl;
275 | // continue;
276 | // }
277 | // jo_read_int (smStats[i], "nvalid", &nvalid);
278 | // if (nvalid < nvalid_threshold) {
279 | // cout << "NVALID N" << i << endl;
280 | // continue;
281 | // }
282 | jo_read_double (smStats[i], "error", &error);
283 | if (error > 5.0) {
284 | cout << "ERROR N" << i << "\t" << error << endl;
285 | continue;
286 | }
287 | matchedLas->push_back(smStats[i]);
288 | }
289 | return 0;
290 | }
291 |
292 |
--------------------------------------------------------------------------------
/src/aux_functions.h:
--------------------------------------------------------------------------------
1 | /*!
2 | \file aux_functions.h
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Collection of auxiliary functions (header file)
5 | */
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #ifndef M_PI
13 | #define M_PI 3.14159265
14 | #endif
15 |
16 | using namespace std;
17 | using namespace CSM;
18 |
19 | /*!
20 | \brief Reads a list of JSON objects from filename
21 | @param filename name of the file to be read
22 | @param list pointer to a vector of JsonObject (JO) used to store data
23 | @return 1 if successfull, 0 otherwhise
24 | */
25 | int read_jsonlist(const char * filename, vector *list);
26 |
27 | /*!
28 | \brief Writes a list of JSON objects to filename
29 | @param filename name of the file to be written
30 | @param list pointer to a vector of JsonObject (JO)
31 | @returns 1 if successfull, 0 otherwhise
32 | */
33 | int write_jsonlist(const char * filename, vector *list);
34 |
35 | /*!
36 | \brief Searches the object (odometry object) closest to a given timestamp
37 | @param ts timestamp to be matched
38 | @param odo vector of odometry objects (JO)
39 | @param start_at starting index for search
40 | @return 0 if no interval matching has been found, otherwhise the index of the closest before
41 | */
42 | int find_closest(double ts, vector odo, int start_at);
43 |
44 | /*!
45 | \brief Searches the object closest (before) to a given timestamp
46 | @param ts timestamp to be matched
47 | @param odo vector of odometry objects (JO)
48 | @param bound starting index for search
49 | @return 0 if no interval matching has been found, otherwhise the index of the closest before
50 | */
51 | int find_closest_ref(double ts, vector odo, int bound);
52 |
53 | /*!
54 | \brief Searches the object closest (after) to a given timestamp
55 | @param ts timestamp to be matched
56 | @param odo vector of odometry objects (JO)
57 | @param bound starting index (from the end of the list) for search
58 | @return 0 if no interval matching has been found, otherwhise the index of the closest before
59 | */
60 | int find_closest_sens(double ts, vector odo, int bound);
61 |
62 | /*!
63 | \brief Sorts in ascending order the elements of an array of doubles
64 | @param sort array to be sorted
65 | @param length length of array
66 | */
67 | void mysort(double *sort, int length);
68 |
69 | /*!
70 | \brief Sorts in ascending order the elements of an array of ints
71 | @param sort array to be sorted
72 | @param length length of array
73 | */
74 | void mysort(int *sort, int length);
75 |
76 | /*!
77 | \brief Gets the ticks from an odometry object (JO)
78 | @param obj odometry object
79 | @param name left/right, selects left or right ticks
80 | @return number of ticks (int)
81 | */
82 | int getticks(JO obj, const char* name);
83 |
84 | /*!
85 | \brief Gets the ticks from an odometry object (JO)
86 | @param obj odometry object
87 | @param name left/right, selects left or right ticks
88 | @return number of ticks (double)
89 | */
90 | double getticksD(JO obj, const char* name);
91 |
92 | /*!
93 | \brief Gets the timestamp from an odometry/laser object (JO).
94 | Time is supposed to be represented by a two values array, an int for seconds and another for microseconds
95 | @param obj odometry object
96 | @param name field name (es: "Timestamp")
97 | @return timestamp
98 | */
99 | double gettime(JO obj, const char* name);
100 |
101 | /*!
102 | \brief Given two vectors (laser and odometry) computates two subvectors with matching timestamps
103 | @param odo vector of JO for odometry
104 | @param las_stats vector of JO for laser (laser statistics)
105 | @param linit starting index of laser subvector
106 | @param lend ending index of laser subvector
107 | @param oinit starting index of odometry subvector
108 | @param oend ending index of odometry subvector
109 | @return 1 if successfull, 0 otherwhise
110 |
111 | */
112 | int logSync(vector odo, vector las_stats, int* linit, int* lend, int* oinit, int* oend);
113 |
114 | /*!
115 | \brief Calculates matching between laser_stats and odometry objects
116 | @param odo vector of JO for odometry
117 | @param smStats vector of JO for laser (laser statistics)
118 | @param matchedOdo vector of JO to store matched odometry
119 | @param matchedLas vector of JO to store matched laser (statistics)
120 | @return 1 if successfull, 0 otherwhise
121 | */
122 | int matchOdoLas(vector odo, vector smStats, vector * matchedOdo, vector * matchedLas);
123 |
--------------------------------------------------------------------------------
/src/calib_tuple.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "calib_tuple.h"
4 | #include "gsl_jacobian.h"
5 |
6 | calib_tuple::calib_tuple() {
7 |
8 | }
9 | /*calib_tuple::calib_tuple(const calib_tuple& x) {
10 | // fim = gsl_matrix_alloc (6,6);
11 | // gsl_matrix_memcpy(fim, x.fim);
12 | }*/
13 | calib_tuple::~calib_tuple() {
14 | // gsl_matrix_free(fim);
15 | }
16 |
17 | gsl_vector * jacobian_helper(const gsl_vector* calib, void*params) {
18 | calib_tuple * t = (calib_tuple*) params;
19 | calib_result r;
20 | r.radius_l = gsl_vector_get(calib, 0);
21 | r.radius_r = gsl_vector_get(calib, 1);
22 | r.axle = gsl_vector_get(calib, 2);
23 | r.l[0] = gsl_vector_get(calib, 3);
24 | r.l[1] = gsl_vector_get(calib, 4);
25 | r.l[2] = gsl_vector_get(calib, 5);
26 | t->compute_disagreement(r);
27 |
28 | gsl_vector*res = gsl_vector_alloc(3);
29 | gsl_vector_set(res, 0, t->est_sm[0]);
30 | gsl_vector_set(res, 1, t->est_sm[1]);
31 | gsl_vector_set(res, 2, t->est_sm[2]);
32 | return res;
33 | }
34 |
35 |
36 | gsl_matrix* calib_tuple::compute_fim(struct calib_result&r, gsl_matrix * inf_sm) {
37 | double state[6] = { r.radius_l, r.radius_r, r.axle, r.l[0], r.l[1], r.l[2]};
38 | gsl_vector_view v = gsl_vector_view_array(state, 6);
39 | gsl_matrix * J = gsl_jacobian(jacobian_helper, &(v.vector), this);
40 |
41 | // XXXXXXXXXX
42 | // FIM = J' * inf_sm * J
43 | // A = J' * inf_sm
44 | gsl_matrix * A = gsl_matrix_alloc(6,3);
45 | gsl_blas_dgemm (CblasTrans, CblasNoTrans, 1, J, inf_sm, 0, A);
46 | // FIM = A * J
47 | gsl_matrix * fim = gsl_matrix_alloc(6,6);
48 | gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1, A, J, 0, fim);
49 |
50 | gsl_matrix_free(J);
51 | gsl_matrix_free(A);
52 | return fim;
53 | }
54 |
55 | void calib_tuple::write_as_long_line(std::ostream&os) {
56 | os
57 | << T << " "
58 | << phi_l << " "
59 | << phi_r << " "
60 | << sm[0] << " "
61 | << sm[1] << " "
62 | << sm[2] << " "
63 | << o[0] << " "
64 | << o[1] << " "
65 | << o[2] << " "
66 | << err[0] << " "
67 | << err[1] << " "
68 | << err[2] << " "
69 | << est_sm[0] << " "
70 | << est_sm[1] << " "
71 | << est_sm[2] << " "
72 | << err_sm[0] << " "
73 | << err_sm[1] << " "
74 | << err_sm[2] << " "
75 | << mark_as_outlier <<
76 | std::endl;
77 | }
78 |
79 | void calib_tuple::compute_disagreement(const struct calib_result&res) {
80 | double J11 = +res.radius_l/2;
81 | double J12 = +res.radius_r/2;
82 | double J21 = -res.radius_l/res.axle;
83 | double J22 = +res.radius_r/res.axle;
84 |
85 | static int once = 1;
86 | // if(once)
87 | // cout << "My J21,J22 "<< J21 << ", " << J22 << endl;
88 | once = 0;
89 |
90 | double speed = J11 * this->phi_l + J12 * this->phi_r;
91 | double omega = J21 * this->phi_l + J22 * this->phi_r;
92 |
93 | double o_theta = T * omega;
94 |
95 | double t1,t2;
96 | if ( fabs(o_theta) > 1e-12 ) {
97 | t1 = ( sin(o_theta) / (o_theta) );
98 | t2 = ( (1-cos(o_theta)) / (o_theta) );
99 | } else {
100 | t1 = 1;
101 | t2 = 0;
102 | }
103 |
104 | this->o[0] = t1 * (speed*T);
105 | this->o[1] = t2 * (speed*T);
106 | this->o[2] = o_theta;
107 |
108 | double l_plus_s[3];
109 | double o_plus_l[3];
110 | oplus_d(res.l, this->sm, l_plus_s);
111 | oplus_d(o, res.l, o_plus_l);
112 |
113 | for(int i=0;i<3;i++)
114 | this->err[i] = l_plus_s[i] - o_plus_l[i];
115 |
116 | pose_diff_d(o_plus_l, res.l, this->est_sm);
117 |
118 | for(int i=0;i<3;i++)
119 | this->err_sm[i] = this->est_sm[i] - this->sm[i];
120 |
121 | }
122 |
123 | bool json2tuple(const JO jo, calib_tuple&tuple) {
124 | int res =
125 | jo_read_double(jo, "T", &tuple.T) &&
126 | jo_read_double(jo, "phi_l", &tuple.phi_l) &&
127 | jo_read_double(jo, "phi_r", &tuple.phi_r) &&
128 | jo_read_double_array (jo, "sm", tuple.sm, 3, GSL_NAN);
129 |
130 | if(!res)
131 | sm_error("Cannot read tuple form JSON.\n");
132 | return res;
133 | }
134 |
135 | JO calib_result2json(const calib_result&res) {
136 | // Build json object
137 | struct json_object *new_obj;
138 | new_obj = json_object_new_object();
139 |
140 | double est_E_d = res.radius_r / res.radius_l;
141 | /** XXX ??? */
142 | double est_E_b = res.axle / 0.09;
143 | json_object_object_add(new_obj, "axle", json_object_new_double(res.axle) );
144 | json_object_object_add(new_obj, "l_diam", json_object_new_double(res.radius_l*2) );
145 | json_object_object_add(new_obj, "r_diam", json_object_new_double(res.radius_r*2) );
146 | json_object_object_add(new_obj, "l_x", json_object_new_double(res.l[0]) );
147 | json_object_object_add(new_obj, "l_y", json_object_new_double(res.l[1]) );
148 | json_object_object_add(new_obj, "l_theta", json_object_new_double(res.l[2]) );
149 | json_object_object_add(new_obj, "E_d", json_object_new_double(est_E_d) );
150 | json_object_object_add(new_obj, "E_b", json_object_new_double(est_E_b) );
151 |
152 | return new_obj;
153 | }
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/src/calib_tuple.h:
--------------------------------------------------------------------------------
1 | #ifndef H_CALIB_TUPLE
2 | #define H_CALIB_TUPLE
3 |
4 | #include
5 | #include "calib_tuple.h"
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 |
14 | struct calib_result {
15 | double radius_l, radius_r;
16 | double axle;
17 |
18 | /** Laser pose */
19 | double l[3];
20 | };
21 |
22 | struct calib_tuple {
23 |
24 | /** Input data */
25 |
26 | /** Period */
27 | double T;
28 | /** Left and right wheel velocities */
29 | double phi_l;
30 | double phi_r;
31 | /** Scan matching estimate */
32 | double sm[3];
33 |
34 | /** Temp data, used for outliers computations */
35 |
36 | /** Estimated rototranslation based on odometry params. */
37 | double o[3];
38 |
39 | /** Estimated disagreement sm - est_sm */
40 | // double e_sm[3];
41 |
42 | double est_sm[3];
43 | double err_sm[3];
44 |
45 | /** Other way to estimate disagreement: l (+) s - o (+) l */
46 | double err[3];
47 |
48 | int mark_as_outlier;
49 |
50 |
51 | /** Computes plenty of statistics, including estimated sm. */
52 | void compute_disagreement(const calib_result&);
53 |
54 | /** Computes fisher information matrix. inf_sm is the inverse of the covariance of sm */
55 | gsl_matrix* compute_fim(struct calib_result&, gsl_matrix * inf_sm);
56 |
57 | void write_as_long_line(std::ostream&os);
58 |
59 | calib_tuple();
60 | ~calib_tuple();
61 |
62 | };
63 |
64 |
65 | bool json2tuple(const JO jo, calib_tuple&tuple);
66 | JO tuple2json(const calib_tuple&tuple);
67 |
68 | JO calib_result2json(const calib_result&res) ;
69 |
70 | #endif
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/gsl_jacobian.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "gsl_jacobian.h"
3 |
4 | struct my_params_struct {
5 | int i, j;
6 | gsl_vector * (*function)(const gsl_vector* x, void*params);
7 | const gsl_vector * x0;
8 | void * params;
9 | };
10 |
11 | double my_gsl_function(double xj, void * my_params) {
12 | struct my_params_struct * s = (struct my_params_struct*) my_params;
13 |
14 | // create x by copying x0 and setting xj
15 | gsl_vector * x = gsl_vector_alloc(s->x0->size);
16 | gsl_vector_memcpy(x, s->x0);
17 | gsl_vector_set(x, s->j, xj);
18 |
19 | gsl_vector * fx = s->function(x, s->params);
20 |
21 | double fi = gsl_vector_get(fx, s->i);
22 |
23 | gsl_vector_free(fx);
24 | gsl_vector_free(x);
25 |
26 | return fi;
27 | }
28 |
29 |
30 | gsl_matrix * gsl_jacobian( gsl_vector * (*function)(const gsl_vector* x, void*params), const gsl_vector *x, void*params) {
31 |
32 | gsl_vector * fx = function(x,params);
33 |
34 | int rows = fx->size;
35 | int columns = x->size;
36 |
37 | gsl_matrix * m = gsl_matrix_alloc(rows,columns);
38 |
39 |
40 | for(int i=0;i
4 | #include
5 |
6 | gsl_matrix * gsl_jacobian( gsl_vector * (*function)(const gsl_vector* x, void*params), const gsl_vector *x, void*params);
7 |
--------------------------------------------------------------------------------
/src/gsl_jacobian_test.cpp:
--------------------------------------------------------------------------------
1 | #include "gsl_jacobian.h"
2 |
3 | gsl_vector* test1(const gsl_vector*x, void*dummy) {
4 | gsl_vector*res = gsl_vector_alloc(x->size);
5 | for(int i=0;isize;i++) {
6 | gsl_vector_set(res, i, gsl_vector_get(x, i) * gsl_vector_get(x, i));
7 | }
8 |
9 | return res;
10 | }
11 |
12 | int main() {
13 |
14 | gsl_vector * v = gsl_vector_alloc(4);
15 | gsl_vector_set(v,0,1);
16 | gsl_vector_set(v,1,2);
17 | gsl_vector_set(v,2,3);
18 | gsl_vector_set(v,3,4);
19 |
20 | gsl_matrix * J = gsl_jacobian(test1, v, 0);
21 |
22 | gsl_matrix_fprintf(stderr, J, "%g");
23 |
24 | fprintf(stderr, "\n");
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/solver.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file solver.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Estimates odometry and sensor parameters
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "aux_functions.h"
24 | #include "solver_options.h"
25 | #include "solver_utils.h"
26 |
27 | #define vg(X,Y) ( gsl_vector_get(X,Y) )
28 | #define vs(X,Y,Z) ( gsl_vector_set(X,Y,Z) )
29 | #define mg(X,Y,Z) ( gsl_matrix_get(X,Y,Z) )
30 | #define ms(X,Y,Z,Q) ( gsl_matrix_set(X,Y,Z,Q) )
31 |
32 | using namespace std;
33 |
34 | extern void solver_options(solver_params*p, struct option*ops);
35 | double f (const gsl_vector *z, void *params);
36 |
37 | /*!
38 | Solver routine
39 | \brief This program has been developed to estimate parameters (odometry and sensor) given a list of tuples generated by synchronizer.
40 |
41 | It uses gsl libraries to handle matrix and vectors, as well as minimization and eigenvalues solution.
42 |
43 | */
44 | int main(int argc, const char * argv[]) {
45 | /*!*/
46 | solver_params params;
47 | struct option* ops = options_allocate(100);
48 | solver_options(¶ms, ops);
49 | if(!options_parse_args(ops, argc, argv)) {
50 | options_print_help(ops, stderr);
51 | return 1;
52 | }
53 |
54 | /*!*/
55 | vector tuple;
56 | if (!read_jsonlist(params.input_file, &tuple) ) {
57 | sm_error("Error opening input files.\n");
58 | return 2;
59 | }
60 |
61 | /*!*/
62 | double J21, J22;
63 | gsl_matrix * A = gsl_matrix_calloc(2,2);
64 | gsl_vector * g = gsl_vector_calloc(2);
65 | gsl_vector * L_i = gsl_vector_alloc(2);
66 | double th_i;
67 | int n = (int) tuple.size();
68 |
69 | for (int i = 0; i < n; i++) {
70 | double T, phi_l, phi_r;
71 | double sm[3];
72 | jo_read_double(tuple[i], "T", &T);
73 | jo_read_double(tuple[i], "phi_l", &phi_l);
74 | jo_read_double(tuple[i], "phi_r", &phi_r);
75 | jo_read_double_array (tuple[i], "sm", sm, 3, 0.0);
76 | vs( L_i, 0, T*phi_l);
77 | vs( L_i, 1, T*phi_r);
78 | gsl_blas_dger (1, L_i, L_i, A); // A = A + L_i'*L_i; A symmetric
79 | gsl_blas_daxpy (sm[2], L_i, g); // g = g + L_i'*y_i; sm :{x , y, theta}
80 | }
81 | gsl_vector_free(L_i);
82 |
83 | // Verify that A isn't singular
84 | double cond = cond_number(A);
85 | if ( cond > 50 ) {
86 | sm_error("Matrix A is almost singular. Not very exciting data!\n");
87 | return 3;
88 | }
89 |
90 | // Ay = g --> y = inv(A)g; A square matrix;
91 | gsl_vector * y = gsl_vector_calloc(2);
92 | if (!solve_square_linear(A, g, y)) {
93 | sm_error("Cannot solve Ay=g. Invalid arguments\n");
94 | return 4;
95 | }
96 | J21 = vg(y, 0); J22 = vg(y, 1);
97 | if ( gsl_isnan(J21) || gsl_isnan(J22) ) {
98 | sm_error("Could not find first two parameters J21, J22");
99 | return 5;
100 | }
101 | //cout << "J21,J22: " << J21 << ", " << J22 << endl;
102 | gsl_vector_free(y);
103 |
104 | /*!*/
105 | // Build M, M2
106 | gsl_matrix * M = gsl_matrix_calloc(5,5);
107 | gsl_matrix * M2 = gsl_matrix_calloc(6,6);
108 | gsl_matrix * L_k = gsl_matrix_calloc(2,5);
109 | gsl_matrix * L_2k = gsl_matrix_calloc(2,6);
110 | double c, cx, cy, cx1, cx2, cy1, cy2, t1, t2;
111 | double o_theta, T, phi_l, phi_r, w0;
112 | double sm[3];
113 |
114 | for (int k = 0; k < n; k++) {
115 | jo_read_double(tuple[k], "T", &T);
116 | jo_read_double(tuple[k], "phi_l", &phi_l);
117 | jo_read_double(tuple[k], "phi_r", &phi_r);
118 | jo_read_double_array (tuple[k], "sm", sm, 3, 0.0);
119 |
120 | o_theta = T * (J21*phi_l + J22*phi_r);
121 | w0 = o_theta / T;
122 |
123 | if ( fabs(o_theta) > 1e-12 ) {
124 | t1 = ( sin(o_theta) / (o_theta) );
125 | t2 = ( (1-cos(o_theta)) / (o_theta) );
126 | }
127 | else {
128 | t1 = 1;
129 | t2 = 0;
130 | }
131 | cx1 = 0.5 * T * (-J21 * phi_l) * t1;
132 | cx2 = 0.5 * T * (+J22 * phi_r) * t1;
133 | cy1 = 0.5 * T * (-J21 * phi_l) * t2;
134 | cy2 = 0.5 * T * (+J22 * phi_r) * t2;
135 | if ( (params.mode == 0)||(params.mode == 1) ) {
136 | cx = cx1 + cx2;
137 | cy = cy1 + cy2;
138 | double array[] = {
139 | -cx, 1-cos(o_theta), sin(o_theta), sm[0], -sm[1],
140 | -cy, -sin(o_theta), 1-cos(o_theta), sm[1], sm[0]
141 | };
142 | gsl_matrix_view tmp = gsl_matrix_view_array(array, 2, 5);
143 | L_k = &tmp.matrix;
144 | // M = M + L_k' * L_k; M is symmetric
145 | gsl_blas_dgemm (CblasTrans,CblasNoTrans, 1, L_k, L_k, 1, M);
146 | }
147 | else {
148 | double array2[] = {
149 | -cx1, -cx2, 1-cos(o_theta), sin(o_theta), sm[0], -sm[1],
150 | -cy1, -cy2, -sin(o_theta), 1-cos(o_theta), sm[1], sm[0]
151 | };
152 | gsl_matrix_view tmp = gsl_matrix_view_array(array2, 2, 6);
153 | L_2k = &tmp.matrix;
154 | // M2 = M2 + L_2k' * L_2k; M2 is symmetric
155 | gsl_blas_dgemm (CblasTrans,CblasNoTrans, 1, L_2k, L_2k, 1, M2);
156 | }
157 | }
158 |
159 | double est_b, est_d_l, est_d_r, laser_x, laser_y, laser_th;
160 | gsl_vector * x;
161 | switch (params.mode)
162 | {
163 | case 0: /*!*/
164 | {
165 | x = full_calibration_min(M);
166 |
167 | est_b = vg(x, 0);
168 | est_d_l = 2*(-est_b * J21);
169 | est_d_r = 2*(est_b * J22);
170 | laser_x = vg(x, 1);
171 | laser_y = vg(x, 2);
172 | laser_th = atan2(vg(x, 4), vg(x, 3));
173 | break;
174 | }
175 | case 1: /*!*/
176 | {
177 | x = numeric_calibration(M);
178 |
179 | est_b = vg(x, 0);
180 | est_d_l = 2*(-est_b * J21);
181 | est_d_r = 2*(est_b * J22);
182 | laser_x = vg(x, 1);
183 | laser_y = vg(x, 2);
184 | laser_th = atan2(vg(x, 4), vg(x, 3));
185 | break;
186 | }
187 | case 2: /*!*/
188 | {
189 | x = numeric_calibration(M2);
190 |
191 | est_b = (vg(x, 0) + vg(x, 1))/2;
192 | est_d_l = 2*(-est_b * J21);
193 | est_d_r = 2*(est_b * J22);
194 | laser_x = vg(x, 2);
195 | laser_y = vg(x, 3);
196 | laser_th = atan2(vg(x, 5), vg(x, 4));
197 | break;
198 | }
199 | default:
200 | break;
201 | }
202 |
203 | /*!*/
204 | // gsl_matrix * M3 = gsl_matrix_calloc(6,6);
205 | // gsl_matrix * L_3k = gsl_matrix_calloc(2,6);
206 | // double dx1, dx2, dy1, dy2;
207 | // double J11, J12;
208 | //
209 | // for (int k = 0; k < n; k++) {
210 | // jo_read_double(tuple[k], "T", &T);
211 | // jo_read_double(tuple[k], "phi_l", &phi_l);
212 | // jo_read_double(tuple[k], "phi_r", &phi_r);
213 | // jo_read_double_array (tuple[k], "sm", sm, 3, 0.0);
214 | //
215 | // o_theta = sm[2];
216 | // w0 = o_theta / T;
217 | //
218 | // if ( fabs(o_theta) > 1e-12 ) {
219 | // t1 = ( sin(o_theta) / (o_theta) );
220 | // t2 = ( (1-cos(o_theta)) / (o_theta) );
221 | // }
222 | // else {
223 | // t1 = 1;
224 | // t2 = 0;
225 | // }
226 | // dx1 = T * ( phi_l) * t1;
227 | // dx2 = T * ( phi_r) * t1;
228 | // dy1 = T * ( phi_l) * t2;
229 | // dy2 = T * ( phi_r) * t2;
230 | // double array3[] = {
231 | // -dx1, -dx2, 1-cos(o_theta), sin(o_theta), sm[0], -sm[1],
232 | // -dy1, -dy2, -sin(o_theta), 1-cos(o_theta), sm[1], sm[0]
233 | // };
234 | // gsl_matrix_view tmp = gsl_matrix_view_array(array3, 2, 6);
235 | // L_3k = &tmp.matrix;
236 | // gsl_blas_dgemm (CblasTrans,CblasNoTrans, 1, L_3k, L_3k, 1, M3);
237 | //
238 | // }
239 | // gsl_vector * x3;
240 | // x3 = numeric_calibration(M3);
241 | // J11 = vg(x3,0);
242 | // J12 = vg(x3,1);
243 | // cout << "J11,J12: " << J11 << ", " << J12 << endl;
244 | // double axle2 = 2*((J11+J12)/(J22-J21));
245 | // cout << " new d_l = " << J11*4 << endl;
246 | // cout << " new d_r = " << J12*4 << endl;
247 | // cout << "TEST\n";
248 | // cout << " axle " << axle2 << endl;
249 | // cout << " l_diam " << 2*J11 - J21*axle2 << endl;
250 | // cout << " r_diam " << 2*J12 + J22*axle2 << endl;
251 | // cout << " l_x " << vg(x3,2) << endl;
252 | // cout << " l_y " << vg(x3,3) << endl;
253 | // cout << " l_th " << atan2(vg(x3, 5), vg(x3, 4)) << endl;
254 |
255 | /*!*/
256 | // Build json object
257 | struct json_object *new_obj;
258 | new_obj = json_object_new_object();
259 |
260 | double est_E_d = est_d_r / est_d_l;
261 | double est_E_b = est_b / 0.09;
262 | json_object_object_add(new_obj, "axle", json_object_new_double(est_b) );
263 | json_object_object_add(new_obj, "l_diam", json_object_new_double(est_d_l) );
264 | json_object_object_add(new_obj, "r_diam", json_object_new_double(est_d_r) );
265 | json_object_object_add(new_obj, "l_x", json_object_new_double(laser_x) );
266 | json_object_object_add(new_obj, "l_y", json_object_new_double(laser_y) );
267 | json_object_object_add(new_obj, "l_theta", json_object_new_double(laser_th) );
268 | json_object_object_add(new_obj, "E_d", json_object_new_double(est_E_d) );
269 | json_object_object_add(new_obj, "E_b", json_object_new_double(est_E_b) );
270 |
271 | // Write json object to file
272 | FILE * output;
273 | if(!strcmp(params.output_file, "stdout")) { output = stdout;}
274 | else {output = fopen(params.output_file, "w");}
275 | fprintf(output, "%s\n", json_object_to_json_string(new_obj) );
276 | fclose(output);
277 | return 0;
278 | }
279 |
280 |
281 |
--------------------------------------------------------------------------------
/src/solver2.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file solver.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Estimates odometry and sensor parameters
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 |
19 | #include "aux_functions.h"
20 | #include "solver_options.h"
21 | #include "solver_utils.h"
22 |
23 | #include
24 | #include
25 |
26 |
27 | #include "calib_tuple.h"
28 |
29 |
30 |
31 | extern void solver_options(solver_params*p, struct option*ops);
32 | int solve_jackknife(const std::vector & tuples, int mode, double max_cond_number, struct calib_result& res);
33 | int solve(const std::vector & tuple, int mode, double max_cond_number, struct calib_result& res);
34 | void estimate_noise(std::vector&tuples, const calib_result&res, double&std_x,double&std_y,double&std_th);
35 |
36 |
37 | const char* banner =
38 | "This program estimates parameters (odometry and sensor) given a list of tuples generated by synchronizer.\n";
39 |
40 | /*!
41 | Solver routine
42 | \brief This program has been developed to estimate parameters (odometry and sensor) given a list of tuples generated by synchronizer.
43 |
44 | It uses gsl libraries to handle matrix and vectors, as well as minimization and eigenvalues solution.
45 |
46 | */
47 | int main(int argc, const char * argv[]) {
48 | sm_set_program_name(argv[0]);
49 |
50 | /*!*/
51 | solver_params params;
52 | struct option* ops = options_allocate(100);
53 | solver_options(¶ms, ops);
54 | options_banner(banner);
55 | if(!options_parse_args(ops, argc, argv)) {
56 | options_print_help(ops, stderr);
57 | return 1;
58 | }
59 |
60 | if(strlen(params.output_file)==0) {
61 | char base[PATH_MAX];
62 | my_no_suffix(params.input_file, base);
63 | char buf[PATH_MAX];
64 | sprintf(buf, "%s_results.json", base);
65 | params.output_file = my_strdup(buf);
66 | sm_info("No output filename given; writing on file '%s'.\n", params.output_file);
67 | }
68 |
69 | if(params.outliers_percentage <= 0 || params.outliers_percentage > 0.5) {
70 | sm_error("Outlier percentage %f does not seem a sane value.\n", params.outliers_percentage);
71 | return 2;
72 | }
73 |
74 | sm_debug_write(params.debug);
75 |
76 |
77 | /*!*/
78 | vector jos;
79 | if (!read_jsonlist(params.input_file, &jos) ) {
80 | sm_error("Error opening input files.\n");
81 | return 2;
82 | }
83 |
84 | vector tuples;
85 | for(int i=0;i original_tuples = tuples;
95 |
96 | vector tuple_history[params.outliers_iterations+1];
97 |
98 | calib_result res;
99 |
100 | for(int iteration=0;iteration<=params.outliers_iterations;iteration++) {
101 | tuple_history[iteration] = tuples;
102 |
103 | // Calibration
104 | if(!solve(tuples, params.mode, params.max_cond_number, res)) {
105 | sm_error("Failed calibration.\n");
106 | return 3;
107 | }
108 |
109 | // Compute residuals
110 | for(int i=0;i err_theta;
115 | for(int i=0;i err_xy;
119 | for(int i=0;i err_theta_sorted(err_theta);
126 | sort( err_theta_sorted.begin(), err_theta_sorted.end() );
127 |
128 | vector err_xy_sorted(err_xy);
129 | sort( err_xy_sorted.begin(), err_xy_sorted.end() );
130 |
131 | int threshold_index = (int) round ( (1-params.outliers_percentage) * tuples.size() );
132 | if(threshold_index<0) threshold_index = 0;
133 | if(threshold_index>=tuples.size()) threshold_index = tuples.size()-1;
134 |
135 | double threshold_theta = err_theta_sorted[threshold_index];
136 | double threshold_xy = err_xy_sorted[threshold_index];
137 |
138 | int noutliers = 0;
139 | int noutliers_theta = 0;
140 | int noutliers_xy = 0;
141 | int noutliers_both = 0;
142 |
143 | for(int i=0;i threshold_xy;
145 | int theta = err_theta[i] > threshold_theta;
146 |
147 | tuples[i].mark_as_outlier = xy | theta;
148 |
149 | if(xy) noutliers_xy ++;
150 | if(theta) noutliers_theta ++;
151 | if(xy&&theta) noutliers_both ++;
152 | if(xy||theta) noutliers ++;
153 | }
154 |
155 | // Output statistics
156 | sm_info("Outlier detection: #tuples = %d, removing percentage = %.0f%% (index=%d)\n", tuples.size(),
157 | 100*params.outliers_percentage, threshold_index);
158 | sm_info(" err_theta min = %f max = %f threshold = %f \n",
159 | err_theta[0], err_theta[tuples.size()-1], threshold_theta);
160 | sm_info(" err_xy min = %f max = %f threshold = %f \n",
161 | err_xy[0], err_xy[tuples.size()-1], threshold_xy);
162 |
163 | sm_info(" num_outliers = %d; for theta = %d; for xy = %d; for both = %d\n", noutliers, noutliers_theta, noutliers_xy, noutliers_both);
164 |
165 |
166 | // Write debug info
167 | char filename[256];
168 | char base[255];
169 | my_no_suffix(params.output_file, base);
170 |
171 | sprintf(filename, "%s_iter%d.asc", base, iteration);
172 | ofstream ofs(filename);
173 | sm_info("%s\n",filename);
174 | if(!ofs) sm_error("could not open '%s'\n",filename);
175 | for(int i=0;i n;
181 | for(int i=0;i
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include "aux_functions.h"
14 | #include "solver_options.h"
15 | #include "solver_utils.h"
16 |
17 | #include
18 | #include
19 |
20 |
21 | #include "calib_tuple.h"
22 |
23 | #define vg(X,Y) ( gsl_vector_get(X,Y) )
24 | #define vs(X,Y,Z) ( gsl_vector_set(X,Y,Z) )
25 | #define mg(X,Y,Z) ( gsl_matrix_get(X,Y,Z) )
26 | #define ms(X,Y,Z,Q) ( gsl_matrix_set(X,Y,Z,Q) )
27 |
28 | using namespace std;
29 |
30 |
31 |
32 | double f (const gsl_vector *z, void *params);
33 |
34 |
35 | int solve(const vector & tuple, int mode, double max_cond_number, struct calib_result& res) {
36 |
37 | /*!*/
38 | double J21, J22;
39 | gsl_matrix * A = gsl_matrix_calloc(2,2);
40 | gsl_vector * g = gsl_vector_calloc(2);
41 | gsl_vector * L_i = gsl_vector_alloc(2);
42 | double th_i;
43 | int n = (int) tuple.size();
44 |
45 | for (int i = 0; i < n; i++) {
46 | const calib_tuple &t = tuple[i];
47 | vs( L_i, 0, t.T*t.phi_l);
48 | vs( L_i, 1, t.T*t.phi_r);
49 | gsl_blas_dger (1, L_i, L_i, A); // A = A + L_i'*L_i; A symmetric
50 | gsl_blas_daxpy (t.sm[2], L_i, g); // g = g + L_i'*y_i; sm :{x , y, theta}
51 | }
52 | gsl_vector_free(L_i);
53 |
54 | // Verify that A isn't singular
55 | double cond = cond_number(A);
56 | if ( cond > max_cond_number ) {
57 | sm_error("Matrix A is almost singular (condition number: %f). Not very exciting data!\n", cond);
58 | return 0;
59 | }
60 |
61 | // Ay = g --> y = inv(A)g; A square matrix;
62 | gsl_vector * y = gsl_vector_calloc(2);
63 | if (!solve_square_linear(A, g, y)) {
64 | sm_error("Cannot solve Ay=g. Invalid arguments\n");
65 | return 0;
66 | }
67 | J21 = vg(y, 0); J22 = vg(y, 1);
68 | if ( gsl_isnan(J21) || gsl_isnan(J22) ) {
69 | sm_error("Could not find first two parameters J21, J22 by solving linear equation.\n");
70 | sm_error("This is A: \n\n"); gsl_matrix_fwrite(stderr, A); fprintf(stderr, "\n");
71 | sm_error("This is g: \n\t"); gsl_vector_fwrite(stderr, g); fprintf(stderr, "\n");
72 | sm_error("This is y: \n\t"); gsl_vector_fwrite(stderr, y); fprintf(stderr, "\n");
73 | return 0;
74 | }
75 | // cerr << "J21,J22: " << J21 << ", " << J22 << endl;
76 | gsl_vector_free(y);
77 |
78 | /*!*/
79 | // Build M, M2
80 | gsl_matrix * M = gsl_matrix_calloc(5,5);
81 | gsl_matrix * M2 = gsl_matrix_calloc(6,6);
82 | gsl_matrix * L_k = gsl_matrix_calloc(2,5);
83 | gsl_matrix * L_2k = gsl_matrix_calloc(2,6);
84 | double c, cx, cy, cx1, cx2, cy1, cy2, t1, t2;
85 | double o_theta, T, phi_l, phi_r, w0;
86 | double sm[3];
87 |
88 | int nused = 0;
89 | for (int k = 0; k < n; k++) {
90 | const calib_tuple &t = tuple[k];
91 |
92 | o_theta = t.T * (J21*t.phi_l + J22*t.phi_r);
93 | w0 = o_theta / t.T;
94 |
95 | /*if( fabs(o_theta) > deg2rad(1) ) {
96 | continue;
97 | } else {
98 | nused ++;
99 | }*/
100 |
101 | if ( fabs(o_theta) > 1e-12 ) {
102 | t1 = ( sin(o_theta) / (o_theta) );
103 | t2 = ( (1-cos(o_theta)) / (o_theta) );
104 | }
105 | else {
106 | t1 = 1;
107 | t2 = 0;
108 | }
109 | cx1 = 0.5 * t.T * (-J21 * t.phi_l) * t1;
110 | cx2 = 0.5 * t.T * (+J22 * t.phi_r) * t1;
111 | cy1 = 0.5 * t.T * (-J21 * t.phi_l) * t2;
112 | cy2 = 0.5 * t.T * (+J22 * t.phi_r) * t2;
113 | if ( (mode == 0)||(mode == 1) ) {
114 | cx = cx1 + cx2;
115 | cy = cy1 + cy2;
116 | double array[] = {
117 | -cx, 1-cos(o_theta), sin(o_theta), t.sm[0], -t.sm[1],
118 | -cy, -sin(o_theta), 1-cos(o_theta), t.sm[1], t.sm[0]
119 | };
120 | gsl_matrix_view tmp = gsl_matrix_view_array(array, 2, 5);
121 | L_k = &tmp.matrix;
122 | // M = M + L_k' * L_k; M is symmetric
123 | gsl_blas_dgemm (CblasTrans,CblasNoTrans, 1, L_k, L_k, 1, M);
124 | }
125 | else {
126 | double array2[] = {
127 | -cx1, -cx2, 1-cos(o_theta), sin(o_theta), t.sm[0], -t.sm[1],
128 | -cy1, -cy2, -sin(o_theta), 1-cos(o_theta), t.sm[1], t.sm[0]
129 | };
130 | gsl_matrix_view tmp = gsl_matrix_view_array(array2, 2, 6);
131 | L_2k = &tmp.matrix;
132 | // M2 = M2 + L_2k' * L_2k; M2 is symmetric
133 | gsl_blas_dgemm (CblasTrans,CblasNoTrans, 1, L_2k, L_2k, 1, M2);
134 | }
135 | }
136 |
137 | // sm_info("Andrea's hack: using %d / %d\n", nused, n);
138 |
139 | double est_b, est_d_l, est_d_r, laser_x, laser_y, laser_th;
140 | gsl_vector * x;
141 | switch (mode)
142 | {
143 | case 0: /*!*/
144 | {
145 | x = full_calibration_min(M);
146 |
147 | est_b = vg(x, 0);
148 | est_d_l = 2*(-est_b * J21);
149 | est_d_r = 2*(est_b * J22);
150 | laser_x = vg(x, 1);
151 | laser_y = vg(x, 2);
152 | laser_th = atan2(vg(x, 4), vg(x, 3));
153 | break;
154 | }
155 | case 1: /*!*/
156 | {
157 | x = numeric_calibration(M);
158 |
159 | est_b = vg(x, 0);
160 | est_d_l = 2*(-est_b * J21);
161 | est_d_r = 2*(est_b * J22);
162 | laser_x = vg(x, 1);
163 | laser_y = vg(x, 2);
164 | laser_th = atan2(vg(x, 4), vg(x, 3));
165 | break;
166 | }
167 | case 2: /*!*/
168 | {
169 | x = numeric_calibration(M2);
170 |
171 | est_b = (vg(x, 0) + vg(x, 1))/2;
172 | est_d_l = 2*(-est_b * J21);
173 | est_d_r = 2*(est_b * J22);
174 | laser_x = vg(x, 2);
175 | laser_y = vg(x, 3);
176 | laser_th = atan2(vg(x, 5), vg(x, 4));
177 | break;
178 | }
179 | default:
180 | break;
181 | }
182 |
183 | /*!*/
184 | // gsl_matrix * M3 = gsl_matrix_calloc(6,6);
185 | // gsl_matrix * L_3k = gsl_matrix_calloc(2,6);
186 | // double dx1, dx2, dy1, dy2;
187 | // double J11, J12;
188 | //
189 | // for (int k = 0; k < n; k++) {
190 | // jo_read_double(tuple[k], "T", &T);
191 | // jo_read_double(tuple[k], "phi_l", &phi_l);
192 | // jo_read_double(tuple[k], "phi_r", &phi_r);
193 | // jo_read_double_array (tuple[k], "sm", sm, 3, 0.0);
194 | //
195 | // o_theta = sm[2];
196 | // w0 = o_theta / T;
197 | //
198 | // if ( fabs(o_theta) > 1e-12 ) {
199 | // t1 = ( sin(o_theta) / (o_theta) );
200 | // t2 = ( (1-cos(o_theta)) / (o_theta) );
201 | // }
202 | // else {
203 | // t1 = 1;
204 | // t2 = 0;
205 | // }
206 | // dx1 = T * ( phi_l) * t1;
207 | // dx2 = T * ( phi_r) * t1;
208 | // dy1 = T * ( phi_l) * t2;
209 | // dy2 = T * ( phi_r) * t2;
210 | // double array3[] = {
211 | // -dx1, -dx2, 1-cos(o_theta), sin(o_theta), sm[0], -sm[1],
212 | // -dy1, -dy2, -sin(o_theta), 1-cos(o_theta), sm[1], sm[0]
213 | // };
214 | // gsl_matrix_view tmp = gsl_matrix_view_array(array3, 2, 6);
215 | // L_3k = &tmp.matrix;
216 | // gsl_blas_dgemm (CblasTrans,CblasNoTrans, 1, L_3k, L_3k, 1, M3);
217 | //
218 | // }
219 | // gsl_vector * x3;
220 | // x3 = numeric_calibration(M3);
221 | // J11 = vg(x3,0);
222 | // J12 = vg(x3,1);
223 | // cout << "J11,J12: " << J11 << ", " << J12 << endl;
224 | // double axle2 = 2*((J11+J12)/(J22-J21));
225 | // cout << " new d_l = " << J11*4 << endl;
226 | // cout << " new d_r = " << J12*4 << endl;
227 | // cout << "TEST\n";
228 | // cout << " axle " << axle2 << endl;
229 | // cout << " l_diam " << 2*J11 - J21*axle2 << endl;
230 | // cout << " r_diam " << 2*J12 + J22*axle2 << endl;
231 | // cout << " l_x " << vg(x3,2) << endl;
232 | // cout << " l_y " << vg(x3,3) << endl;
233 | // cout << " l_th " << atan2(vg(x3, 5), vg(x3, 4)) << endl;
234 |
235 | /*!*/
236 |
237 | res.axle = est_b;
238 | res.radius_l = est_d_l/2;
239 | res.radius_r = est_d_r/2;
240 | res.l[0] = laser_x;
241 | res.l[1] = laser_y;
242 | res.l[2] = laser_th;
243 |
244 | return 1;
245 |
246 | }
247 |
248 |
249 | int solve_jackknife(const vector & tuples, int mode, double max_cond_number, struct calib_result& res) {
250 |
251 | union {
252 | double tmp_params[6];
253 | struct calib_result tmp_res;
254 | };
255 |
256 | // check that the union trick is working
257 | tmp_res.radius_l = 0;
258 | tmp_res.radius_r = 1;
259 | tmp_res.axle = 2;
260 | tmp_res.l[0] = 3;
261 | tmp_res.l[1] = 4;
262 | tmp_res.l[2] = 5;
263 |
264 | for(int i=0;i<6;i++)
265 | if(tmp_params[i] != i) {
266 | sm_error("Ooops! the union trick is not working");
267 | exit(-1);
268 | }
269 |
270 | int n = tuples.size();
271 | vector minusone;
272 | for(int i=1;i&tuples, const calib_result&res, double&std_x,double&std_y,double&std_th) {
322 | int n = tuples.size();
323 | double err_sm[3][n];
324 | for(int i=0;i
9 | #include "solver_options.h"
10 |
11 | void solver_options(solver_params *p, struct option*ops) {
12 |
13 | options_string(ops, "input_file",
14 | &(p->input_file), "",
15 | "Input file containing a list of tuples");
16 |
17 | options_string(ops, "output_file",
18 | (&p->output_file), "",
19 | "Output file ");
20 |
21 | options_int(ops, "mode",
22 | (&p->mode), 0,
23 | "Minimization method ");
24 |
25 | options_int(ops, "outliers_iterations", (&p->outliers_iterations), 4,
26 | "Number of outliers removal iterations.");
27 | options_double(ops, "outliers_percentage", &(p->outliers_percentage), 0.01,
28 | "Percentage of outliers to reject at each iteration. Double value: 0.01 == 1%%" );
29 |
30 | options_int(ops, "debug", &(p->debug), 0, "Shows debug information");
31 |
32 | options_double(ops, "max_cond_number", &(p->max_cond_number), 75,
33 | "Max condition number allowed for the first linear estimation step." );
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/solver_options.h:
--------------------------------------------------------------------------------
1 | /*!
2 | \file solver_options.h
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief options for the solver executable
5 | */
6 |
7 | #ifndef _SOLVER_OPTIONS_H
8 | #define _SOLVER_OPTIONS_H
9 |
10 | /*!
11 | \struct solver_params
12 | \brief Solver parameter instance structure
13 | @param input_file filename containing a list of tuples obtained from synchronizer
14 | @param output_file filename for output
15 | @param mode computation mode
16 | */
17 | typedef struct {
18 | const char * input_file;
19 | const char * output_file;
20 | int mode;
21 |
22 | double max_cond_number;
23 |
24 | int outliers_iterations;
25 | double outliers_percentage;
26 |
27 | int debug;
28 | } solver_params;
29 |
30 | /*!
31 | Initializes parameters for solver procedure
32 | \param p pointer to parameters' structure
33 | \param ops options' structure
34 | */
35 | void solver_options(solver_params*p, struct option*ops);
36 |
37 | #endif
38 |
39 |
--------------------------------------------------------------------------------
/src/solver_utils.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file solver_utils.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Implements methods for Solver_utils
5 | */
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #include
24 | #include
25 | #include
26 | #include "aux_functions.h"
27 | #include "solver_utils.h"
28 |
29 | #define sp(X) ( pow(X,2) )
30 | #define cp(X) ( pow(X,3) )
31 | #define fp(X) ( pow(X,4) )
32 | #define vg(X,Y) ( gsl_vector_get(X,Y) )
33 | #define vs(X,Y,Z) ( gsl_vector_set(X,Y,Z) )
34 | #define mg(X,Y,Z) ( gsl_matrix_get(X,Y,Z) )
35 | #define ms(X,Y,Z,Q) ( gsl_matrix_set(X,Y,Z,Q) )
36 |
37 | using namespace std;
38 |
39 | double cond_number(gsl_matrix * M)
40 | {
41 | size_t row = M->size1;
42 | size_t col = M->size2;
43 | gsl_matrix * V = gsl_matrix_alloc(col,col);
44 | gsl_matrix * U = gsl_matrix_alloc(row,col);
45 | gsl_matrix_memcpy(U, M);
46 |
47 | //vettore per i valori singolari di A
48 | gsl_vector * S = gsl_vector_alloc( min(row,col) );
49 | gsl_vector * work = gsl_vector_alloc( min(row,col) );
50 | gsl_linalg_SV_decomp(U, V, S, work );
51 |
52 | double cond = gsl_vector_max(S) / gsl_vector_min(S);
53 |
54 | gsl_matrix_free(U);
55 | gsl_matrix_free(V);
56 | gsl_vector_free(work);
57 | gsl_vector_free(S);
58 | return cond;
59 | }
60 |
61 | int solve_square_linear(gsl_matrix * A, gsl_vector * g, gsl_vector * x)
62 | {
63 | size_t sz = A->size1;
64 | if (A->size2 != sz) return 0;
65 | if (x->size != sz) return 0;
66 | if (g->size != sz) return 0;
67 | gsl_matrix * LU = gsl_matrix_alloc(sz,sz);
68 | gsl_permutation * p = gsl_permutation_alloc(sz);
69 | gsl_matrix_memcpy(LU, A);
70 | int signum;
71 | gsl_linalg_LU_decomp (LU, p, &signum );
72 | gsl_linalg_LU_solve (LU, p, g, x );
73 | gsl_matrix_free(LU);
74 | gsl_permutation_free(p);
75 |
76 | return 1;
77 | }
78 |
79 | int eigenv(gsl_matrix * M, gsl_vector * eigenvalues, gsl_matrix * eigenvectors)
80 | {
81 | size_t sz2 = M->size2;
82 | size_t sz = M->size1;
83 | if (sz != sz2) return 0;
84 | gsl_eigen_symmv_workspace * wk = gsl_eigen_symmv_alloc(sz);
85 | gsl_matrix *M_tmp = gsl_matrix_alloc(sz, sz);
86 |
87 | gsl_matrix_memcpy(M_tmp, M);
88 | gsl_eigen_symmv(M_tmp, eigenvalues, eigenvectors, wk);
89 | gsl_eigen_gensymmv_sort (eigenvalues, eigenvectors, GSL_EIGEN_SORT_ABS_ASC);
90 |
91 | gsl_matrix_free(M_tmp);
92 | gsl_eigen_symmv_free(wk);
93 | return 1;
94 | }
95 |
96 | double calculate_error(gsl_vector * x, gsl_matrix * M)
97 | {
98 | double error;
99 | gsl_vector * tmp = gsl_vector_calloc( x->size );
100 |
101 | gsl_blas_dgemv(CblasNoTrans, 1, M, x, 0, tmp);
102 | gsl_blas_ddot(x ,tmp, &error);
103 |
104 | gsl_vector_free(tmp);
105 | return error;
106 | }
107 |
108 | gsl_vector * full_calibration_min(gsl_matrix * M)
109 | {
110 | double m11 = mg(M,0,0);
111 | double m13 = mg(M,0,2);
112 | double m14 = mg(M,0,3);
113 | double m15 = mg(M,0,4);
114 | double m22 = mg(M,1,1);
115 | double m25 = mg(M,1,4);
116 | double m34 = mg(M,2,3);
117 | double m35 = mg(M,2,4);
118 | double m44 = mg(M,3,3);
119 | double m55 = mg(M,4,4);
120 | double a,b,c;
121 |
122 | /* Coefficienti del determinante M + lambda*W */
123 | a = m11 * sp(m22) - m22 * sp(m13);
124 |
125 | b = 2 * m11 * sp(m22) * m44 - sp(m22) * sp(m14)
126 | - 2 * m22 * sp(m13) * m44 - 2 * m11 * m22 * sp(m34)
127 | - 2 * m11 * m22 * sp(m35) - sp(m22) * sp(m15)
128 | + 2 * m13 * m22 * m34 * m14 + sp(m13) * sp(m34)
129 | + 2 * m13 * m22 * m35 * m15 + sp(m13) * sp(m35);
130 |
131 | c = - 2 * m13 * cp(m35) * m15 - m22 * sp(m13) * sp(m44) + m11 * sp(m22) * sp(m44)
132 | + sp(m13) * sp(m35) * m44 + 2 * m13 * m22 * m34 * m14 * m44 + sp(m13) * sp(m34) * m44
133 | - 2 * m11 * m22 * sp(m34) * m44 - 2 * m13 * cp(m34) * m14 - 2 * m11 * m22 * sp(m35) * m44
134 | + 2 * m11 * sp(m35) * sp(m34) + m22 * sp(m14) * sp(m35) - 2 * m13 * sp(m35) * m34 * m14
135 | - 2 * m13 * sp(m34) * m35 * m15 + m11 * fp(m34) + m22 * sp(m15) * sp(m34)
136 | + m22 * sp(m35) * sp(m15) + m11 * fp(m35) - sp(m22) * sp(m14) * m44
137 | + 2 * m13 * m22 * m35 * m15 * m44 + m22 * sp(m34) * sp(m14) - sp(m22) * sp(m15) * m44;
138 |
139 | /* Calcolo radice del polinomio */
140 | gsl_complex * r0 = new gsl_complex;
141 | gsl_complex * r1 = new gsl_complex;
142 |
143 | gsl_poly_complex_solve_quadratic(a, b, c, r0, r1);
144 |
145 | if ( (r0->dat[1] == 0) ) { //|| (GSL_IMAG(r1) == 0)) {
146 | /* Costruzione matrice W */
147 | gsl_matrix * W = gsl_matrix_calloc(5,5);
148 | gsl_matrix_set(W,3,3,1);
149 | gsl_matrix_set(W,4,4,1);
150 | gsl_vector * x0 = x_given_lambda(M, r0->dat[0], W);
151 | gsl_vector * x1 = x_given_lambda(M, r1->dat[0], W);
152 | gsl_matrix_free(W);
153 |
154 | double e0 = calculate_error(x0, M);
155 | double e1 = calculate_error(x1, M);
156 |
157 | return e0 < e1 ? x0 : x1;
158 | }
159 | else {
160 | sm_error("bad thing: imaginary solution\n");
161 | return NULL;
162 | }
163 | }
164 |
165 | gsl_vector * x_given_lambda(gsl_matrix * M, double lambda, gsl_matrix * W)
166 | {
167 | gsl_matrix * Z = gsl_matrix_calloc(5,5);
168 | gsl_matrix * ZZ = gsl_matrix_calloc(5,5);
169 |
170 | // Z = M + lamda*W
171 | gsl_matrix_memcpy(Z, W);
172 | gsl_matrix_scale (Z, lambda);
173 | gsl_matrix_add (Z, M);
174 |
175 | gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1, Z, Z, 0, ZZ); /* ZZ = Z * Z' */
176 | /** Calculate eigenvalues and eigenvectors */
177 | gsl_vector * eigenvalues = gsl_vector_alloc(5);
178 | gsl_matrix * eigenvectors = gsl_matrix_alloc(5,5);
179 | eigenv(ZZ, eigenvalues, eigenvectors);
180 | gsl_vector * v0 = gsl_vector_alloc(5);
181 | gsl_matrix_get_col(v0, eigenvectors, gsl_vector_min_index(eigenvalues) );
182 |
183 | /** Conditions: x1 > 0; x4^2 + x5^2 = 1 */
184 | gsl_vector * tmp_v = gsl_vector_alloc(2);
185 | vs(tmp_v ,0, vg(v0, 3));
186 | vs(tmp_v ,1, vg(v0, 4));
187 | double norm = gsl_blas_dnrm2(tmp_v);
188 | double coeff = ( GSL_SIGN( vg(v0,0) ) / norm );
189 | gsl_vector_scale(v0 ,coeff);
190 |
191 | gsl_matrix_free(Z);
192 | gsl_matrix_free(ZZ);
193 | gsl_matrix_free(eigenvectors);
194 | gsl_vector_free(eigenvalues);
195 | gsl_vector_free(tmp_v);
196 | return v0;
197 | }
198 |
199 | int fminimize_simplex(gsl_vector * init, gsl_vector * min_found, gsl_matrix * Q, double (*f) (const gsl_vector *z, void *params) )
200 | {
201 | int sz = (int) init->size;
202 | if ( (Q->size1 != sz) || (Q->size2 != sz) ) return 0;
203 | const gsl_multimin_fminimizer_type * T = gsl_multimin_fminimizer_nmsimplex;
204 | gsl_multimin_fminimizer * s = gsl_multimin_fminimizer_alloc (T, sz);
205 |
206 | void *par = Q->data;
207 | gsl_multimin_function func;
208 | func.n = sz;
209 | func.f = f;
210 | func.params = par;
211 | gsl_vector *step = gsl_vector_alloc(sz);
212 | gsl_vector_set_all(step, 1e-12);
213 |
214 | int iter = 0;
215 | double size;
216 | int status;
217 | gsl_multimin_fminimizer_set (s, &func, init, step);
218 | do {
219 | iter++;
220 | status = gsl_multimin_fminimizer_iterate (s);
221 | if (status) break;
222 |
223 | size = gsl_multimin_fminimizer_size (s);
224 | status = gsl_multimin_test_size(size, 1e-8);
225 |
226 | if (status == GSL_SUCCESS) {
227 | sm_debug("Minimum found at:\n");
228 | for (int i = 0; i < sz; i++)
229 | sm_debug("%f \n", vg(s->x, i));
230 | }
231 | } while (status == GSL_CONTINUE && iter < 2000);
232 |
233 | if (status != GSL_SUCCESS) cout << "Symplex method: Maximum iteration reached before the minimum is found\n";
234 | gsl_vector_memcpy( min_found, gsl_multimin_fminimizer_x(s) );
235 | gsl_multimin_fminimizer_free (s);
236 | return 1;
237 | }
238 |
239 | gsl_vector * numeric_calibration(gsl_matrix * H) {
240 | int sz = (int)(H->size1);
241 | gsl_vector * eigenvalues = gsl_vector_alloc(sz);
242 | gsl_matrix * eigenvectors = gsl_matrix_alloc(sz,sz);
243 | eigenv(H, eigenvalues, eigenvectors);
244 |
245 | gsl_vector * v0 = gsl_vector_alloc(sz);
246 | gsl_matrix_get_col(v0, eigenvectors, sz-5); /*Starting point for numerical search*/
247 |
248 | gsl_vector * tmp_v = gsl_vector_alloc(2);
249 | vs(tmp_v , 0, vg(v0, sz-2));
250 | vs(tmp_v , 1, vg(v0, sz-1));
251 | double norm = gsl_blas_dnrm2(tmp_v);
252 | double coeff = ( GSL_SIGN( vg(v0,0) ) / norm );
253 | gsl_vector_scale(v0 ,coeff);
254 | gsl_vector_free(tmp_v);
255 |
256 | gsl_vector * min = gsl_vector_alloc(sz); /*vector where minimum will be stored*/
257 | fminimize_simplex(v0, min, H, &f);
258 |
259 | return min;
260 | }
261 |
262 | /**
263 | Function f(z) = [z(1) z(2) ... z(n)]' * M * [z(1) z(2) ... z(n)].
264 | Used for minimization in solver routine
265 | */
266 | double f (const gsl_vector *z, void *params) {
267 | int sz = (int) z->size;
268 | gsl_vector * v = gsl_vector_alloc(sz);
269 | gsl_matrix * M = gsl_matrix_alloc(sz, sz);
270 | gsl_vector_memcpy(v, z);
271 |
272 | double *p = (double *)params;
273 | M->data = p;
274 | double * res = new double;
275 | gsl_vector * tmp = gsl_vector_calloc(sz);
276 | gsl_blas_dgemv(CblasNoTrans, 1, M, v, 0, tmp);
277 | gsl_blas_ddot(v ,tmp, res);
278 | gsl_vector_free(tmp);
279 |
280 | return( res[0] );
281 | }
282 |
283 |
284 |
--------------------------------------------------------------------------------
/src/solver_utils.h:
--------------------------------------------------------------------------------
1 | /*!
2 | \file solver_utils.h
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Header of Solver_utils
5 | */
6 |
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include "aux_functions.h"
14 |
15 | using namespace std;
16 |
17 | /*!
18 | \brief calculates condition number for a matrix
19 | @param M gsl_matrix pointer
20 | @return condition number of matrix M
21 | */
22 | double cond_number(gsl_matrix * M);
23 |
24 | /*!
25 | \brief Solves linear system \f$ Ax=g \f$, where A is a square matrix \f$ ( x = inv(A)g ) \f$
26 | @param A gsl_matrix pointer
27 | @param g gsl_vector pointer
28 | @param x gsl_vector pointer to store result
29 | @return 1 if succesfull, 0 otherwhise
30 | */
31 | int solve_square_linear(gsl_matrix * A, gsl_vector * g, gsl_vector * x);
32 | /*!
33 | Compute eigenvalues and eigenvectors of a symmetric matrix M
34 | */
35 | /*!
36 | \brief Calculates eigenvalues and eigenvectors (sorted in ascending order) of a symmetric matrix
37 | @param M gsl_matrix pointer
38 | @param eigenvalues gsl_vector pointer
39 | @param eigenvectors gsl_vector pointer to store eigenvectors
40 | @return 1 if succesfull, 0 otherwise
41 | */
42 | int eigenv(gsl_matrix * M, gsl_vector * eigenvalues, gsl_matrix * eigenvectors);
43 |
44 | /*!
45 | \brief Calculates values of a quadratic function \f$ x'Mx \f$ for a given x
46 | @param x gsl_vector pointer
47 | @param M gsl_matrix pointer
48 | @return value of function
49 | */
50 | double calculate_error(gsl_vector * x, gsl_matrix * M);
51 |
52 | /*!
53 | \brief Calculate x solution of \f$ (M + \lambda W)x = 0 \f$; \lambda such that \f$ (M + \lambda W) \f$ is singular
54 | @param M gsl_matrix pointer
55 | @param lambda gsl_vector pointer
56 | @param W gsl_matrix pointer
57 | @return pointer to gsl_vector storing solution
58 | \note Caller must deallocate returned pointer
59 | */
60 | gsl_vector * x_given_lambda(gsl_matrix * M, double lambda, gsl_matrix * W);
61 |
62 | /*!
63 | \brief Solves \f$ (M + \lambda W)x = 0 \f$, M is a square matrix, \f$ W = \left[ \begin{array}{cc} 0_{3x3} & 0_{3x2} \\ 0_{2x3} & I_{2x2} \end{array} \right] \f$
64 | @param M gsl_matrix pointer
65 | @return pointer to gsl_vector storing solution
66 | \note Caller must deallocate returned pointer
67 | */
68 | gsl_vector * full_calibration_min(gsl_matrix * M);
69 |
70 | /*!
71 | \brief Numerically search minimum for a function \f$ x'Qx \f$, starting from a specified point, using symplex method
72 | @param init initial point for minimization
73 | @param min_found pointer to gsl_vector to store result
74 | @param Q pointer to gsl_matrix
75 | @param double(*f) is a pointer to function
76 | @return 1 if successfull, 0 otherwhise
77 | */
78 | int fminimize_simplex(gsl_vector * init, gsl_vector * min_found, gsl_matrix * Q, double (*f) (const gsl_vector *z, void *params) );
79 |
80 | /*!
81 | \brief Uses symplex method to estimate parameters
82 | @param H pointer to matrix of quadratic function (\f$ x'Hx \f$)
83 | @return pointer to gsl_vector storing minimum
84 | */
85 | gsl_vector * numeric_calibration(gsl_matrix * H);
86 |
87 | /*!
88 | \brief Implements a quadratic function (used in minimization functions)
89 | @param z pointer to point where the function has to be evaluated
90 | @param params pointer to parameters vector
91 | */
92 | double f (const gsl_vector *z, void *params);
93 |
94 |
95 |
--------------------------------------------------------------------------------
/src/synchronizer.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file synchronizer.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief synchronizes an odometry log and a laser log
5 | */
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include "synchronizer_options.h"
18 | #include "aux_functions.h"
19 |
20 | using namespace std;
21 | using namespace CSM;
22 |
23 | extern void synchro_options(synchro_params*p, struct option*ops);
24 |
25 | int main(int argc, const char * argv[]) {
26 | sm_set_program_name("Synchronizer");
27 |
28 | //!
29 | synchro_params params;
30 | struct option* ops = options_allocate(100);
31 | synchro_options(¶ms, ops);
32 | if(!options_parse_args(ops, argc, argv)) {
33 | options_print_help(ops, stderr);
34 | return -1;
35 | }
36 |
37 | //!
38 | vector laser;
39 | vector odo;
40 | vector result;
41 | if (!read_jsonlist(params.las_file, &laser) ) {
42 | sm_error("Error reading laser_file '%s'.\n", params.las_file);
43 | return -1;
44 | }
45 | if (!read_jsonlist(params.odo_file, &odo) ) {
46 | sm_error("Error reading odometry file '%s'.\n", params.odo_file);
47 | return -1;
48 | }
49 |
50 |
51 | //!
52 | sm_info("Starting synchronization\n");
53 | int n = (int) laser.size();
54 |
55 | int discarded_valid = 0;
56 | int discarded_error = 0;
57 | int discarded_nvalid = 0;
58 | int discarded_t_k = 0;
59 | int discarded_time_tol = 0;
60 | int discarded_no_odo = 0;
61 | int still_num = 0;
62 |
63 | //!
64 | double mean_error[n];
65 | double mean_error_sorted[n];
66 | int nvalid_sorted[n];
67 | double perc = params.perc_threshold;
68 |
69 | for(int i = 0; i < n; i++) {
70 | double error;
71 | int nvalid;
72 |
73 | jo_read_double(laser[i], "error", &error);
74 | jo_read_int(laser[i], "nvalid", &nvalid);
75 | mean_error[i] = error/nvalid;
76 | mean_error_sorted[i] = mean_error[i];
77 | nvalid_sorted[i] = nvalid;
78 | }
79 |
80 | mysort(mean_error_sorted, n);
81 | mysort(nvalid_sorted, n);
82 | double mean_error_threshold = mean_error_sorted[ (int)round(perc*n)];
83 | // cout << "mean_error_threshold " << mean_error_threshold << endl;
84 | int nvalid_threshold = nvalid_sorted[ (int)round((1 - perc)*n)];
85 |
86 | //!
87 | int m = 0;
88 | int last = 0;
89 | int jb_ref, jb_sens;
90 | double error, t_k, left_speed, right_speed;
91 | int nvalid, valid;
92 | double tr1, tr2, ts1, ts2;
93 | double Lr1, Lr2, Ls1, Ls2;
94 | double Rr1, Rr2, Rs1, Rs2;
95 | double laser_ref_ts, laser_sens_ts, t_delta;
96 | double times[4];
97 | double time_tol;
98 | double ref_alpha, sens_alpha, avg_left_start, avg_right_start,
99 | avg_left_end, avg_right_end, left_inc, right_inc;
100 |
101 | double ticks_to_rad = 2 * M_PI / ( 691.2 * 4 );
102 | for (int k = 0; k < n; k++) {
103 | valid = jo_read_int(laser[k], "valid", &valid);
104 | if (valid == 0) {
105 | discarded_valid = discarded_valid + 1;
106 | continue;
107 | }
108 |
109 | /*
110 | for each entry in raw_sm we seek the two indices
111 | which are immediately before and after in raw_odo
112 | */
113 | t_delta = params.laser_timestamp_correction;
114 | laser_ref_ts = t_delta + gettime(laser[k], "laser_ref_timestamp");
115 | laser_sens_ts = t_delta + gettime(laser[k], "laser_sens_timestamp");
116 |
117 | jb_ref = find_closest_ref(laser_ref_ts, odo, last);
118 | jb_sens = find_closest_sens(laser_sens_ts, odo, last);
119 | // jb_ref = find_closest(laser_ref_ts, odo, last);
120 | // jb_sens = find_closest(laser_sens_ts, odo, last);
121 |
122 | if ( (jb_ref == -1) || (jb_sens == -1) ) {
123 | discarded_no_odo = discarded_no_odo + 1;
124 | sm_info("merge_logs: Could not match timestamp %f %f\n", laser_ref_ts, laser_sens_ts);
125 | continue;
126 | }
127 | last = jb_ref;
128 |
129 | tr1 = gettime(odo[jb_ref] , "timestamp");
130 | tr2 = gettime(odo[jb_ref +1] , "timestamp");
131 | ts1 = gettime(odo[jb_sens -1] , "timestamp");
132 | ts2 = gettime(odo[jb_sens] , "timestamp");
133 |
134 | times[0] = fabs( tr1 - laser_ref_ts );
135 | times[1] = fabs( tr2 - laser_ref_ts );
136 | times[2] = fabs( ts1 - laser_sens_ts );
137 | times[3] = fabs( ts2 - laser_sens_ts );
138 | mysort(times, 4);
139 | time_tol = times[3];
140 |
141 | ref_alpha = (laser_ref_ts - tr1) / (tr2 - tr1);
142 | sens_alpha = (laser_sens_ts - ts1) /(ts2 - ts1);
143 |
144 | Lr1 = getticks(odo[jb_ref] , "left");
145 | Lr2 = getticks(odo[jb_ref+1] , "left");
146 | Ls1 = getticks(odo[jb_sens-1] , "left");
147 | Ls2 = getticks(odo[jb_sens] , "left");
148 | Rr1 = getticks(odo[jb_ref] , "right");
149 | Rr2 = getticks(odo[jb_ref+1] , "right");
150 | Rs1 = getticks(odo[jb_sens-1] , "right");
151 | Rs2 = getticks(odo[jb_sens] , "right");
152 |
153 | avg_left_start = (1-ref_alpha) * Lr1 + ref_alpha * Lr2;
154 | avg_right_start = (1-ref_alpha) * Rr1 + ref_alpha * Rr2;
155 | avg_left_end = (1-sens_alpha)* Ls1 + sens_alpha* Ls2;
156 | avg_right_end = (1-sens_alpha)* Rs1 + sens_alpha* Rs2;
157 |
158 | left_inc = (avg_left_end - avg_left_start);
159 | right_inc = (avg_right_end - avg_right_start);
160 | //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
161 | // // Calculate time tolerance
162 | // double times[4];
163 | // times[0] = fabs( gettime(odo[jb_ref], "timestamp") - laser_ref_ts );
164 | // times[1] = fabs( gettime(odo[jb_ref+1], "timestamp") - laser_ref_ts );
165 | // times[2] = fabs( gettime(odo[jb_sens], "timestamp") - laser_sens_ts );
166 | // times[3] = fabs( gettime(odo[jb_sens+1], "timestamp") - laser_sens_ts );
167 | // mysort(times, 4);
168 | // double time_tol = times[3];
169 | //
170 | // // Check if the robot is still
171 | // double ref_alpha = (laser_ref_ts - gettime(odo[jb_ref],"timestamp")) / (gettime(odo[jb_ref+1],"timestamp") - gettime(odo[jb_ref],"timestamp") );
172 | // double sens_alpha = ( laser_sens_ts - gettime(odo[jb_sens],"timestamp")) / (gettime(odo[jb_sens+1],"timestamp") - gettime(odo[jb_sens],"timestamp") );
173 | //
174 | // // double avg_left_start = ( getticks(odo[jb_ref], "left") + getticks(odo[jb_ref+1], "left") )/2;
175 | // // double avg_right_start = ( getticks(odo[jb_ref], "right") + getticks(odo[jb_ref+1], "right") )/2;
176 | // // double avg_left_end = ( getticks(odo[jb_sens], "left") + getticks(odo[jb_sens+1], "left") )/2;
177 | // // double avg_right_end = ( getticks(odo[jb_sens], "right") + getticks(odo[jb_sens+1], "right") )/2;
178 | // double avg_left_start = ref_alpha*getticks(odo[jb_ref], "left") + (1-ref_alpha)*getticks(odo[jb_ref+1], "left");
179 | // double avg_right_start = ref_alpha*getticks(odo[jb_ref],"right")+(1-ref_alpha)*getticks(odo[jb_ref+1],"right");
180 | //
181 | // double avg_left_end = sens_alpha*getticks(odo[jb_sens],"left") + (1-sens_alpha)*getticks(odo[jb_sens+1],"left");
182 | // double avg_right_end = sens_alpha*getticks(odo[jb_sens],"right")+(1-sens_alpha)*getticks(odo[jb_sens+1],"right");
183 | //
184 | // double left_inc = (avg_left_end - avg_left_start);
185 | // double right_inc = (avg_right_end - avg_right_start);
186 | //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
187 |
188 | if ( (left_inc == 0) && (right_inc == 0) ) {
189 | still_num = still_num + 1;
190 | continue;
191 | }
192 |
193 | /* Check if data is awful and eventually discard it */
194 | jo_read_double(laser[k], "error", &error);
195 | if( error == 0 ) {
196 | continue;
197 | }
198 |
199 | if(mean_error[k] > mean_error_threshold) {
200 | discarded_error = discarded_error + 1;
201 | continue;
202 | }
203 |
204 | jo_read_int(laser[k], "nvalid", &nvalid);
205 | if( nvalid <= nvalid_threshold ) {
206 | discarded_nvalid = discarded_nvalid + 1;
207 | continue;
208 | }
209 |
210 | if ( time_tol > params.time_tolerance ) {
211 | discarded_time_tol = discarded_time_tol + 1;
212 | continue;
213 | }
214 |
215 | t_k = laser_sens_ts - laser_ref_ts;
216 |
217 | if( t_k > params.tk_threshold) {
218 | discarded_t_k = discarded_t_k + 1;
219 | cout << "Interval between scans exceedes limit: " << t_k << " > " << params.tk_threshold << endl;
220 | continue;
221 | }
222 |
223 | left_speed = (left_inc * ticks_to_rad) / t_k;
224 | right_speed = (right_inc * ticks_to_rad) / t_k;
225 |
226 | /* Build k-esim json object*/
227 | struct json_object *new_obj;
228 | new_obj = json_object_new_object();
229 | json_object_object_add(new_obj, "T", json_object_new_double(t_k) );
230 | json_object_object_add(new_obj, "phi_l", json_object_new_double(left_speed) );
231 | json_object_object_add(new_obj, "phi_r", json_object_new_double(right_speed) );
232 | double sm[3];
233 | jo_read_double_array (laser[k], "x", sm, 3, 0.0);
234 | jo_add_double_array (new_obj, "sm", sm, 3);
235 | // double odometry[3];
236 | // jo_read_double_array (odo[jb_ref], "odometry", odometry, 3, 0.0);
237 | // jo_add_double_array (new_obj, "odometry", odometry, 3);
238 | // json_object_object_add(new_obj, "time_tol", json_object_new_double(time_tol) );
239 | // json_object_object_add(new_obj, "error", json_object_new_double(error) );
240 | // json_object_object_add(new_obj, "mean_error", json_object_new_double(mean_error[k]) );
241 | // json_object_object_add(new_obj, "nvalid", json_object_new_int(nvalid) );
242 | // json_object_object_add(new_obj, "sens_alpha", json_object_new_double(sens_alpha) );
243 | // json_object_object_add(new_obj, "ref_alpha", json_object_new_double(ref_alpha) );
244 | result.push_back(new_obj) ;
245 |
246 | m = m + 1;
247 | }
248 |
249 | //!
250 | if ( !write_jsonlist(params.out_file, &result) ) {
251 | sm_error("Error writing on output file '%s'.\n", params.out_file);
252 | return (-1);
253 | }
254 |
255 | sm_info(" still number: %d\n", still_num);
256 | sm_info(" Number of valid data: %d\n", m);
257 | sm_info(" discarded valid: %d\n", discarded_valid);
258 | sm_info(" discarded error: %d\n", discarded_error);
259 | sm_info(" discarded nvalid: %d\n", discarded_nvalid);
260 | sm_info(" discarded_t_k: %d\n", discarded_t_k);
261 | sm_info(" discarded_time_tol: %d\n", discarded_time_tol);
262 | sm_info(" discarded_no_odo: %d\n", discarded_no_odo);
263 |
264 | return 0;
265 | }
266 |
--------------------------------------------------------------------------------
/src/synchronizer_options.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file synchronizer_options.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Options for the syncronizer executable. (implementation file)
5 | */
6 |
7 | #include
8 | #include "synchronizer_options.h"
9 |
10 | void synchro_options(synchro_params *p, struct option*ops) {
11 |
12 | options_string(ops, "las_file",
13 | &(p->las_file), "",
14 | "Input sm_stats file");
15 |
16 | options_string(ops, "odo_file",
17 | (&p->odo_file), "",
18 | "Input odometry file ");
19 |
20 | options_string(ops, "output",
21 | &(p->out_file), "stdout",
22 | "Output file ");
23 |
24 | options_double(ops, "laser_timestamp_correction",
25 | &(p->laser_timestamp_correction), 0.0,
26 | "Correction for laser timestamp");
27 |
28 | options_double(ops, "perc_threshold",
29 | &(p->perc_threshold), 0.95,
30 | "Percentual threshold");
31 |
32 | options_double(ops, "time_tolerance",
33 | &(p->time_tolerance), 0.05,
34 | "A threshold on time tolerance (sec)");
35 |
36 | options_double(ops, "tk_threshold",
37 | &(p->tk_threshold), 3.0,
38 | "A threshold on the differerence between laser_sens_timestamp and laser_ref_timestamp (sec)");
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/synchronizer_options.h:
--------------------------------------------------------------------------------
1 | /*!
2 | \file synchronizer_options.h
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Options for the synchronizer executable (header file)
5 | */
6 |
7 | #ifndef _SYNCHRONIZER_OPTIONS_H
8 | #define _SYNCHRONIZER_OPTIONS_H
9 |
10 | /*!
11 | \struct synchro_params
12 | \brief Synchronizer parameter instance structure
13 | @param las_file Input sm_stats file for synchronizer procedure.\n Default Null
14 | @param odo_file Input odometry file for synchronizer procedure.\n Default Null
15 | @param out_file Output file of synchronizer procedure.\n Default stdout
16 | @param laser_timestamp_correction Correction for laser timestamp.\n Default 0.0
17 | @param perc_threshold Value used to define a threshold on mean error and nvalid.\n Default 0.95, range is [0,1]
18 | @param time_tolerance A threshold on time tolerance.\n Default 0.05
19 | @param tk_threshold A threshold on the differerence between laser_sens_timestamp and laser_ref_timestamp.\n Default 5.0
20 | */
21 | typedef struct {
22 | const char * las_file;
23 | const char * odo_file;
24 | const char * out_file;
25 | double laser_timestamp_correction;
26 | double perc_threshold;
27 | double time_tolerance;
28 | double tk_threshold;
29 | } synchro_params;
30 |
31 | /*!
32 | \brief Initializes parameters for synchronization procedure
33 | \param p pointer to parameters' structure
34 | \param ops options' structure
35 | */
36 | void synchro_options(synchro_params*p, struct option*ops);
37 |
38 | #endif
39 |
40 |
--------------------------------------------------------------------------------
/src/test_json.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(int argc, const char * argv[]) {
5 | sm_set_program_name(argv[0]);
6 |
7 | int n;
8 |
9 | /* Clean treatment of parameters using the "options" library */
10 | struct option* ops = options_allocate(3);
11 | options_int(ops, "n", &n, 1, "Number of copies");
12 |
13 | if(!options_parse_args(ops, argc, argv)) {
14 | sm_info("%s : reads a JSON stream and copies it multiplied by n."
15 | "\n\nOptions:\n", (char*)argv[0]);
16 | options_print_help(ops, stderr);
17 | return -1;
18 | }
19 |
20 | JO jo;
21 |
22 | while((jo = json_read_stream(stdin))) {
23 | const char * s = json_object_to_json_string(jo);
24 | int i; for(i=0;i
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #include "verifier_utils.h"
26 | #include "verifier_options.h"
27 | #include "aux_functions.h"
28 |
29 | #include "analyzer.h"
30 |
31 | using namespace std;
32 | using namespace CSM;
33 |
34 | int main(int argc, const char * argv[]) {
35 |
36 | /*!*/
37 | verifier_params params;
38 | struct option* ops = options_allocate(100);
39 | verifier_options(¶ms, ops);
40 | if(!options_parse_args(ops, argc, argv)) {
41 | options_print_help(ops, stderr);
42 | return -2;
43 | }
44 |
45 | JO est_params;
46 | FILE * input = open_file_for_reading(params.calib_params);
47 | if (!input) return 1;
48 | est_params = json_read_stream(input);
49 | fclose(input);
50 | double l_diam, r_diam, axle;
51 | double laser[3];
52 | jo_read_double(est_params, "l_diam", &l_diam);
53 | jo_read_double(est_params, "r_diam", &r_diam);
54 | jo_read_double(est_params, "axle", &axle);
55 | jo_read_double(est_params, "l_x", &laser[0]);
56 | jo_read_double(est_params, "l_y", &laser[1]);
57 | jo_read_double(est_params, "l_theta", &laser[2]);
58 |
59 | printf("\nparametri stimati: b = %f, l_diam = %f, r_diam = %f, l_x = %f, l_y = %f, l_theta = %f\n", axle, l_diam, r_diam, laser[0], laser[1], laser[2]);
60 |
61 | double J11 = l_diam/4;
62 | double J12 = r_diam/4;
63 | double J21 = -l_diam/(2*axle);
64 | double J22 = r_diam/(2*axle);
65 |
66 | vector odo;
67 | if (!read_jsonlist(params.odometry, &odo) ) {
68 | sm_error("Error opening input files.\n");
69 | return -1;
70 | }
71 | vector smStats;
72 | if (!read_jsonlist(params.smStats, &smStats) ) {
73 | sm_error("Error opening input files.\n");
74 | return -1;
75 | }
76 |
77 | vector matchedOdo;
78 | vector matchedLas;
79 | matchOdoLas(odo, smStats, &matchedOdo, &matchedLas);
80 | int nOdo = (int)matchedOdo.size();
81 | int nLas = (int)matchedLas.size();
82 | vector integratedOdo;
83 | integratedOdo.reserve(nOdo);
84 | vector integratedLas;
85 | integratedLas.reserve(nLas);
86 | /*!*/
87 | double tmp_q[3];
88 | double q_int[3];
89 | double o[3];
90 | double T_i;
91 | double left_inc, right_inc;
92 | double ticks_to_rad;
93 | double w_l, w_r, v_i, w_i;
94 | double o_increment[3], t1, t2;
95 | struct json_object *new_obj;
96 |
97 | //set initial position.
98 | jo_read_double_array (matchedOdo[0], "odometry", q_int, 3, 0.0);
99 | new_obj = json_object_new_object();
100 | jo_add_double_array (new_obj, "odometry", q_int, 3);
101 | integratedOdo.push_back(new_obj);
102 |
103 | for (int i = 0; i < nOdo-1; i++) {
104 | //calcolo v_k, w_k;
105 | T_i = gettime( matchedOdo[i+1], "timestamp") - gettime( matchedOdo[i], "timestamp");
106 | left_inc = getticksD(matchedOdo[i+1], "left") - getticksD(matchedOdo[i], "left");
107 | right_inc = getticksD(matchedOdo[i+1], "right") - getticksD(matchedOdo[i], "right");
108 | ticks_to_rad = 2 * M_PI / ( 691.2 * 4 );
109 | w_l = (left_inc * ticks_to_rad) / T_i;
110 | w_r = (right_inc * ticks_to_rad) / T_i;
111 | v_i = J11*w_l + J12*w_r;
112 | w_i = J21*w_l + J22*w_r;
113 | o_increment[2] = w_i*T_i;
114 |
115 | if ( fabs(o_increment[2]) > 1e-7 ) {
116 | t1 = ( sin(o_increment[2]) / (o_increment[2]) );
117 | t2 = ( (1-cos(o_increment[2])) / (o_increment[2]) );
118 | }
119 | else {
120 | t1 = 1;
121 | t2 = 0;
122 | }
123 | //i-esimo passo di integrazione
124 | o_increment[0] = ( (v_i*T_i)*t1 );
125 | o_increment[1] = ( (v_i*T_i)*t2 );
126 | tmp_q[0] = q_int[0];
127 | tmp_q[1] = q_int[1];
128 | tmp_q[2] = q_int[2];
129 | planarComp(tmp_q, o_increment, q_int);
130 | if (q_int[2] > M_PI) q_int[2] = q_int[2] - 2*M_PI;
131 | if (q_int[2] < -M_PI) q_int[2] = q_int[2] + 2*M_PI;
132 | //store integration step
133 | new_obj = json_object_new_object();
134 | jo_add_double_array (new_obj, "odometry", q_int, 3);
135 | integratedOdo.push_back(new_obj);
136 | } // end for
137 |
138 | // calcolo della rototraslazione tra q0 e la qk ricavata dall'integrazione dell'odometria con i nuovi parametri
139 | jo_read_double_array (matchedOdo[0], "odometry", tmp_q, 3, 0.0);
140 | inv_planarComp(q_int, tmp_q, o);
141 |
142 | jo_read_double_array (matchedOdo[nOdo-1], "odometry", tmp_q, 3, 0.0);
143 | printf("\nfinal odometry:\t%3.6f\t%3.6f\t%3.6f\n", tmp_q[0], tmp_q[1], tmp_q[2]);
144 |
145 | /*!*/
146 | double tmp_s[3];
147 | double s[3];
148 | double s_int[3];
149 |
150 | switch(params.use_gsl) {
151 | case 1: {
152 | cout << "Using GSL...\n";
153 | gsl_matrix * T = gsl_matrix_calloc(4,4);
154 | gsl_matrix * A = gsl_matrix_calloc(4,4);
155 | gsl_matrix * R = gsl_matrix_calloc(4,4);
156 |
157 | jo_read_double_array (matchedOdo[0], "odometry", tmp_s, 3, 0.0);
158 | new_obj = json_object_new_object();
159 | jo_add_double_array (new_obj, "odometrySm", tmp_s, 3);
160 | integratedLas.push_back(new_obj);
161 | rototras(A, tmp_s[0], tmp_s[1], tmp_s[2]);
162 | rototras(T, laser[0], laser[1], laser[2]);
163 | gsl_blas_dgemm (CblasNoTrans,CblasNoTrans, 1, A, T, 1, R);
164 | gsl_matrix_memcpy(A,R);
165 | gsl_matrix_free(R);
166 |
167 | for(int u = 0; u < nLas; u++) {
168 | R = gsl_matrix_calloc(4,4);
169 | jo_read_double_array (matchedLas[u], "x", tmp_s, 3, 0.0);
170 | rototras(T, tmp_s[0], tmp_s[1], tmp_s[2]);
171 | gsl_blas_dgemm (CblasNoTrans,CblasNoTrans, 1, A, T, 1, R);
172 | gsl_matrix_memcpy(A,R);
173 | gsl_matrix_free(R);
174 |
175 | R = gsl_matrix_calloc(4,4);
176 | rototras(T, laser[0], laser[1], laser[2]);
177 | gsl_matrix * LU = gsl_matrix_alloc(4,4);
178 | gsl_permutation * p = gsl_permutation_alloc(4);
179 | gsl_matrix_memcpy(LU, T);
180 | int signum;
181 | gsl_linalg_LU_decomp (LU, p, &signum );
182 | gsl_linalg_LU_invert (LU, p, T );
183 | gsl_blas_dgemm (CblasNoTrans,CblasNoTrans, 1, A, T, 1, R);
184 | s[0] = gsl_matrix_get(R, 0, 3);
185 | s[1] = gsl_matrix_get(R, 1, 3);
186 | s[2] = atan2( gsl_matrix_get(R, 1, 0) , gsl_matrix_get(R, 0, 0) );
187 | new_obj = json_object_new_object();
188 | jo_add_double_array (new_obj, "odometrySm", s, 3);
189 | integratedLas.push_back(new_obj);
190 | gsl_matrix_free(R);
191 | }
192 | break;
193 | }
194 | case 0: {
195 | cout << "no GSL\n";
196 | jo_read_double_array (matchedOdo[0], "odometry", s_int, 3, 0.0);
197 | tmp_s[0] = s_int[0];
198 | tmp_s[1] = s_int[1];
199 | tmp_s[2] = s_int[2];
200 | new_obj = json_object_new_object();
201 | jo_add_double_array (new_obj, "odometrySm", s_int, 3);
202 | integratedLas.push_back(new_obj);
203 |
204 | planarComp(tmp_s, laser, s_int);
205 | if (s_int[2] > M_PI) s_int[2] = s_int[2] - 2*M_PI;
206 | if (s_int[2] < -M_PI) s_int[2] = s_int[2] + 2*M_PI;
207 |
208 | for (int u = 0; u < nLas; u++) {
209 | tmp_s[0] = s_int[0];
210 | tmp_s[1] = s_int[1];
211 | tmp_s[2] = s_int[2];
212 | jo_read_double_array (matchedLas[u], "x", s, 3, 0.0);
213 | planarComp(tmp_s, s, s_int);
214 | if (s_int[2] > M_PI) s_int[2] = s_int[2] - 2*M_PI;
215 | if (s_int[2] < -M_PI) s_int[2] = s_int[2] + 2*M_PI;
216 |
217 | tmp_s[2] = s_int[2]- laser[2];
218 | tmp_s[0] = s_int[0] - laser[0]*cos(tmp_s[2]) + laser[1]*sin(tmp_s[2]);
219 | tmp_s[1] = s_int[1] - laser[0]*sin(tmp_s[2]) - laser[1]*cos(tmp_s[2]);
220 | if (tmp_s[2] > M_PI) tmp_s[2] = tmp_s[2] - 2*M_PI;
221 | if (tmp_s[2] < -M_PI) tmp_s[2] = tmp_s[2] + 2*M_PI;
222 | new_obj = json_object_new_object();
223 | jo_add_double_array (new_obj, "odometrySm", s_int, 3);
224 | integratedLas.push_back(new_obj);
225 |
226 | }
227 | tmp_s[0] = s_int[0];
228 | tmp_s[1] = s_int[1];
229 | tmp_s[2] = s_int[2];
230 |
231 | s_int[2] = tmp_s[2]- laser[2];
232 | s_int[0] = tmp_s[0] - laser[0]*cos(s_int[2]) + laser[1]*sin(s_int[2]);
233 | s_int[1] = tmp_s[1] - laser[0]*sin(s_int[2]) - laser[1]*cos(s_int[2]);
234 | if (s_int[2] > M_PI) s_int[2] = s_int[2] - 2*M_PI;
235 | if (s_int[2] < -M_PI) s_int[2] = s_int[2] + 2*M_PI;
236 |
237 | new_obj = json_object_new_object();
238 | jo_add_double_array (new_obj, "odometrySm", s_int, 3);
239 | integratedLas.push_back(new_obj);
240 |
241 | jo_read_double_array (matchedOdo[0], "odometry", tmp_s, 3, 0.0);
242 | inv_planarComp(s_int, tmp_s, s);
243 | }
244 | default: break;
245 | }
246 |
247 | /*!*/
248 | double e[3];
249 | inv_planarComp(s, o, e);
250 | if (e[2] > M_PI) e[2] = e[2] - 2*M_PI;
251 | if (e[2] < -M_PI) e[2] = e[2] + 2*M_PI;
252 |
253 | /*!*/
254 | new_obj = json_object_new_object();
255 | jo_add_double_array (new_obj, "o", o, 3);
256 | jo_add_double_array (new_obj, "s", s, 3);
257 | jo_add_double_array (new_obj, "e", e, 3);
258 | // Write json object to file
259 | FILE * output;
260 | if(!strcmp(params.out, "stdout")) { output = stdout;}
261 | else {output = fopen(params.out, "w");}
262 | fprintf(output, "%s\n", json_object_to_json_string(new_obj) );
263 | fclose(output);
264 |
265 | /*!*/
266 |
267 | Analyzer * an;
268 |
269 | //Creating Graph using integrated odometry
270 | Graph * ix_graph = new Graph(); Graph * iy_graph = new Graph(); Graph * ith_graph = new Graph();
271 | an->set_par(ix_graph, "x_int.vgr" , "X int coordinate" , "step", "x", "lines", "Integrated Odo");
272 | an->set_par(iy_graph, "y_int.vgr" , "Y int coordinate" , "step", "y", "lines", "Integrated Odo");
273 | an->set_par(ith_graph,"th_int.vgr","THETA int coordinate", "step", "th","lines", "Integrated Odo");
274 | double * int_x = new double[nOdo];
275 | double * int_y = new double[nOdo];
276 | double * int_th = new double[nOdo];
277 | double * int_axis = new double[nOdo];
278 | for (int i = 0; i < nOdo; i++) {
279 | int_axis[i] = i;
280 | jo_read_double_array (integratedOdo[i], "odometry", tmp_s, 3, 0.0);
281 | int_x[i] = tmp_s[0]; int_y[i] = tmp_s[1]; int_th[i] = tmp_s[2];
282 | }
283 | an->add_data_graph(int_x, int_axis, nOdo, ix_graph);
284 | an->add_data_graph(int_y, int_axis, nOdo, iy_graph);
285 | an->add_data_graph(int_th,int_axis, nOdo, ith_graph);
286 |
287 | //Creating Graph using Scan Matcher rototranslation
288 | Graph * lx_graph = new Graph(); Graph * ly_graph = new Graph(); Graph * lth_graph = new Graph();
289 | an->set_par(lx_graph, "x_las.vgr" , "X las coordinate" , "step", "x", "lines", "Scan Matcher");
290 | an->set_par(ly_graph, "y_las.vgr" , "Y las coordinate" , "step", "y", "lines", "Scan Matcher");
291 | an->set_par(lth_graph,"th_las.vgr","THETA las coordinate", "step", "th","lines", "Scan Matcher");
292 |
293 | nLas = nLas+1;
294 | double * las_x = new double[nLas];
295 | double * las_y = new double[nLas];
296 | double * las_th = new double[nLas];
297 | double * las_axis = new double[nLas];
298 | for (int i = 0; i < nLas; i++) {
299 | las_axis[i] = i;
300 | jo_read_double_array (integratedLas[i], "odometrySm", tmp_s, 3, 0.0);
301 | las_x[i] = tmp_s[0]; las_y[i] = tmp_s[1]; las_th[i] = tmp_s[2];
302 | }
303 | an->add_data_graph(las_x, las_axis, nLas, lx_graph);
304 | an->add_data_graph(las_y, las_axis, nLas, ly_graph);
305 | an->add_data_graph(las_th,las_axis, nLas, lth_graph);
306 |
307 | //Creating Graph using odometry
308 | Graph * ox_graph = new Graph(); Graph * oy_graph = new Graph(); Graph * oth_graph = new Graph();
309 | an->set_par(ox_graph, "x_odo.vgr" , "X odo coordinate" , "step", "x", "lines", "Odometry");
310 | an->set_par(oy_graph, "y_odo.vgr" , "Y odo coordinate" , "step", "y", "lines", "Odometry");
311 | an->set_par(oth_graph,"th_odo.vgr", "THETA odo coordinate", "step", "th","lines", "Odometry");
312 | double * odo_x = new double[nOdo];
313 | double * odo_y = new double[nOdo];
314 | double * odo_th = new double[nOdo];
315 | double * odo_axis = new double[nOdo];
316 | for (int i = 0; i < nOdo; i++) {
317 | odo_axis[i] = i;
318 | jo_read_double_array (matchedOdo[i], "odometry", tmp_s, 3, 0.0);
319 | odo_x[i] = tmp_s[0]; odo_y[i] = tmp_s[1]; odo_th[i] = tmp_s[2];
320 | }
321 | an->add_data_graph(odo_x, odo_axis, nOdo, ox_graph);
322 | an->add_data_graph(odo_y, odo_axis, nOdo, oy_graph);
323 | an->add_data_graph(odo_th,odo_axis, nOdo, oth_graph);
324 |
325 | // Creating Graph s_theta (as y) vs i_theta (as x)
326 | Graph * thesi_graph = new Graph();
327 | an->set_par(thesi_graph, "th_s-i.vgr", "THETA sm versus integrated", "i_theta", "s_theta", "points", "");
328 | an->add_data_graph(las_th, int_th, nOdo, thesi_graph);
329 |
330 | // Creating Graph trajectory
331 | double * spec_int_y = new double[nOdo];
332 | double * spec_odo_y = new double[nOdo];
333 | double * spec_las_y = new double[nLas];
334 | for (int i = 0; i < nOdo; i++) {
335 | spec_int_y[i] = -int_y[i];
336 | spec_odo_y[i] = -odo_y[i];
337 | }
338 | for (int i = 0; i < nLas; i++) {
339 | spec_las_y[i] = -las_y[i];
340 | }
341 | Graph traj_graph[3];
342 | an->set_par(&(traj_graph[0]), "i_traj.vgr", "Trajectory integrated" , "", "", "lines", "integrated Odo");
343 | an->set_par(&(traj_graph[1]), "l_traj.vgr", "Trajectory scan matcher", "", "", "lines", "Scan matcher");
344 | an->set_par(&(traj_graph[2]), "o_traj.vgr", "Trajectory odometry" , "", "", "lines", "odometry");
345 |
346 | an->add_data_graph(int_x, spec_int_y, nOdo, &traj_graph[0]);
347 | an->add_data_graph(las_x, spec_las_y, nOdo, &traj_graph[1]);
348 | an->add_data_graph(odo_x, spec_odo_y, nOdo, &traj_graph[2]);
349 |
350 | // Creating error plots
351 | Graph * eth_graph, * ethAbs_graph, * releth_graph;
352 |
353 | if (nLas == nOdo) {
354 | // Creating graph absolute theta error (int_th - las_th)
355 | ethAbs_graph = new Graph();
356 | an->set_par(ethAbs_graph, "err_th_abs.vgr", "Absolute THETA error", "step", "|E_th|", "lines", "");
357 | double * ethAbs = new double[nOdo];
358 | for (int i = 0; i < nOdo; i++) ethAbs[i] = fabs(int_th[i] - las_th[i]);
359 | an->add_data_graph(ethAbs, int_axis, nOdo, ethAbs_graph);
360 |
361 | // Creating graph theta error (int_th - las_th)
362 | eth_graph = new Graph();
363 | an->set_par(eth_graph, "err_th.vgr", "THETA error", "step", "E_th", "lines", "");
364 | double * eth = new double[nOdo];
365 | for (int i = 0; i < nOdo; i++) eth[i] = (int_th[i] - las_th[i]);
366 | an->add_data_graph(eth, int_axis, nOdo, eth_graph);
367 |
368 | // Creating graph error theta vs integrated theta
369 | releth_graph = new Graph();
370 | an->set_par(releth_graph, "rel_err_th.vgr", "relative THETA error", "i_th", "i_th - s_th", "points", "");
371 | an->add_data_graph(eth, int_th, nOdo, releth_graph);
372 | }
373 | else {
374 | cout << "Note: number of laser entries is: " << nLas
375 | << ", while number of odometry entries is: " << nOdo
376 | << "\n Omitting error graphs!\n";
377 | }
378 |
379 | // Creating plots
380 | int n_plots = 3;
381 | Graph * x_plots = new Graph[n_plots];
382 | Graph * y_plots = new Graph[n_plots];
383 | Graph * th_plots = new Graph[n_plots];
384 |
385 | x_plots[0] = ix_graph[0]; x_plots[1] = lx_graph[0]; x_plots[2] = ox_graph[0];
386 | y_plots[0] = iy_graph[0]; y_plots[1] = ly_graph[0]; y_plots[2] = oy_graph[0];
387 | th_plots[0] = ith_graph[0]; th_plots[1] = lth_graph[0]; th_plots[2] = oth_graph[0];
388 |
389 | // Plotting
390 | cout << "Plotting odometry's and laser's graphs" << endl;
391 | an->create_same_plot("X coordinate", "step", "x", x_plots, n_plots, "x_plots.vpl", 1, 1);
392 | an->plot("x_plots.vpl");
393 | an->create_same_plot("Y coordinate", "step", "y", y_plots, n_plots, "y_plots.vpl", 1, 1);
394 | an->plot("y_plots.vpl");
395 | an->create_same_plot("Theta coordinate", "step", "th", th_plots, n_plots, "th_plots.vpl", 1, 1);
396 | an->plot("th_plots.vpl");
397 | an->create_same_plot("Trajectory", "world x", "world y", traj_graph, 3, "traj_plot.vpl", 1, 1);
398 | an->plot("traj_plot.vpl");
399 |
400 | if (nLas == nOdo) {
401 | cout << "Plotting errors' graphs" << endl;
402 | an->create_plot(thesi_graph, 1, "thesi_plot.vpl", 1, 0);
403 | an->plot("thesi_plot.vpl");
404 | an->create_plot(eth_graph , 1, "eth_plot.vpl", 1, 0);
405 | an->plot("eth_plot.vpl");
406 | an->create_plot(ethAbs_graph,1, "ethAbs_plot.vpl", 1, 0);
407 | an->plot("ethAbs_plot.vpl");
408 | an->create_plot(releth_graph,1, "releth_plot.vpl", 1, 0);
409 | an->plot("releth_plot.vpl");
410 | }
411 | return 0;
412 | }
413 |
--------------------------------------------------------------------------------
/src/verifier_options.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file verifier_options.ccp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Manages options for verifier (implementation file)
5 | */
6 | #include
7 | #include "verifier_options.h"
8 |
9 | void verifier_options(verifier_params *p, struct option*ops) {
10 |
11 | options_string(ops, "smStats",
12 | &(p->smStats), "",
13 | "Input laser file");
14 |
15 | options_string(ops, "odometry",
16 | (&p->odometry), "",
17 | "Input odometry file ");
18 |
19 | options_string(ops, "calib_params",
20 | &(p->calib_params), "",
21 | "Input file with estimated parameters");
22 |
23 | options_string(ops, "out",
24 | &(p->out), "stdout",
25 | "Output file");
26 |
27 | options_int(ops, "use_gsl",
28 | &(p->use_gsl), 0,
29 | "0: no GSL; 1 use GSL");
30 | }
31 |
--------------------------------------------------------------------------------
/src/verifier_options.h:
--------------------------------------------------------------------------------
1 | /*!
2 | \file verifier_options.h
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Manages options for verifier (header file)
5 | */
6 | #ifndef _VERIFIER_OPTIONS_H
7 | #define _VERIFIER_OPTIONS_H
8 |
9 | /*!
10 | \struct verifier_params
11 | @param sm_stats laser_stats input filename
12 | @param odometry odometry input filename
13 | @param parameters estimated parameters filename
14 | @param out output filename
15 | */
16 | typedef struct {
17 | const char * smStats;
18 | const char * odometry;
19 | const char * calib_params;
20 | const char * out;
21 | int use_gsl;
22 | } verifier_params;
23 |
24 | /*!
25 | Initializes parameters for verifier procedure
26 | \param p pointer to parameters' structure
27 | \param ops options' structure
28 | */
29 | void verifier_options(verifier_params*p, struct option*ops);
30 |
31 | #endif
32 |
33 |
--------------------------------------------------------------------------------
/src/verifier_utils.cpp:
--------------------------------------------------------------------------------
1 | /*!
2 | \file verifier_utils.cpp
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Auxiliary methods for verifier.cpp
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | using namespace std;
12 |
13 | // a, b, result are pointers to array with three elements!
14 | // a(+)b
15 | void planarComp(double * a, double * b, double * result) {
16 | result[0] = a[0] + b[0]*cos(a[2]) - b[1]*sin(a[2]);
17 | result[1] = a[1] + b[0]*sin(a[2]) + b[1]*cos(a[2]);
18 | result[2] = a[2] + b[2];
19 | }
20 |
21 | // a, b, result are pointers to array with three elements!
22 | // a(-)b
23 | void inv_planarComp(double * a, double * b, double * result) {
24 | result[2] = a[2] - b[2];
25 | result[0] = + a[0]*cos(b[2]) + a[1]*sin(b[2]) - b[0]*cos(b[2]) - b[1]*sin(b[2]);
26 | result[1] = - a[0]*sin(b[2]) + a[1]*cos(b[2]) + b[0]*sin(b[2]) - b[1]*cos(b[2]);
27 | }
28 |
29 | void rototras(gsl_matrix * M, double x, double y, double theta){
30 | /* M = [ cos(theta) -sin(theta) 0 x
31 | sin(theta) cos(theta) 0 y
32 | 0 0 1 0
33 | 0 0 0 1 ] */
34 | gsl_matrix_set_zero(M);
35 | gsl_matrix_set(M , 0, 0, cos(theta) );
36 | gsl_matrix_set(M , 0, 1, -sin(theta) );
37 | gsl_matrix_set(M , 0, 2, 0 );
38 | gsl_matrix_set(M , 0, 3, x );
39 | gsl_matrix_set(M , 1, 0, sin(theta) );
40 | gsl_matrix_set(M , 1, 1, cos(theta) );
41 | gsl_matrix_set(M , 1, 2, 0 );
42 | gsl_matrix_set(M , 1, 3, y );
43 | gsl_matrix_set(M , 2, 0, 0 );
44 | gsl_matrix_set(M , 2, 1, 0 );
45 | gsl_matrix_set(M , 2, 2, 1.0 );
46 | gsl_matrix_set(M , 2, 3, 0 );
47 | gsl_matrix_set(M , 3, 0, 0 );
48 | gsl_matrix_set(M , 3, 1, 0 );
49 | gsl_matrix_set(M , 3, 2, 0 );
50 | gsl_matrix_set(M , 3, 3, 1.0 );
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/src/verifier_utils.h:
--------------------------------------------------------------------------------
1 | /*!
2 | \file verifier_utils.h
3 | \author Carlo Masone, Margherita Petrocchi, Lorenzo Rosa
4 | \brief Header of verifier_utils
5 | */
6 |
7 | #include
8 | #include
9 |
10 | #include "aux_functions.h"
11 |
12 | using namespace std;
13 |
14 | /*!
15 | \brief Computate composition of planar transformations
16 | @param a \f$ \left[ \begin{array}{ccc} x & y & \theta \end{array} \right] \f$
17 | @param b \f$ \left[ \begin{array}{ccc} x & y & \theta \end{array} \right] \f$
18 | @param result \f$ a \oplus b \f$ = \f$ \left[ \begin{array}{ccc} x & y & \theta \end{array} \right] \f$
19 | */
20 | void planarComp(double * a, double * b, double * result);
21 |
22 | /*!
23 | \brief Computate inverse composition of planar transformations
24 | @param a \f$ \left[ \begin{array}{ccc} x & y & \theta \end{array} \right] \f$
25 | @param b \f$ \left[ \begin{array}{ccc} x & y & \theta \end{array} \right] \f$
26 | @param result \f$ a \ominus b \f$ = \f$ \left[ \begin{array}{ccc} x & y & \theta \end{array} \right] \f$
27 | */
28 | void inv_planarComp(double * a, double * b, double * result);
29 |
30 | /*!
31 | \brief Computate homogeneus transformation
32 | @param M pointer to gsl_matrix to store result
33 | @param x translation along x axis
34 | @param y translation along y axis
35 | @param theta rotation (z axis)
36 | */
37 | void rototras(gsl_matrix * M, double x, double y, double theta);
38 |
39 |
--------------------------------------------------------------------------------