18
18
#include " JointFeatures.hh"
19
19
20
20
#include < algorithm>
21
+ #include < cmath>
22
+ #include < cstddef>
21
23
#include < memory>
22
24
#include < unordered_map>
23
25
@@ -28,6 +30,29 @@ namespace gz {
28
30
namespace physics {
29
31
namespace bullet_featherstone {
30
32
33
+ // ///////////////////////////////////////////////
34
+ void recreateJointLimitConstraint (JointInfo *_jointInfo, ModelInfo *_modelInfo,
35
+ WorldInfo *_worldInfo)
36
+ {
37
+ const auto *identifier = std::get_if<InternalJoint>(&_jointInfo->identifier );
38
+ if (!identifier)
39
+ return ;
40
+
41
+ if (_jointInfo->jointLimits )
42
+ {
43
+ _worldInfo->world ->removeMultiBodyConstraint (_jointInfo->jointLimits .get ());
44
+ _jointInfo->jointLimits .reset ();
45
+ }
46
+
47
+ _jointInfo->jointLimits =
48
+ std::make_shared<btMultiBodyJointLimitConstraint>(
49
+ _modelInfo->body .get (), identifier->indexInBtModel ,
50
+ static_cast <btScalar>(_jointInfo->axisLower ),
51
+ static_cast <btScalar>(_jointInfo->axisUpper ));
52
+
53
+ _worldInfo->world ->addMultiBodyConstraint (_jointInfo->jointLimits .get ());
54
+ }
55
+
31
56
// ///////////////////////////////////////////////
32
57
void makeColliderStatic (LinkInfo *_linkInfo)
33
58
{
@@ -277,8 +302,13 @@ void JointFeatures::SetJointForce(
277
302
return ;
278
303
279
304
const auto *model = this ->ReferenceInterface <ModelInfo>(joint->model );
305
+
306
+ // clamp the values
307
+ double force = std::clamp (_value,
308
+ joint->minEffort , joint->maxEffort );
309
+
280
310
model->body ->getJointTorqueMultiDof (
281
- identifier->indexInBtModel )[_dof] = static_cast <btScalar>(_value );
311
+ identifier->indexInBtModel )[_dof] = static_cast <btScalar>(force );
282
312
model->body ->wakeUp ();
283
313
}
284
314
@@ -409,20 +439,153 @@ void JointFeatures::SetJointVelocityCommand(
409
439
auto modelInfo = this ->ReferenceInterface <ModelInfo>(jointInfo->model );
410
440
if (!jointInfo->motor )
411
441
{
442
+ auto *world = this ->ReferenceInterface <WorldInfo>(modelInfo->world );
443
+ // \todo(iche033) The motor constraint is created with a max impulse
444
+ // computed by maxEffort * stepsize. However, our API supports
445
+ // stepping sim with varying dt. We should recompute max impulse
446
+ // if stepSize changes.
412
447
jointInfo->motor = std::make_shared<btMultiBodyJointMotor>(
413
448
modelInfo->body .get (),
414
449
std::get<InternalJoint>(jointInfo->identifier ).indexInBtModel ,
415
450
0 ,
416
451
static_cast <btScalar>(0 ),
417
- static_cast <btScalar>(jointInfo->effort ));
418
- auto *world = this ->ReferenceInterface <WorldInfo>(modelInfo->world );
452
+ static_cast <btScalar>(jointInfo->maxEffort * world->stepSize ));
419
453
world->world ->addMultiBodyConstraint (jointInfo->motor .get ());
420
454
}
421
455
422
- jointInfo->motor ->setVelocityTarget (static_cast <btScalar>(_value));
456
+ // clamp the values
457
+ double velocity = std::clamp (_value,
458
+ jointInfo->minVelocity , jointInfo->maxVelocity );
459
+
460
+ jointInfo->motor ->setVelocityTarget (static_cast <btScalar>(velocity));
423
461
modelInfo->body ->wakeUp ();
424
462
}
425
463
464
+ // ///////////////////////////////////////////////
465
+ void JointFeatures::SetJointMinPosition (
466
+ const Identity &_id, std::size_t _dof, double _value)
467
+ {
468
+ auto *jointInfo = this ->ReferenceInterface <JointInfo>(_id);
469
+ if (std::isnan (_value))
470
+ {
471
+ gzerr << " Invalid minimum joint position value [" << _value
472
+ << " ] commanded on joint [" << jointInfo->name << " DOF " << _dof
473
+ << " ]. The command will be ignored\n " ;
474
+ return ;
475
+ }
476
+ jointInfo->axisLower = _value;
477
+
478
+ auto *modelInfo = this ->ReferenceInterface <ModelInfo>(jointInfo->model );
479
+ auto *worldInfo = this ->ReferenceInterface <WorldInfo>(modelInfo->world );
480
+ recreateJointLimitConstraint (jointInfo, modelInfo, worldInfo);
481
+ }
482
+
483
+ // ///////////////////////////////////////////////
484
+ void JointFeatures::SetJointMaxPosition (
485
+ const Identity &_id, std::size_t _dof, double _value)
486
+ {
487
+ auto *jointInfo = this ->ReferenceInterface <JointInfo>(_id);
488
+ if (std::isnan (_value))
489
+ {
490
+ gzerr << " Invalid maximum joint position value [" << _value
491
+ << " ] commanded on joint [" << jointInfo->name << " DOF " << _dof
492
+ << " ]. The command will be ignored\n " ;
493
+ return ;
494
+ }
495
+
496
+ jointInfo->axisUpper = _value;
497
+
498
+ auto *modelInfo = this ->ReferenceInterface <ModelInfo>(jointInfo->model );
499
+ auto *worldInfo = this ->ReferenceInterface <WorldInfo>(modelInfo->world );
500
+ recreateJointLimitConstraint (jointInfo, modelInfo, worldInfo);
501
+ }
502
+
503
+ // ///////////////////////////////////////////////
504
+ void JointFeatures::SetJointMinVelocity (
505
+ const Identity &_id, std::size_t _dof, double _value)
506
+ {
507
+ auto *jointInfo = this ->ReferenceInterface <JointInfo>(_id);
508
+ if (std::isnan (_value))
509
+ {
510
+ gzerr << " Invalid minimum joint velocity value [" << _value
511
+ << " ] commanded on joint [" << jointInfo->name << " DOF " << _dof
512
+ << " ]. The command will be ignored\n " ;
513
+ return ;
514
+ }
515
+
516
+ jointInfo->minVelocity = _value;
517
+ }
518
+
519
+ // ///////////////////////////////////////////////
520
+ void JointFeatures::SetJointMaxVelocity (
521
+ const Identity &_id, std::size_t _dof, double _value)
522
+ {
523
+ auto *jointInfo = this ->ReferenceInterface <JointInfo>(_id);
524
+ if (std::isnan (_value))
525
+ {
526
+ gzerr << " Invalid maximum joint velocity value [" << _value
527
+ << " ] commanded on joint [" << jointInfo->name << " DOF " << _dof
528
+ << " ]. The command will be ignored\n " ;
529
+ return ;
530
+ }
531
+
532
+ jointInfo->maxVelocity = _value;
533
+ }
534
+
535
+ // ///////////////////////////////////////////////
536
+ void JointFeatures::SetJointMinEffort (
537
+ const Identity &_id, std::size_t _dof, double _value)
538
+ {
539
+ auto *jointInfo = this ->ReferenceInterface <JointInfo>(_id);
540
+ if (std::isnan (_value))
541
+ {
542
+ gzerr << " Invalid minimum joint effort value [" << _value
543
+ << " ] commanded on joint [" << jointInfo->name << " DOF " << _dof
544
+ << " ]. The command will be ignored\n " ;
545
+
546
+ return ;
547
+ }
548
+
549
+ jointInfo->minEffort = _value;
550
+ }
551
+
552
+ // ///////////////////////////////////////////////
553
+ void JointFeatures::SetJointMaxEffort (
554
+ const Identity &_id, std::size_t _dof, double _value)
555
+ {
556
+ auto *jointInfo = this ->ReferenceInterface <JointInfo>(_id);
557
+ if (std::isnan (_value))
558
+ {
559
+ gzerr << " Invalid maximum joint effort value [" << _value
560
+ << " ] commanded on joint [" << jointInfo->name << " DOF " << _dof
561
+ << " ]. The command will be ignored\n " ;
562
+ return ;
563
+ }
564
+
565
+ const auto *identifier = std::get_if<InternalJoint>(&jointInfo->identifier );
566
+ if (!identifier)
567
+ return ;
568
+
569
+ jointInfo->maxEffort = _value;
570
+
571
+ auto *modelInfo = this ->ReferenceInterface <ModelInfo>(jointInfo->model );
572
+ auto *world = this ->ReferenceInterface <WorldInfo>(modelInfo->world );
573
+
574
+ if (jointInfo->motor )
575
+ {
576
+ world->world ->removeMultiBodyConstraint (jointInfo->motor .get ());
577
+ jointInfo->motor .reset ();
578
+ }
579
+
580
+ jointInfo->motor = std::make_shared<btMultiBodyJointMotor>(
581
+ modelInfo->body .get (),
582
+ std::get<InternalJoint>(jointInfo->identifier ).indexInBtModel ,
583
+ 0 ,
584
+ static_cast <btScalar>(0 ),
585
+ static_cast <btScalar>(jointInfo->maxEffort * world->stepSize ));
586
+ world->world ->addMultiBodyConstraint (jointInfo->motor .get ());
587
+ }
588
+
426
589
// ///////////////////////////////////////////////
427
590
Identity JointFeatures::AttachFixedJoint (
428
591
const Identity &_childID,
0 commit comments