@@ -88,7 +88,7 @@ Device::
88
88
Device ( const std::string& n )
89
89
:Entity(n)
90
90
,state_(6 )
91
- ,vel_controlInit_( false )
91
+ ,sanityCheck_( true )
92
92
,controlInputType_(CONTROL_INPUT_ONE_INTEGRATION)
93
93
,controlSIN( NULL ," Device(" +n+" )::input(double)::control" )
94
94
,attitudeSIN(NULL ," Device(" + n +" )::input(vector3)::attitudeIN" )
@@ -282,6 +282,88 @@ setControlInputType(const std::string& cit)
282
282
sotDEBUG (25 )<<" Unrecognized control input type: " <<cit<<endl;
283
283
}
284
284
285
+ void Device::
286
+ setSanityCheck (const bool & enableCheck)
287
+ {
288
+ if (enableCheck) {
289
+ const Vector::Index& s = state_.size ();
290
+ switch (controlInputType_) {
291
+ case CONTROL_INPUT_TWO_INTEGRATION:
292
+ dgRTLOG ()
293
+ << " Sanity check for this control is not well supported. "
294
+ " In order to make it work, use pinocchio and the contact forces "
295
+ " to estimate the joint torques for the given acceleration.\n " ;
296
+ if ( s != lowerTorque_.size ()
297
+ || s != upperTorque_.size () )
298
+ throw std::invalid_argument (" Upper and/or lower torque bounds "
299
+ " do not match state size. Set them first with setTorqueBounds" );
300
+ case CONTROL_INPUT_ONE_INTEGRATION:
301
+ if ( s != lowerVelocity_.size ()
302
+ || s != upperVelocity_.size () )
303
+ throw std::invalid_argument (" Upper and/or lower velocity bounds "
304
+ " do not match state size. Set them first with setVelocityBounds" );
305
+ case CONTROL_INPUT_NO_INTEGRATION:
306
+ if ( s != lowerPosition_.size ()
307
+ || s != upperPosition_.size () )
308
+ throw std::invalid_argument (" Upper and/or lower position bounds "
309
+ " do not match state size. Set them first with setPositionBounds" );
310
+ break ;
311
+ default :
312
+ throw std::invalid_argument (" Invalid control mode type." );
313
+ }
314
+ }
315
+ sanityCheck_ = enableCheck;
316
+ }
317
+
318
+ void Device::
319
+ setPositionBounds (const Vector& lower, const Vector& upper)
320
+ {
321
+ std::ostringstream oss;
322
+ if (lower.size () != state_.size ()) {
323
+ oss << " Lower bound size should be " << state_.size ();
324
+ throw std::invalid_argument (oss.str ());
325
+ }
326
+ if (upper.size () != state_.size ()) {
327
+ oss << " Upper bound size should be " << state_.size ();
328
+ throw std::invalid_argument (oss.str ());
329
+ }
330
+ lowerPosition_ = lower;
331
+ upperPosition_ = upper;
332
+ }
333
+
334
+ void Device::
335
+ setVelocityBounds (const Vector& lower, const Vector& upper)
336
+ {
337
+ std::ostringstream oss;
338
+ if (lower.size () != velocity_.size ()) {
339
+ oss << " Lower bound size should be " << velocity_.size ();
340
+ throw std::invalid_argument (oss.str ());
341
+ }
342
+ if (upper.size () != velocity_.size ()) {
343
+ oss << " Upper bound size should be " << velocity_.size ();
344
+ throw std::invalid_argument (oss.str ());
345
+ }
346
+ lowerVelocity_ = lower;
347
+ upperVelocity_ = upper;
348
+ }
349
+
350
+ void Device::
351
+ setTorqueBounds (const Vector& lower, const Vector& upper)
352
+ {
353
+ // TODO I think the torque bounds size are state_.size()-6...
354
+ std::ostringstream oss;
355
+ if (lower.size () != state_.size ()) {
356
+ oss << " Lower bound size should be " << state_.size ();
357
+ throw std::invalid_argument (oss.str ());
358
+ }
359
+ if (upper.size () != state_.size ()) {
360
+ oss << " Lower bound size should be " << state_.size ();
361
+ throw std::invalid_argument (oss.str ());
362
+ }
363
+ lowerTorque_ = lower;
364
+ upperTorque_ = upper;
365
+ }
366
+
285
367
void Device::
286
368
increment ( const double & dt )
287
369
{
@@ -371,6 +453,23 @@ increment( const double & dt )
371
453
motorcontrolSOUT .setConstant ( state_ );
372
454
}
373
455
456
+ // Return true if it saturates.
457
+ inline bool
458
+ saturateBounds (double & val, const double & lower, const double & upper)
459
+ {
460
+ assert (lower <= upper);
461
+ if (val < lower) { val = lower; return true ; }
462
+ if (upper < val) { val = upper; return true ; }
463
+ return false ;
464
+ }
465
+
466
+ #define CHECK_BOUNDS (val, lower, upper, what ) \
467
+ for (int i = 0 ; i < val.size(); ++i) { \
468
+ if (saturateBounds (val (i), lower (i), upper (i))) \
469
+ dgRTLOG () << " A robot " what" bound would be violated at DoF " << i << \
470
+ " " << val (i); \
471
+ }
472
+
374
473
void Device::integrate ( const double & dt )
375
474
{
376
475
const Vector & controlIN = controlSIN.accessCopy ();
@@ -379,6 +478,7 @@ void Device::integrate( const double & dt )
379
478
{
380
479
assert (state_.size ()==controlIN.size ()+6 );
381
480
state_.tail (controlIN.size ()) = controlIN;
481
+ CHECK_BOUNDS (state_, lowerPosition_, upperPosition_, " position" );
382
482
return ;
383
483
}
384
484
@@ -391,6 +491,7 @@ void Device::integrate( const double & dt )
391
491
392
492
if (controlInputType_==CONTROL_INPUT_TWO_INTEGRATION)
393
493
{
494
+ // TODO check acceleration
394
495
// Position increment
395
496
vel_control_ = velocity_.tail (controlIN.size ()) + (0.5 *dt)*controlIN;
396
497
// Velocity integration.
@@ -401,12 +502,23 @@ void Device::integrate( const double & dt )
401
502
vel_control_ = controlIN;
402
503
}
403
504
505
+ // Velocity bounds check
506
+ if (sanityCheck_) {
507
+ CHECK_BOUNDS (velocity_, lowerVelocity_, upperVelocity_, " velocity" );
508
+ }
509
+
510
+ // Freeflyer integration
404
511
if (vel_control_.size () == state_.size ()) {
405
512
integrateRollPitchYaw (state_, vel_control_, dt);
406
513
}
407
514
408
515
// Position integration
409
516
state_.tail (controlIN.size ()) += vel_control_ * dt;
517
+
518
+ // Position bounds check
519
+ if (sanityCheck_) {
520
+ CHECK_BOUNDS (state_, lowerPosition_, upperPosition_, " position" );
521
+ }
410
522
}
411
523
412
524
/* --- DISPLAY ------------------------------------------------------------ */
0 commit comments