GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/** |
||
2 |
* @file device.cpp |
||
3 |
* @author Maximilien Naveau (maximilien.naveau@gmail.com) |
||
4 |
* @license License BSD-3-Clause |
||
5 |
* @copyright Copyright (c) 2019, New York University and Max Planck Gesellschaft. |
||
6 |
* @date 2019-05-22 |
||
7 |
*/ |
||
8 |
|||
9 |
#include <iostream> |
||
10 |
|||
11 |
#include "yaml_cpp_catkin/yaml_eigen.h" |
||
12 |
|||
13 |
#include <dynamic-graph/factory.h> |
||
14 |
#include <dynamic-graph/all-commands.h> |
||
15 |
#include <dynamic-graph/linear-algebra.h> |
||
16 |
#include <dynamic-graph/debug.h> |
||
17 |
|||
18 |
#include <dynamic_graph_manager/device.hh> |
||
19 |
|||
20 |
using namespace std; |
||
21 |
using namespace dynamic_graph; |
||
22 |
|||
23 |
/** |
||
24 |
* @brief str2int used in the switch case, it allows to convert in compile time |
||
25 |
* strings to int |
||
26 |
* @param str is the string to convert |
||
27 |
* @param h is the index of the string to start with |
||
28 |
* @return an integer that correspond to the string |
||
29 |
*/ |
||
30 |
constexpr unsigned int str2int(const char* str, int h = 0) |
||
31 |
{ |
||
32 |
return !str[h] ? |
||
33 |
5381 : (str2int(str, h+1) * 33) ^ static_cast<unsigned int>(str[h]); |
||
34 |
} |
||
35 |
|||
36 |
/** |
||
37 |
* @brief dynamic_graph::Device::CLASS_NAME must be the name as the actual |
||
38 |
* device class. |
||
39 |
*/ |
||
40 |
✓✗✓✗ ✓✗✗✗ |
4 |
DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(Device, "Device"); |
41 |
|||
42 |
20 |
Device::Device(const std::string& input_name): |
|
43 |
// Call the mother class constructor |
||
44 |
✓✗✓✗ |
20 |
Entity(input_name) |
45 |
{ |
||
46 |
/******************************************* |
||
47 |
* Initilize the command upon construction. * |
||
48 |
********************************************/ |
||
49 |
// I am not sure why bu this as to take place in the constructor |
||
50 |
|||
51 |
// Handle commands and signals called in a synchronous way |
||
52 |
✓✗✓✗ |
20 |
periodic_call_before_.addSpecificCommands(*this, commandMap, "before."); |
53 |
✓✗✓✗ |
20 |
periodic_call_after_.addSpecificCommands(*this, commandMap, "after."); |
54 |
|||
55 |
// Add a initialize command to parametrize the device from a yaml file |
||
56 |
✓✗ | 60 |
addCommand ( |
57 |
"initialize", |
||
58 |
✓✗ | 20 |
dynamicgraph::command::makeCommandVoid1( |
59 |
*this, |
||
60 |
&Device::initialize_from_file, |
||
61 |
✓✗✓✗ ✓✗ |
40 |
dynamicgraph::command::docCommandVoid1( |
62 |
"Initialize the device from a YAML file.", |
||
63 |
✓✗ | 20 |
"string (valid path to the yaml configuration file)"))); |
64 |
|||
65 |
✓✗ | 60 |
addCommand ( |
66 |
"executeGraph", |
||
67 |
✓✗ | 20 |
dynamicgraph::command::makeCommandVoid0( |
68 |
*this, |
||
69 |
&Device::execute_graph_deprecated, |
||
70 |
✓✗✓✗ |
40 |
dynamicgraph::command::docCommandVoid0( |
71 |
✓✗ | 20 |
"Deprecated Execute the current control graph using the currentsensor signals."))); |
72 |
|||
73 |
✓✗ | 60 |
addCommand ( |
74 |
"execute_graph", |
||
75 |
✓✗ | 20 |
dynamicgraph::command::makeCommandVoid0( |
76 |
*this, |
||
77 |
&Device::execute_graph, |
||
78 |
✓✗✓✗ |
40 |
dynamicgraph::command::docCommandVoid0( |
79 |
✓✗ | 20 |
"Execute the current control graph using the currentsensor signals."))); |
80 |
20 |
} |
|
81 |
|||
82 |
void Device::initialize_from_file(const std::string& yaml_file) |
||
83 |
{ |
||
84 |
YAML::Node params = YAML::LoadFile(yaml_file); |
||
85 |
initialize(params["device"]); |
||
86 |
} |
||
87 |
|||
88 |
18 |
void Device::initialize(const YAML::Node& params) |
|
89 |
{ |
||
90 |
18 |
params_ = params; |
|
91 |
/********************************************** |
||
92 |
* create maps for signals and vector<double> * |
||
93 |
**********************************************/ |
||
94 |
18 |
initialize_maps(params_); |
|
95 |
|||
96 |
/****************************** |
||
97 |
* registering sensor signals * |
||
98 |
******************************/ |
||
99 |
✓✓ | 222 |
for (DeviceOutSignalMap::iterator sig_it = sensors_out_.begin(); |
100 |
148 |
sig_it != sensors_out_.end(); ++sig_it) |
|
101 |
{ |
||
102 |
✓✗✓✗ |
56 |
signalRegistration(*(sig_it->second)); |
103 |
} |
||
104 |
|||
105 |
/******************************* |
||
106 |
* registering control signals * |
||
107 |
*******************************/ |
||
108 |
✓✓ | 138 |
for (DeviceInSignalMap::iterator sig_it = motor_controls_in_.begin(); |
109 |
92 |
sig_it != motor_controls_in_.end(); ++sig_it) |
|
110 |
{ |
||
111 |
✓✗✓✗ |
28 |
signalRegistration(*(sig_it->second)); |
112 |
} |
||
113 |
18 |
} |
|
114 |
|||
115 |
53 |
Device::~Device() |
|
116 |
{ |
||
117 |
// destruct the sensor signals |
||
118 |
✓✓ | 264 |
for(DeviceOutSignalMap::iterator it = sensors_out_.begin() ; |
119 |
176 |
it != sensors_out_.end() ; ++it) |
|
120 |
{ |
||
121 |
✓✗ | 68 |
if(it->second != nullptr) |
122 |
{ |
||
123 |
✓✗ | 68 |
delete it->second; |
124 |
68 |
it->second = nullptr; |
|
125 |
} |
||
126 |
} |
||
127 |
// destruct the motor controls signals |
||
128 |
✓✓ | 162 |
for(DeviceInSignalMap::iterator it = motor_controls_in_.begin() ; |
129 |
108 |
it != motor_controls_in_.end() ; ++it) |
|
130 |
{ |
||
131 |
✓✗ | 34 |
if(it->second != nullptr) |
132 |
{ |
||
133 |
✓✗ | 34 |
delete it->second; |
134 |
34 |
it->second = nullptr; |
|
135 |
} |
||
136 |
} |
||
137 |
|||
138 |
20 |
this->entityDeregistration(); |
|
139 |
✗✓ | 33 |
} |
140 |
|||
141 |
21 |
void Device::initialize_maps(const YAML::Node& sensors_and_controls) |
|
142 |
{ |
||
143 |
/************************************************************** |
||
144 |
* Parsing the YAML node and fill in the Eigen::VectosXd maps * |
||
145 |
**************************************************************/ |
||
146 |
✓✗ | 21 |
parse_yaml_node(sensors_and_controls, sensors_map_, motor_controls_map_); |
147 |
|||
148 |
✓✗ | 42 |
std::string hardware_name (""); |
149 |
|||
150 |
/******************************* |
||
151 |
* We iterate over the sensors * |
||
152 |
*******************************/ |
||
153 |
21 |
sensors_out_.clear(); |
|
154 |
✓✓ | 267 |
for (VectorDGMap::const_iterator sensor_it = sensors_map_.begin(); |
155 |
178 |
sensor_it != sensors_map_.end(); ++sensor_it) |
|
156 |
{ |
||
157 |
{ |
||
158 |
✓✗ | 68 |
hardware_name = sensor_it->first; |
159 |
✓✗ | 136 |
ostringstream sig_name; |
160 |
✓✗✓✗ ✓✗ |
68 |
sig_name << "Device(" << this->name << ")::" |
161 |
✓✗✓✗ ✓✗✓✗ |
136 |
<< "output(vector" << sensor_it->second.size() << "d)::" |
162 |
✓✗ | 68 |
<< hardware_name ; |
163 |
✓✗✓✗ ✓✗✓✗ |
68 |
sensors_out_[hardware_name] = new OutSignal(sig_name.str()); |
164 |
✓✗✓✗ ✓✗ |
68 |
sensors_out_[hardware_name]->setConstant(sensors_map_[hardware_name]); |
165 |
} |
||
166 |
} |
||
167 |
|||
168 |
/******************************** |
||
169 |
* We iterate over the controls * |
||
170 |
********************************/ |
||
171 |
✓✓ | 165 |
for (VectorDGMap::const_iterator control_it = motor_controls_map_.begin(); |
172 |
110 |
control_it != motor_controls_map_.end(); ++control_it) |
|
173 |
{ |
||
174 |
{ |
||
175 |
✓✗ | 34 |
hardware_name = control_it->first; |
176 |
✓✗ | 68 |
ostringstream sig_name; |
177 |
✓✗✓✗ ✓✗ |
34 |
sig_name << "Device(" << this->name << ")::" |
178 |
✓✗✓✗ ✓✗✓✗ |
68 |
<< "input(vector" << control_it->second.size() << "d)::" |
179 |
✓✗ | 34 |
<< hardware_name ; |
180 |
✓✗ | 34 |
motor_controls_in_[hardware_name] = |
181 |
✓✗✓✗ ✓✗ |
68 |
new InSignal(nullptr, sig_name.str()); |
182 |
✓✗ | 34 |
motor_controls_in_[hardware_name]->setConstant( |
183 |
✓✗✓✗ |
34 |
motor_controls_map_[hardware_name]); |
184 |
} |
||
185 |
} |
||
186 |
21 |
} |
|
187 |
|||
188 |
2 |
void Device::set_sensors_from_map(const VectorDGMap& sensors) |
|
189 |
{ |
||
190 |
// check that all map has the same size |
||
191 |
✗✓ | 4 |
assert(sensors.size() == sensors_map_.size() && |
192 |
sensors_map_.size() == sensors_out_.size() && |
||
193 |
✓✗ | 2 |
"Device::set_sensors_from_map: All maps has to be the same size"); |
194 |
// we do a copy of the map while checking for sanity |
||
195 |
✓✓ | 30 |
for(VectorDGMap::const_iterator ext_sensor_it = sensors.begin(); |
196 |
20 |
ext_sensor_it != sensors.end(); ++ext_sensor_it) |
|
197 |
{ |
||
198 |
✓✗ | 8 |
assert(sensors_map_.count(ext_sensor_it->first) && |
199 |
"Device::set_sensors_from_map: All field in the input sensors map" |
||
200 |
✗✓ | 8 |
" exists in the internal copy"); |
201 |
✓✗✓✗ ✓✗ |
8 |
assert(static_cast<unsigned>(ext_sensor_it->second.size()) == |
202 |
sensors_map_[ext_sensor_it->first].size() && |
||
203 |
"Device::set_sensors_from_map: the vectors have the same size in the" |
||
204 |
✗✓ | 8 |
" maps"); |
205 |
✓✗✓✗ |
8 |
sensors_map_[ext_sensor_it->first] = ext_sensor_it->second; |
206 |
✓✗✓✗ |
8 |
sensors_out_[ext_sensor_it->first]->setConstant(ext_sensor_it->second); |
207 |
} |
||
208 |
2 |
} |
|
209 |
|||
210 |
2 |
void Device::execute_graph() |
|
211 |
{ |
||
212 |
/******************************************* |
||
213 |
* Get the time of the last sensor reading * |
||
214 |
*******************************************/ |
||
215 |
✗✓ | 2 |
assert(sensors_out_.size() != 0 && "There exist some sensors."); |
216 |
// Here the time is the maximum time of all sensors. |
||
217 |
✓✗ | 2 |
int local_time = sensors_out_.begin()->second->getTime(); |
218 |
✓✓ | 30 |
for(DeviceOutSignalMap::const_iterator sig_out_it = sensors_out_.begin() ; |
219 |
20 |
sig_out_it != sensors_out_.end() ; ++sig_out_it) |
|
220 |
{ |
||
221 |
✓✗ | 8 |
int sig_time = sig_out_it->second->getTime(); |
222 |
✗✓ | 8 |
if(sig_time > local_time) |
223 |
{ |
||
224 |
local_time = sig_time; |
||
225 |
} |
||
226 |
} |
||
227 |
|||
228 |
/****************************************************************** |
||
229 |
* Run Synchronous commands and evaluate signals outside the main * |
||
230 |
* connected component of the graph. * |
||
231 |
******************************************************************/ |
||
232 |
try |
||
233 |
{ |
||
234 |
✓✗✗✗ ✗ |
2 |
periodic_call_before_.run(local_time+1); |
235 |
} |
||
236 |
catch (std::exception& e) |
||
237 |
{ |
||
238 |
std::cerr |
||
239 |
<< "exception caught while running periodical commands (before): " |
||
240 |
<< e.what () << std::endl; |
||
241 |
} |
||
242 |
catch (const char* str) |
||
243 |
{ |
||
244 |
std::cerr |
||
245 |
<< "exception caught while running periodical commands (before): " |
||
246 |
<< str << std::endl; |
||
247 |
} |
||
248 |
catch (...) |
||
249 |
{ |
||
250 |
std::cerr |
||
251 |
<< "unknown exception caught while" |
||
252 |
<< " running periodical commands (before)" << std::endl; |
||
253 |
} |
||
254 |
|||
255 |
/*********************************************************************** |
||
256 |
* Run the graph by accessing the values of the signals inside the map * |
||
257 |
***********************************************************************/ |
||
258 |
✓✓ | 18 |
for(DeviceInSignalMap::const_iterator sig_in_it = motor_controls_in_.begin() ; |
259 |
12 |
sig_in_it != motor_controls_in_.end() ; ++sig_in_it) |
|
260 |
{ |
||
261 |
✓✗ | 4 |
sig_in_it->second->recompute(local_time+1); |
262 |
} |
||
263 |
|||
264 |
/****************************************************************** |
||
265 |
* Run Synchronous commands and evaluate signals outside the main * |
||
266 |
* connected component of the graph. * |
||
267 |
******************************************************************/ |
||
268 |
try |
||
269 |
{ |
||
270 |
// TODO: "time" or "time + 1" |
||
271 |
✓✗✗✗ ✗ |
2 |
periodic_call_after_.run(local_time+1); |
272 |
} |
||
273 |
catch (std::exception& e) |
||
274 |
{ |
||
275 |
std::cerr |
||
276 |
<< "exception caught while running periodical commands (after): " |
||
277 |
<< e.what () << std::endl; |
||
278 |
} |
||
279 |
catch (const char* str) |
||
280 |
{ |
||
281 |
std::cerr |
||
282 |
<< "exception caught while running periodical commands (after): " |
||
283 |
<< str << std::endl; |
||
284 |
} |
||
285 |
catch (...) |
||
286 |
{ |
||
287 |
std::cerr |
||
288 |
<< "unknown exception caught while" |
||
289 |
<< " running periodical commands (after)" << std::endl; |
||
290 |
} |
||
291 |
2 |
} |
|
292 |
|||
293 |
2 |
void Device::get_controls_to_map(VectorDGMap& motor_controls) |
|
294 |
{ |
||
295 |
// check that all map has the same size |
||
296 |
✗✓ | 4 |
assert(motor_controls.size() == motor_controls_map_.size() && |
297 |
motor_controls_map_.size() == motor_controls_in_.size() && |
||
298 |
✓✗ | 2 |
"Device::get_controls_to_map: All maps has to be the same size"); |
299 |
// we do a copy of the map while checking for sanity |
||
300 |
✓✓ | 18 |
for(VectorDGMap::iterator ext_control_it = motor_controls.begin(); |
301 |
12 |
ext_control_it != motor_controls.end(); ++ext_control_it) |
|
302 |
{ |
||
303 |
✓✗ | 4 |
assert(motor_controls_map_.count(ext_control_it->first) && |
304 |
"Device::get_controls_to_map: All field in the input sensors map " |
||
305 |
✗✓ | 4 |
"exists in the internal copy"); |
306 |
✓✗✓✗ ✓✗ |
4 |
assert(static_cast<unsigned>(ext_control_it->second.size()) == |
307 |
motor_controls_map_[ext_control_it->first].size() && |
||
308 |
"Device::get_controls_to_map: the vectors have the same size in the " |
||
309 |
✗✓ | 4 |
"maps"); |
310 |
|||
311 |
✓✗ | 8 |
motor_controls_map_[ext_control_it->first] = |
312 |
✓✗✓✗ ✓✗ |
12 |
motor_controls_in_[ext_control_it->first]->accessCopy(); |
313 |
✓✗✓✗ |
4 |
ext_control_it->second = motor_controls_map_[ext_control_it->first]; |
314 |
} |
||
315 |
✓✗✓✗ |
14 |
} |
Generated by: GCOVR (Version 4.2) |