1 |
|
|
/* |
2 |
|
|
* Copyright 2016, |
3 |
|
|
* |
4 |
|
|
* Olivier Stasse |
5 |
|
|
* Rohan Budhiraja |
6 |
|
|
* |
7 |
|
|
* LAAS, CNRS |
8 |
|
|
* |
9 |
|
|
* This file is part of TalosController. |
10 |
|
|
* TALOSController is a free software, |
11 |
|
|
* |
12 |
|
|
*/ |
13 |
|
|
|
14 |
|
|
#include <fstream> |
15 |
|
|
#include <map> |
16 |
|
|
|
17 |
|
|
#if DEBUG |
18 |
|
|
#define ODEBUG(x) std::cout << x << std::endl |
19 |
|
|
#else |
20 |
|
|
#define ODEBUG(x) |
21 |
|
|
#endif |
22 |
|
|
#define ODEBUG3(x) std::cout << x << std::endl |
23 |
|
|
|
24 |
|
|
#define DBGFILE "/tmp/sot-talos-device.txt" |
25 |
|
|
|
26 |
|
|
#if 0 |
27 |
|
|
#define RESETDEBUG5() \ |
28 |
|
|
{ \ |
29 |
|
|
std::ofstream DebugFile; \ |
30 |
|
|
DebugFile.open(DBGFILE, std::ofstream::out); \ |
31 |
|
|
DebugFile.close(); \ |
32 |
|
|
} |
33 |
|
|
#define ODEBUG5FULL(x) \ |
34 |
|
|
{ \ |
35 |
|
|
std::ofstream DebugFile; \ |
36 |
|
|
DebugFile.open(DBGFILE, std::ofstream::app); \ |
37 |
|
|
DebugFile << __FILE__ << ":" << __FUNCTION__ << "(#" << __LINE__ \ |
38 |
|
|
<< "):" << x << std::endl; \ |
39 |
|
|
DebugFile.close(); \ |
40 |
|
|
} |
41 |
|
|
#define ODEBUG5(x) \ |
42 |
|
|
{ \ |
43 |
|
|
std::ofstream DebugFile; \ |
44 |
|
|
DebugFile.open(DBGFILE, std::ofstream::app); \ |
45 |
|
|
DebugFile << x << std::endl; \ |
46 |
|
|
DebugFile.close(); \ |
47 |
|
|
} |
48 |
|
|
|
49 |
|
|
#else |
50 |
|
|
// Void the macro |
51 |
|
|
#define RESETDEBUG5() |
52 |
|
|
#define ODEBUG5FULL(x) |
53 |
|
|
#define ODEBUG5(x) |
54 |
|
|
#endif |
55 |
|
|
|
56 |
|
|
#include <dynamic-graph/all-commands.h> |
57 |
|
|
#include <dynamic-graph/factory.h> |
58 |
|
|
|
59 |
|
|
#include <sot/core/debug.hh> |
60 |
|
|
|
61 |
|
|
#include "sot-talos-device.hh" |
62 |
|
|
|
63 |
|
|
using namespace std; |
64 |
|
|
|
65 |
|
|
const double SoTTalosDevice::TIMESTEP_DEFAULT = 0.001; |
66 |
|
|
|
67 |
|
|
DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(SoTTalosDevice, "DeviceTalos"); |
68 |
|
|
|
69 |
|
|
SoTTalosDevice::SoTTalosDevice(std::string RobotName) |
70 |
|
|
: dgsot::Device(RobotName), |
71 |
|
|
previousState_(), |
72 |
|
|
baseff_(), |
73 |
|
|
accelerometerSOUT_("Device(" + RobotName + |
74 |
|
|
")::output(vector)::accelerometer"), |
75 |
|
|
gyrometerSOUT_("Device(" + RobotName + ")::output(vector)::gyrometer"), |
76 |
|
|
currentsSOUT_("Device(" + RobotName + ")::output(vector)::currents"), |
77 |
|
|
joint_anglesSOUT_("Device(" + RobotName + |
78 |
|
|
")::output(vector)::joint_angles"), |
79 |
|
|
motor_anglesSOUT_("Device(" + RobotName + |
80 |
|
|
")::output(vector)::motor_angles"), |
81 |
|
|
p_gainsSOUT_("Device(" + RobotName + ")::output(vector)::p_gains"), |
82 |
|
|
d_gainsSOUT_("Device(" + RobotName + ")::output(vector)::d_gains"), |
83 |
|
|
dgforces_(6), |
84 |
|
|
accelerometer_(3), |
85 |
|
|
gyrometer_(3) { |
86 |
|
|
RESETDEBUG5(); |
87 |
|
|
timestep_ = TIMESTEP_DEFAULT; |
88 |
|
|
sotDEBUGIN(25); |
89 |
|
|
|
90 |
|
|
for (int i = 0; i < 4; ++i) { |
91 |
|
|
withForceSignals[i] = true; |
92 |
|
|
} |
93 |
|
|
signalRegistration(accelerometerSOUT_ |
94 |
|
|
<< gyrometerSOUT_ << currentsSOUT_ << joint_anglesSOUT_ |
95 |
|
|
<< motor_anglesSOUT_ << p_gainsSOUT_ << d_gainsSOUT_); |
96 |
|
|
dg::Vector data(3); |
97 |
|
|
data.setZero(); |
98 |
|
|
accelerometerSOUT_.setConstant(data); |
99 |
|
|
gyrometerSOUT_.setConstant(data); |
100 |
|
|
baseff_.resize(7); |
101 |
|
|
dg::Vector dataForces(6); |
102 |
|
|
dataForces.setZero(); |
103 |
|
|
for (int i = 0; i < 4; i++) forcesSOUT[i]->setConstant(dataForces); |
104 |
|
|
|
105 |
|
|
using namespace dynamicgraph::command; |
106 |
|
|
std::string docstring; |
107 |
|
|
/* Command increment. */ |
108 |
|
|
docstring = |
109 |
|
|
"\n" |
110 |
|
|
" Integrate dynamics for time step provided as input\n" |
111 |
|
|
"\n" |
112 |
|
|
" take one floating point number as input\n" |
113 |
|
|
"\n"; |
114 |
|
|
addCommand("increment", |
115 |
|
|
makeCommandVoid1((Device&)*this, &Device::increment, docstring)); |
116 |
|
|
|
117 |
|
|
sotDEBUGOUT(25); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
SoTTalosDevice::~SoTTalosDevice() {} |
121 |
|
|
|
122 |
|
|
void SoTTalosDevice::setSensorsForce( |
123 |
|
|
map<string, dgsot::SensorValues>& SensorsIn, int t) { |
124 |
|
|
int map_sot_2_urdf[4] = {2, 0, 3, 1}; |
125 |
|
|
sotDEBUGIN(15); |
126 |
|
|
map<string, dgsot::SensorValues>::iterator it; |
127 |
|
|
it = SensorsIn.find("forces"); |
128 |
|
|
if (it != SensorsIn.end()) { |
129 |
|
|
// Implements force recollection. |
130 |
|
|
const vector<double>& forcesIn = it->second.getValues(); |
131 |
|
|
for (int i = 0; i < 4; ++i) { |
132 |
|
|
sotDEBUG(15) << "Force sensor " << i << std::endl; |
133 |
|
|
int idx_sensor = map_sot_2_urdf[i]; |
134 |
|
|
for (int j = 0; j < 6; ++j) { |
135 |
|
|
dgforces_(j) = forcesIn[idx_sensor * 6 + j]; |
136 |
|
|
sotDEBUG(15) << "Force value " << j << ":" << dgforces_(j) << std::endl; |
137 |
|
|
} |
138 |
|
|
forcesSOUT[i]->setConstant(dgforces_); |
139 |
|
|
forcesSOUT[i]->setTime(t); |
140 |
|
|
} |
141 |
|
|
} |
142 |
|
|
sotDEBUGIN(15); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
void SoTTalosDevice::setSensorsIMU(map<string, dgsot::SensorValues>& SensorsIn, |
146 |
|
|
int t) { |
147 |
|
|
map<string, dgsot::SensorValues>::iterator it; |
148 |
|
|
// TODO: Confirm if this can be made quaternion |
149 |
|
|
it = SensorsIn.find("attitude"); |
150 |
|
|
if (it != SensorsIn.end()) { |
151 |
|
|
const vector<double>& attitude = it->second.getValues(); |
152 |
|
|
for (unsigned int i = 0; i < 3; ++i) |
153 |
|
|
for (unsigned int j = 0; j < 3; ++j) pose(i, j) = attitude[i * 3 + j]; |
154 |
|
|
attitudeSOUT.setConstant(pose); |
155 |
|
|
attitudeSOUT.setTime(t); |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
it = SensorsIn.find("accelerometer_0"); |
159 |
|
|
if (it != SensorsIn.end()) { |
160 |
|
|
const vector<double>& accelerometer = |
161 |
|
|
SensorsIn["accelerometer_0"].getValues(); |
162 |
|
|
for (std::size_t i = 0; i < 3; ++i) accelerometer_(i) = accelerometer[i]; |
163 |
|
|
accelerometerSOUT_.setConstant(accelerometer_); |
164 |
|
|
accelerometerSOUT_.setTime(t); |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
it = SensorsIn.find("gyrometer_0"); |
168 |
|
|
if (it != SensorsIn.end()) { |
169 |
|
|
const vector<double>& gyrometer = SensorsIn["gyrometer_0"].getValues(); |
170 |
|
|
for (std::size_t i = 0; i < 3; ++i) gyrometer_(i) = gyrometer[i]; |
171 |
|
|
gyrometerSOUT_.setConstant(gyrometer_); |
172 |
|
|
gyrometerSOUT_.setTime(t); |
173 |
|
|
} |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
void SoTTalosDevice::setSensorsEncoders( |
177 |
|
|
map<string, dgsot::SensorValues>& SensorsIn, int t) { |
178 |
|
|
map<string, dgsot::SensorValues>::iterator it; |
179 |
|
|
|
180 |
|
|
it = SensorsIn.find("motor-angles"); |
181 |
|
|
if (it != SensorsIn.end()) { |
182 |
|
|
const vector<double>& anglesIn = it->second.getValues(); |
183 |
|
|
dgRobotState_.resize(anglesIn.size() + 6); |
184 |
|
|
motor_angles_.resize(anglesIn.size()); |
185 |
|
|
for (unsigned i = 0; i < 6; ++i) dgRobotState_(i) = 0.; |
186 |
|
|
for (unsigned i = 0; i < anglesIn.size(); ++i) { |
187 |
|
|
dgRobotState_(i + 6) = anglesIn[i]; |
188 |
|
|
motor_angles_(i) = anglesIn[i]; |
189 |
|
|
} |
190 |
|
|
robotState_.setConstant(dgRobotState_); |
191 |
|
|
robotState_.setTime(t); |
192 |
|
|
motor_anglesSOUT_.setConstant(motor_angles_); |
193 |
|
|
motor_anglesSOUT_.setTime(t); |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
it = SensorsIn.find("joint-angles"); |
197 |
|
|
if (it != SensorsIn.end()) { |
198 |
|
|
const vector<double>& joint_anglesIn = it->second.getValues(); |
199 |
|
|
joint_angles_.resize(joint_anglesIn.size()); |
200 |
|
|
for (unsigned i = 0; i < joint_anglesIn.size(); ++i) |
201 |
|
|
joint_angles_(i) = joint_anglesIn[i]; |
202 |
|
|
joint_anglesSOUT_.setConstant(joint_angles_); |
203 |
|
|
joint_anglesSOUT_.setTime(t); |
204 |
|
|
} |
205 |
|
|
} |
206 |
|
|
|
207 |
|
|
void SoTTalosDevice::setSensorsVelocities( |
208 |
|
|
map<string, dgsot::SensorValues>& SensorsIn, int t) { |
209 |
|
|
map<string, dgsot::SensorValues>::iterator it; |
210 |
|
|
|
211 |
|
|
it = SensorsIn.find("velocities"); |
212 |
|
|
if (it != SensorsIn.end()) { |
213 |
|
|
const vector<double>& velocitiesIn = it->second.getValues(); |
214 |
|
|
dgRobotVelocity_.resize(velocitiesIn.size() + 6); |
215 |
|
|
for (unsigned i = 0; i < 6; ++i) dgRobotVelocity_(i) = 0.; |
216 |
|
|
for (unsigned i = 0; i < velocitiesIn.size(); ++i) { |
217 |
|
|
dgRobotVelocity_(i + 6) = velocitiesIn[i]; |
218 |
|
|
} |
219 |
|
|
robotVelocity_.setConstant(dgRobotVelocity_); |
220 |
|
|
robotVelocity_.setTime(t); |
221 |
|
|
} |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
void SoTTalosDevice::setSensorsTorquesCurrents( |
225 |
|
|
map<string, dgsot::SensorValues>& SensorsIn, int t) { |
226 |
|
|
map<string, dgsot::SensorValues>::iterator it; |
227 |
|
|
it = SensorsIn.find("torques"); |
228 |
|
|
if (it != SensorsIn.end()) { |
229 |
|
|
const std::vector<double>& torques = SensorsIn["torques"].getValues(); |
230 |
|
|
torques_.resize(torques.size()); |
231 |
|
|
for (std::size_t i = 0; i < torques.size(); ++i) torques_(i) = torques[i]; |
232 |
|
|
pseudoTorqueSOUT.setConstant(torques_); |
233 |
|
|
pseudoTorqueSOUT.setTime(t); |
234 |
|
|
} |
235 |
|
|
|
236 |
|
|
it = SensorsIn.find("currents"); |
237 |
|
|
if (it != SensorsIn.end()) { |
238 |
|
|
const std::vector<double>& currents = SensorsIn["currents"].getValues(); |
239 |
|
|
currents_.resize(currents.size()); |
240 |
|
|
for (std::size_t i = 0; i < currents.size(); ++i) |
241 |
|
|
currents_(i) = currents[i]; |
242 |
|
|
currentsSOUT_.setConstant(currents_); |
243 |
|
|
currentsSOUT_.setTime(t); |
244 |
|
|
} |
245 |
|
|
} |
246 |
|
|
|
247 |
|
|
void SoTTalosDevice::setSensorsGains( |
248 |
|
|
map<string, dgsot::SensorValues>& SensorsIn, int t) { |
249 |
|
|
map<string, dgsot::SensorValues>::iterator it; |
250 |
|
|
it = SensorsIn.find("p_gains"); |
251 |
|
|
if (it != SensorsIn.end()) { |
252 |
|
|
const std::vector<double>& p_gains = SensorsIn["p_gains"].getValues(); |
253 |
|
|
p_gains_.resize(p_gains.size()); |
254 |
|
|
for (std::size_t i = 0; i < p_gains.size(); ++i) p_gains_(i) = p_gains[i]; |
255 |
|
|
p_gainsSOUT_.setConstant(p_gains_); |
256 |
|
|
p_gainsSOUT_.setTime(t); |
257 |
|
|
} |
258 |
|
|
|
259 |
|
|
it = SensorsIn.find("d_gains"); |
260 |
|
|
if (it != SensorsIn.end()) { |
261 |
|
|
const std::vector<double>& d_gains = SensorsIn["d_gains"].getValues(); |
262 |
|
|
d_gains_.resize(d_gains.size()); |
263 |
|
|
for (std::size_t i = 0; i < d_gains.size(); ++i) d_gains_(i) = d_gains[i]; |
264 |
|
|
d_gainsSOUT_.setConstant(d_gains_); |
265 |
|
|
d_gainsSOUT_.setTime(t); |
266 |
|
|
} |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
void SoTTalosDevice::setSensors(map<string, dgsot::SensorValues>& SensorsIn) { |
270 |
|
|
sotDEBUGIN(25); |
271 |
|
|
map<string, dgsot::SensorValues>::iterator it; |
272 |
|
|
int t = stateSOUT.getTime() + 1; |
273 |
|
|
|
274 |
|
|
setSensorsForce(SensorsIn, t); |
275 |
|
|
setSensorsIMU(SensorsIn, t); |
276 |
|
|
setSensorsEncoders(SensorsIn, t); |
277 |
|
|
setSensorsVelocities(SensorsIn, t); |
278 |
|
|
setSensorsTorquesCurrents(SensorsIn, t); |
279 |
|
|
setSensorsGains(SensorsIn, t); |
280 |
|
|
|
281 |
|
|
sotDEBUGOUT(25); |
282 |
|
|
} |
283 |
|
|
|
284 |
|
|
void SoTTalosDevice::setupSetSensors( |
285 |
|
|
map<string, dgsot::SensorValues>& SensorsIn) { |
286 |
|
|
// The first time we read the sensors, we need to copy the state of the |
287 |
|
|
// robot into the signal device.state. |
288 |
|
|
setSensors(SensorsIn); |
289 |
|
|
setState(robotState_(0)); |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
void SoTTalosDevice::nominalSetSensors( |
293 |
|
|
map<string, dgsot::SensorValues>& SensorsIn) { |
294 |
|
|
setSensors(SensorsIn); |
295 |
|
|
} |
296 |
|
|
|
297 |
|
|
void SoTTalosDevice::cleanupSetSensors( |
298 |
|
|
map<string, dgsot::SensorValues>& SensorsIn) { |
299 |
|
|
setSensors(SensorsIn); |
300 |
|
|
} |
301 |
|
|
|
302 |
|
|
void SoTTalosDevice::getControl(map<string, dgsot::ControlValues>& controlOut) { |
303 |
|
|
|
304 |
|
|
ODEBUG5FULL("start"); |
305 |
|
|
sotDEBUGIN(25); |
306 |
|
|
vector<double> anglesOut, velocityOut; |
307 |
|
|
anglesOut.resize(state_.size()); |
308 |
|
|
velocityOut.resize(state_.size()); |
309 |
|
|
|
310 |
|
|
// Integrate control |
311 |
|
|
increment(timestep_); |
312 |
|
|
sotDEBUG(25) << "state = " << state_ << std::endl; |
313 |
|
|
sotDEBUG(25) << "diff = " |
314 |
|
|
<< ((previousState_.size() == state_.size()) |
315 |
|
|
? (state_ - previousState_) |
316 |
|
|
: state_) |
317 |
|
|
<< std::endl; |
318 |
|
|
ODEBUG5FULL("state = " << state_); |
319 |
|
|
ODEBUG5FULL("diff = " << ((previousState_.size() == state_.size()) |
320 |
|
|
? (state_ - previousState_) |
321 |
|
|
: state_)); |
322 |
|
|
previousState_ = state_; |
323 |
|
|
|
324 |
|
|
// Specify the joint values for the controller. |
325 |
|
|
// warning: we make here the asumption that the control signal contains the |
326 |
|
|
// velocity of the freeflyer joint. This may change in the future. |
327 |
|
|
if ((int)anglesOut.size() != state_.size() - 6){ |
328 |
|
|
anglesOut.resize(state_.size() - 6); |
329 |
|
|
velocityOut.resize(state_.size() - 6); |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
int time = controlSIN.getTime(); |
333 |
|
|
for (unsigned int i = 6; i < state_.size(); ++i){ |
334 |
|
|
anglesOut[i - 6] = state_(i); |
335 |
|
|
velocityOut[i-6] = controlSIN(time)(i); |
336 |
|
|
} |
337 |
|
|
// Store in "control" the joint values |
338 |
|
|
controlOut["control"].setValues(anglesOut); |
339 |
|
|
// Store in "velocity" the joint velocity values |
340 |
|
|
controlOut["velocity"].setValues(velocityOut); |
341 |
|
|
// Read zmp reference from input signal if plugged |
342 |
|
|
zmpSIN.recompute(time + 1); |
343 |
|
|
// Express ZMP in free flyer reference frame |
344 |
|
|
dg::Vector zmpGlobal(4); |
345 |
|
|
for (unsigned int i = 0; i < 3; ++i) zmpGlobal(i) = zmpSIN(time + 1)(i); |
346 |
|
|
zmpGlobal(3) = 1.; |
347 |
|
|
dgsot::MatrixHomogeneous inversePose; |
348 |
|
|
|
349 |
|
|
inversePose = freeFlyerPose().inverse(Eigen::Affine); |
350 |
|
|
dg::Vector localZmp(4); |
351 |
|
|
localZmp = inversePose.matrix() * zmpGlobal; |
352 |
|
|
vector<double> ZMPRef(3); |
353 |
|
|
for (unsigned int i = 0; i < 3; ++i) ZMPRef[i] = localZmp(i); |
354 |
|
|
|
355 |
|
|
controlOut["zmp"].setName("zmp"); |
356 |
|
|
controlOut["zmp"].setValues(ZMPRef); |
357 |
|
|
|
358 |
|
|
// Update position of freeflyer in global frame |
359 |
|
|
Eigen::Vector3d transq_(freeFlyerPose().translation()); |
360 |
|
|
dg::sot::VectorQuaternion qt_(freeFlyerPose().linear()); |
361 |
|
|
|
362 |
|
|
// translation |
363 |
|
|
for (int i = 0; i < 3; i++) baseff_[i] = transq_(i); |
364 |
|
|
|
365 |
|
|
// rotation: quaternion |
366 |
|
|
baseff_[3] = qt_.w(); |
367 |
|
|
baseff_[4] = qt_.x(); |
368 |
|
|
baseff_[5] = qt_.y(); |
369 |
|
|
baseff_[6] = qt_.z(); |
370 |
|
|
|
371 |
|
|
controlOut["baseff"].setValues(baseff_); |
372 |
|
|
ODEBUG5FULL("end"); |
373 |
|
|
sotDEBUGOUT(25); |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
using namespace dynamicgraph::sot; |
377 |
|
|
|
378 |
|
|
namespace dynamicgraph { |
379 |
|
|
namespace sot { |
380 |
|
|
#ifdef WIN32 |
381 |
|
|
const char* DebugTrace::DEBUG_FILENAME_DEFAULT = "c:/tmp/sot-core-traces.txt"; |
382 |
|
|
#else // WIN32 |
383 |
|
|
const char* DebugTrace::DEBUG_FILENAME_DEFAULT = "/tmp/sot-core-traces.txt"; |
384 |
|
|
#endif // WIN32 |
385 |
|
|
|
386 |
|
|
#ifdef VP_DEBUG |
387 |
|
|
#ifdef WIN32 |
388 |
|
|
std::ofstream debugfile("C:/tmp/sot-core-traces.txt", |
389 |
|
|
std::ios::trunc& std::ios::out); |
390 |
|
|
#else // WIN32 |
391 |
|
|
std::ofstream debugfile("/tmp/sot-core-traces.txt", |
392 |
|
|
std::ios::trunc& std::ios::out); |
393 |
|
|
#endif // WIN32 |
394 |
|
|
#else // VP_DEBUG |
395 |
|
|
|
396 |
|
|
std::ofstream debugfile; |
397 |
|
|
|
398 |
|
|
#endif // VP_DEBUG |
399 |
|
|
|
400 |
|
|
} /* namespace sot */ |
401 |
|
|
} /* namespace dynamicgraph */ |