File: tutorial-json.dox

package info (click to toggle)
visp 3.6.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 119,296 kB
  • sloc: cpp: 500,914; ansic: 52,904; xml: 22,642; python: 7,365; java: 4,247; sh: 482; makefile: 237; objc: 145
file content (260 lines) | stat: -rw-r--r-- 10,616 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/**
  \page tutorial-json Tutorial: Using JSON serialization to save your data and read program arguments
  \tableofcontents

\section tuto-json-intro Introduction

Since ViSP 3.6.0, a 3rd party library was introduced to allow the seamless use of JSON (JavaScript Object Notation) in ViSP.
The library that is used is <a target="_blank" href="https://github.com/nlohmann/json">JSON for modern C++</a>.
To install it on your system, look at \ref soft_tool_json installation instructions for your system.

The main use case for using JSON in your programs is to save your experimental results. The main advantage of using JSON is
that it is widely supported by default in other languages.

Thanks to this 3rd party, JSON serialization was introduced for vpCameraParameters, vpArray2D, vpColVector, vpPoseVector,
vpHomogeneousMatrix, vpMe and vpMbGenericTracker.

In this tutorial, we will use JSON to:
  - Read program arguments from a configuration file. This makes it easier to run your program many times and makes storing
    different configurations easier
  - Save the data generated by running a visual servoing loop
  - Generate plots in Python

\subsection tuto-json-overview JSON overview

First of all, it is necessary to understand the structure of JSON documents to better use them.
For a detailed description, you may be interested in <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON">the Mozilla Developer Network documentation</a>.

Much of this section is a repeat of the library's documentation, available <a target="_blank" href="https://json.nlohmann.me/">here</a>.

To use JSON in your code you should first include the relevant header:
\code{.cpp}
#include <nlohmann/json.hpp>
using json = nlohmann::json; // For convenience
\endcode

This introduces a new type named `json` which supports many types out of the box:
\code{.cpp}
json j = {
  {"bool", false},
  {"double", 3.14156},
  {"string", "Hello World!"},
  {"aVector", {1.0, 2.0, 3.0}}
};
std::cout << j.dump(4) << std::endl;
\endcode
This snippet will print
\verbatim
{
  "aVector": [1.0, 2.0, 3.0],
  "bool": false,
  "double": 3.14156,
  "string": "Hello World!"
}
\endverbatim

\subsection tuto-json-custom-conversion Defining a JSON conversion for your types

The library also allows to define explicit conversion between a custom type and JSON. This can be achieved by defining the two following functions:
\code
void from_json(const json& j, YourType& t);
void to_json(json& j, const YourType& t);
\endcode
These functions must be defined in the same scope namespace as YourType and must be accessible everywhere YourType is used. It is thus common to define it in the header where YourType is defined.
\code
#include <nlohmann/json.hpp>

class YourType {
public:
  YourType(double x): x(x) {}

private:
  double x;
  friend from_json(const json& j, YourType& t);    // Declare friends if you wish to access private members
  friend void to_json(json& j, const YourType& t);
};

inline void from_json(const json& j, YourType& t)
{
  t.x = j.at("x");
}

inline void to_json(json& j, const YourType& t)
{
  j["x"] = t.x;
}
\endcode

Once this conversion is defined you can convert to and from json with:
\code{.cpp}
YourType t(5.0);
json j = t;                         // j == {"x": 5.0}, calls to_json
YourType t2 = j;                    // t2.x == 5.0, calls from_json
j = {YourType(1.0), YourType(2.0)}; // j == [{"x": 1.0}, {"x": 2.0}]
                                    // JSON conversion for std vector is already known and call
                                    // to_json for each of the elements of the vector
\endcode

To better understand the requirements and caveats when writing custom conversions, we encourage
you to read <a href="https://json.nlohmann.me/features/arbitrary_types/#basic-usage" target="_blank">the documentation on arbitrary type conversion</a>.

\section tuto-json-ibvs Example: Using JSON for a visual servoing experiment

This example will demonstrate some basic usage of JSON to save the data generated by running an IBVS and exporting it to python to plot some figures.
This example is a modification tutorial-ibvs-4pts.cpp and the full code is available at tutorial-ibvs-4pts-json.cpp.

This program can be run with:
\verbatim
$ cd $VISP_WS/visp-build/tutorial/visual-servo/ibvs
$ ./tutorial-ibvs-4pts-json --settings ibvs_settings.json --output results.json
\endverbatim

\subsection tuto-json-ibvs-arguments Using JSON for program arguments

We first start by defining the program arguments:

\snippet tutorial-ibvs-4pts-json.cpp Arguments

This struct contains the control law gain, the desired and starting pose, as well as the visual error threshold and robot sampling time.
Finally it contains a value of type `vpInteractionMatrixTypeSubset` which is defined as
\snippet tutorial-ibvs-4pts-json.cpp Enum

This value will be converted to a vpServo::vpServoIteractionMatrixType when defining the control law,
by calling `Arguments::getInteractionMatrixType()`.

Now that our arguments are defined we must now know to parse JSON to get them. We start by defining how to
serialize our enumeration `vpInteractionMatrixTypeSubset`:
\snippet tutorial-ibvs-4pts-json.cpp Enum conversion
Note that if the value is not in `CURRENT`, `DESIRED` or `MEAN`, then the parsing result will default to the value `vpInteractionMatrixTypeSubset::UNKNOWN`.

Next we define how to parse the full list of arguments:
\snippet tutorial-ibvs-4pts-json.cpp Arguments conversion
Where the method `from_json()` is used to parse JSON and, inversely, `to_json()` is used to convert the arguments to JSON, which we will use afterwards.

The syntax
\code
x = j.value("key", x);
\endcode
is used to fill in optional values from the JSON document. If the key is not found then `x` will be left unchanged
This syntax can also be used to set a default value, e.g.:
\code
a.lambda = j.value("lambda", 0.5);
\endcode

In the `from_json()` method, we ensure that all the arguments are correctly set:
  - Lambda should be > 0
  - Sampling time should be > 0
  - Error threshold should be > 0
  - The type of interaction matrix should be correct

With this conversion defined, we can read the program settings from a file (`ibvs_settings.json`), containing
\include ibvs_settings.json

Note that while the `Arguments` class represents the desired and starting poses as vpHomogeneousMatrix elements, they are defined in the JSON as vpPoseVector representations. ViSP will automatically convert one representation to the other when parsing JSON.

To read from the `ibvs_settings.json` file, we will define the following method:

\snippet tutorial-ibvs-4pts-json.cpp JSON input conversion

Which we will call in the `main()`, to finally obtain our program arguments:
\snippet tutorial-ibvs-4pts-json.cpp Main parsing

We can now start servoing and acquiring data, that will be saved to another JSON file.

\subsection tuto-json-ibvs-saving Collecting and saving visual servoing data

To save the data to a JSON file, we first define what we'll save
\snippet tutorial-ibvs-4pts-json.cpp Result structure

This includes:
  - The arguments used to launch the program
  - The desired visual features
  - For each iteration
    - The visual features
    - The camera pose
    - The squared norm of the visual error
    - The velocity
    - The interaction matrix

Before starting the servoing loop we create a `results` object:
\snippet tutorial-ibvs-4pts-json.cpp Results creation
We then start the visual servoing loop:
\snippet tutorial-ibvs-4pts-json.cpp VS loop
where at each iteration, we update our `results` object with
\snippet tutorial-ibvs-4pts-json.cpp Results update

Finally, to save the results to a file, we define a function to write to a file
\snippet tutorial-ibvs-4pts-json.cpp write json to file
and call it at the end of the program
\snippet tutorial-ibvs-4pts-json.cpp Save call

Our data is now saved in a JSON file, and we can reuse it in other programs, as we demonstrate further below.

\subsection tuto-json-ibvs-python Reusing the data in Python to generate plots

We will now reparse the JSON file saved in \ref tuto-json-ibvs-saving section to generate high quality plots
in Python with Matplotlib. The script, `plot-ibvs-control-law.py` can be found in the script folder of the ViSP
git repository. It has been tested with Python 3.7.9, matplotlib 3.3.2 and numpy 1.17.3.

If not already done, to use the script install the following:

- Install the latest [Python3](https://www.python.org/downloads/) release
- Check if `pip3` and `python3` are correctly installed
\verbatim
$ python3 --version
$ pip3 --version
\endverbatim
- Upgrade your pip to avoid errors during installation.
\verbatim
$ pip3 install --upgrade pip
\endverbatim
- Enter the following command to install Numpy using `pip3`
\verbatim
$ pip3 install numpy
\endverbatim
- Enter the following command to install Matplotlib using `pip3`
\verbatim
$ pip3 install matplotlib
\endverbatim

The script gives `plot-ibvs-control-law.py` a reference on how to plot with JSON data coming from ViSP. You may wish to modify
and extend it to fit your use case or control law.

To run the script, replace the json path that contains the data to plot and where you wish to save the
plots in the following command:
\verbatim
$ cd VISP_WS/visp/script
$ python3 plot-ibvs-control-law.py --data $VISP_WS/visp-build/tutorial/visual-servo/ibvs/results.json \
                                   --plot_folder ./plots
\endverbatim

The script should produce similar output:
\verbatim
Generating error norm plot...
Generating velocity plot...
Generating 2D and 3D trajectory plots...
Generating features plot...
Plots were saved to $VISP_WS/visp/script/plots
\endverbatim

You can then view the generated plots in the folder where you saved them (in our case in `./plots/`
corresponding to `$VISP_WS/visp/script/plots` folder).
\verbatim
$ ls $VISP_WS/visp/script/plots
cMo.pdf			  error.pdf		          velocity.pdf
cMo_3d.pdf		trajectories_2d.pdf
\endverbatim

You should obtain plots similar to those below, but with a higher quality (generated in pdf):

\image html image/tutorial/visual-servo/ibvs-python-plots/cMo.jpg
\image html image/tutorial/visual-servo/ibvs-python-plots/cMo_3d.jpg
\image html image/tutorial/visual-servo/ibvs-python-plots/velocity.jpg
\image html image/tutorial/visual-servo/ibvs-python-plots/error.jpg
\image html image/tutorial/visual-servo/ibvs-python-plots/trajectories_2d.jpg

\section tuto-json-next Next tutorial

You are now ready to see how to continue with \ref tutorial-mb-generic-json.

*/