RcsPySim
A robot control and simulation library
ECBallInTube.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright (c) 2020, Fabio Muratore, Honda Research Institute Europe GmbH, and
3  Technical University of Darmstadt.
4  All rights reserved.
5 
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8  1. Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  2. Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  3. Neither the name of Fabio Muratore, Honda Research Institute Europe GmbH,
14  or Technical University of Darmstadt, nor the names of its contributors may
15  be used to endorse or promote products derived from this software without
16  specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL FABIO MURATORE, HONDA RESEARCH INSTITUTE EUROPE GMBH,
22  OR TECHNICAL UNIVERSITY OF DARMSTADT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  POSSIBILITY OF SUCH DAMAGE.
29 *******************************************************************************/
30 
31 #include "ExperimentConfig.h"
32 #include "action/ActionModelIK.h"
36 #include "observation/OMCombined.h"
40 #include "observation/OMPartial.h"
49 #include "physics/ForceDisturber.h"
51 #include "util/string_format.h"
52 
53 #include <Rcs_macros.h>
54 #include <Rcs_typedef.h>
55 #include <Rcs_Vec3d.h>
56 #include <TaskPosition3D.h>
57 #include <TaskPosition1D.h>
58 #include <TaskVelocity1D.h>
59 #include <TaskPositionForce1D.h>
60 #include <TaskOmega1D.h>
61 #include <TaskEuler3D.h>
62 
63 #ifdef GRAPHICS_AVAILABLE
64 
65 #include <RcsViewer.h>
66 
67 #endif
68 
69 #include <memory>
70 #include <iomanip>
71 
72 namespace Rcs
73 {
75 {
77  {
78  // Setup inner action model
79  RcsBody* leftEffector = RcsGraph_getBodyByName(graph, "Effector_L");
80  RCHECK(leftEffector);
81  RcsBody* rightEffector = RcsGraph_getBodyByName(graph, "Effector_R");
82  RCHECK(rightEffector);
83 
84  // Get reference frames for the position and orientation tasks
85  std::string refFrameType = "world";
86  properties->getProperty(refFrameType, "refFrame");
87  RcsBody* refBody = nullptr;
88  RcsBody* refFrame = nullptr;
89  if (refFrameType == "world") {
90  // Keep nullptr
91  }
92  else if (refFrameType == "table") {
93  RcsBody* table = RcsGraph_getBodyByName(graph, "Table");
94  RCHECK(table);
95  refBody = table;
96  refFrame = table;
97  }
98  else if (refFrameType == "slider") {
99  RcsBody* slider = RcsGraph_getBodyByName(graph, "Slider");
100  RCHECK(slider);
101  refBody = slider;
102  refFrame = slider;
103  }
104  else {
105  std::ostringstream os;
106  os << "Unsupported reference frame type: " << refFrame;
107  throw std::invalid_argument(os.str());
108  }
109 
110  // Get the method how to combine the movement primitives / tasks given their activation
111  std::string taskCombinationMethod = "unspecified";
112  properties->getProperty(taskCombinationMethod, "taskCombinationMethod");
114 
115  std::string actionModelType = "unspecified";
116  properties->getProperty(actionModelType, "actionModelType");
117 
118  if (actionModelType == "ik") {
119  // Create the action model
120  auto amIK = new AMIKGeneric(graph);
121  std::vector<Task*> tasks;
122 
123  if (properties->getPropertyBool("positionTasks", true)) {
124  throw std::invalid_argument("Position tasks are not implemented for AMIKGeneric in this environment.");
125  }
126  else {
127  // Left
128  tasks.emplace_back(new TaskVelocity1D("Xd", graph, leftEffector, refBody, refFrame));
129  tasks.back()->resetParameter(Task::Parameters(-dt, dt, 1.0, "Xd Left [m/s]"));
130  tasks.emplace_back(new TaskVelocity1D("Yd", graph, leftEffector, refBody, refFrame));
131  tasks.back()->resetParameter(Task::Parameters(-dt, dt, 1.0, "Yd Left [m/s]"));
132  tasks.emplace_back(new TaskVelocity1D("Zd", graph, leftEffector, refBody, refFrame));
133  tasks.back()->resetParameter(Task::Parameters(-dt, dt, 1.0, "Zd Left [m/s]"));
134  tasks.emplace_back(new TaskOmega1D("Ad", graph, leftEffector, refBody, refFrame));
135  tasks.back()->resetParameter(Task::Parameters(-dt*M_PI_2, dt*M_PI_2, 1.0, "Ad Left [deg/s]"));
136  tasks.emplace_back(new TaskOmega1D("Bd", graph, leftEffector, refBody, refFrame));
137  tasks.back()->resetParameter(Task::Parameters(-dt*M_PI_2, dt*M_PI_2, 1.0, "Bd Left [deg/s]"));
138  tasks.emplace_back(new TaskOmega1D("Cd", graph, leftEffector, refBody, refFrame));
139  tasks.back()->resetParameter(Task::Parameters(-dt*M_PI_2, dt*M_PI_2, 1.0, "Cd Left [deg/s]"));
140 
141  // Right
142  tasks.emplace_back(new TaskVelocity1D("Xd", graph, rightEffector, refBody, refFrame));
143  tasks.back()->resetParameter(Task::Parameters(-dt, dt, 1.0, "Xd Right [m/s]"));
144  tasks.emplace_back(new TaskVelocity1D("Yd", graph, rightEffector, refBody, refFrame));
145  tasks.back()->resetParameter(Task::Parameters(-dt, dt, 1.0, "Yd Right [m/s]"));
146  tasks.emplace_back(new TaskVelocity1D("Zd", graph, rightEffector, refBody, refFrame));
147  tasks.back()->resetParameter(Task::Parameters(-dt, dt, 1.0, "Zd Right [m/s]"));
148  tasks.emplace_back(new TaskOmega1D("Ad", graph, rightEffector, refBody, refFrame));
149  tasks.back()->resetParameter(Task::Parameters(-dt*M_PI_2, dt*M_PI_2, 1.0, "Ad Right [deg/s]"));
150  tasks.emplace_back(new TaskOmega1D("Bd", graph, rightEffector, refBody, refFrame));
151  tasks.back()->resetParameter(Task::Parameters(-dt*M_PI_2, dt*M_PI_2, 1.0, "Bd Right [deg/s]"));
152  tasks.emplace_back(new TaskOmega1D("Cd", graph, rightEffector, refBody, refFrame));
153  tasks.back()->resetParameter(Task::Parameters(-dt*M_PI_2, dt*M_PI_2, 1.0, "Cd Right [deg/s]"));
154 
155  // Add the tasks
156  for (auto t : tasks) { amIK->addTask(t); }
157 
158  return amIK;
159  }
160  }
161 
162  else if (actionModelType == "ik_activation") {
163  // Create the action model
164  auto amIK = new AMIKControllerActivation(graph, tcm);
165  std::vector<Task*> tasks;
166 
167  if (properties->getPropertyBool("positionTasks", true)) {
168  RcsBody* ball = RcsGraph_getBodyByName(graph, "Ball");
169  RcsBody* table = RcsGraph_getBodyByName(graph, "Table");
170  RcsBody* slider = RcsGraph_getBodyByName(graph, "Slider");
171  RCHECK(ball);
172  RCHECK(table);
173  RCHECK(slider);
174  std::string taskName;
175 
176  // Left
177  auto tl0 = new TaskPosition3D(graph, leftEffector, nullptr, nullptr);
178  taskName = " Position Home [m]";
179  tl0->resetParameter(Task::Parameters(0., 2., 1.0, "X" + taskName));
180  tl0->addParameter(Task::Parameters(-1., 1., 1.0, "Y" + taskName));
181  tl0->addParameter(Task::Parameters(0., 1.7, 1.0, "Z" + taskName));
182  tasks.emplace_back(tl0);
183  auto tl1 = new TaskPosition3D(graph, leftEffector, ball, nullptr);
184  taskName = " Position rel Ball [m]";
185  tl1->resetParameter(Task::Parameters(-2., 2., 1.0, "X" + taskName));
186  tl1->addParameter(Task::Parameters(-1., 1., 1.0, "Y" + taskName));
187  tl1->addParameter(Task::Parameters(
188  -ball->shape[0]->extents[0], 1., 1.0, "Z" + taskName));
189  tasks.emplace_back(tl1);
190 // RCHECK(RcsGraph_getSensorByName(graph, "lbr_joint_7_torque_L"));
191 // auto tl2 = new TaskPositionForce1D("ForceX", graph, leftEffector, ball, nullptr, "lbr_joint_7_torque_L", false);
192 // tasks.emplace_back(tl2);
193  auto tl3 = new TaskEuler3D(graph, leftEffector, table, nullptr);
194  tasks.emplace_back(tl3);
195  // Right
196  auto tr0 = new TaskPosition3D(graph, rightEffector, nullptr, nullptr);
197  taskName = " Position Home [m]";
198  tr0->resetParameter(Task::Parameters(0., 2., 1.0, "X" + taskName));
199  tr0->addParameter(Task::Parameters(-1., 1., 1.0, "Y" + taskName));
200  tr0->addParameter(Task::Parameters(0., 1.7, 1.0, "Z" + taskName));
201  tasks.emplace_back(tr0);
202  auto tr1 = new TaskPosition3D(graph, rightEffector, slider, nullptr);
203  taskName = " Position rel Slider [m]";
204  tr1->resetParameter(Task::Parameters(-2., 2., 1.0, "X" + taskName));
205  tr1->addParameter(Task::Parameters(-1., 1., 1.0, "Y" + taskName));
206  tr1->addParameter(Task::Parameters(-0.5, 1., 1.0, "Z" + taskName));
207  tasks.emplace_back(tr1);
208  auto tr2 = new TaskPosition1D("Y", graph, rightEffector, table, nullptr);
209  tr2->resetParameter(Task::Parameters(-1., 1., 1.0, "Y Position [m]"));
210  tasks.emplace_back(tr2);
211  auto tr3 = new TaskEuler3D(graph, rightEffector, slider, nullptr);
212  tasks.emplace_back(tr3);
213 
214  // Add the tasks
215  for (auto t : tasks) { amIK->addTask(t); }
216 
217  // Set the tasks' desired states
218  std::vector<PropertySource*> taskSpec = properties->getChildList("taskSpecIK");
219  amIK->setXdesFromTaskSpec(taskSpec);
220 
221  // Incorporate collision costs into IK
222  if (properties->getPropertyBool("collisionAvoidanceIK", true)) {
223  REXEC(4) {
224  std::cout << "IK considers the provided collision model" << std::endl;
225  }
226  amIK->setupCollisionModel(collisionMdl);
227  }
228  }
229  else {
230  throw std::invalid_argument("Velocity tasks are not supported for AMIKControllerActivation.");
231  }
232 
233  return amIK;
234  }
235 
236  else if (actionModelType == "ds_activation") {
237  // Initialize action model and tasks
238  std::unique_ptr<AMIKGeneric> innerAM(new AMIKGeneric(graph));
239  std::vector<std::unique_ptr<DynamicalSystem>> tasks;
240 
241  // Control effector positions and orientation
242  if (properties->getPropertyBool("positionTasks", false)) {
243  RcsBody* slider = RcsGraph_getBodyByName(graph, "Slider");
244  RCHECK(slider);
245  // Left
246  innerAM->addTask(new TaskPosition3D(graph, leftEffector, slider, slider));
247  innerAM->addTask(new TaskEuler3D(graph, leftEffector, slider, slider));
248  // Right
249  innerAM->addTask(new TaskPosition3D(graph, rightEffector, slider, slider));
250  innerAM->addTask(new TaskEuler3D(graph, rightEffector, slider, slider));
251 
252  // Obtain task data (depends on the order of the MPs coming from Pyrado)
253  // Left
254  unsigned int i = 0;
255  std::vector<unsigned int> taskDimsLeft{
256  3, 3, 3, 3
257  };
258  std::vector<unsigned int> offsetsLeft{
259  0, 0, 3, 3
260  };
261  auto& tsLeft = properties->getChildList("tasksLeft");
262  for (auto tsk : tsLeft) {
263  DynamicalSystem* ds = DynamicalSystem::create(tsk, taskDimsLeft[i]);
264  tasks.emplace_back(new DSSlice(ds, offsetsLeft[i], taskDimsLeft[i]));
265  i++;
266  }
267  // Right
268  std::vector<unsigned int> taskDimsRight{
269  3, 3, 3, 3
270  };
271  unsigned int oL = offsetsLeft.back() + taskDimsLeft.back();
272  std::vector<unsigned int> offsetsRight{
273  oL, oL, oL + 3, oL + 3
274  };
275  i = 0;
276  auto& tsRight = properties->getChildList("tasksRight");
277  for (auto tsk : tsRight) {
278  DynamicalSystem* ds = DynamicalSystem::create(tsk, taskDimsRight[i]);
279  tasks.emplace_back(new DSSlice(ds, offsetsRight[i], taskDimsRight[i]));
280  i++;
281  }
282  }
283 
284  // Control effector velocity and orientation
285  else {
286  // Left
287  innerAM->addTask(new TaskVelocity1D("Xd", graph, leftEffector, refBody, refFrame));
288  innerAM->addTask(new TaskVelocity1D("Yd", graph, leftEffector, refBody, refFrame));
289  innerAM->addTask(new TaskVelocity1D("Zd", graph, leftEffector, refBody, refFrame));
290  innerAM->addTask(new TaskOmega1D("Ad", graph, leftEffector, refBody, refFrame));
291  innerAM->addTask(new TaskOmega1D("Bd", graph, leftEffector, refBody, refFrame));
292  innerAM->addTask(new TaskOmega1D("Cd", graph, leftEffector, refBody, refFrame));
293  // Right
294  innerAM->addTask(new TaskVelocity1D("Xd", graph, rightEffector, refBody, refFrame));
295  innerAM->addTask(new TaskVelocity1D("Yd", graph, rightEffector, refBody, refFrame));
296  innerAM->addTask(new TaskVelocity1D("Zd", graph, rightEffector, refBody, refFrame));
297  innerAM->addTask(new TaskOmega1D("Ad", graph, rightEffector, refBody, refFrame));
298  innerAM->addTask(new TaskOmega1D("Bd", graph, rightEffector, refBody, refFrame));
299  innerAM->addTask(new TaskOmega1D("Cd", graph, rightEffector, refBody, refFrame));
300 
301  // Obtain task data (depends on the order of the MPs coming from Pyrado)
302  // Left
303  unsigned int i = 0;
304  std::vector<unsigned int> taskDimsLeft{
305  1, 1, 1, 1, 1, 1
306  };
307  std::vector<unsigned int> offsetsLeft{
308  0, 1, 2, 3, 4, 5
309  };
310  auto& tsLeft = properties->getChildList("tasksLeft");
311  for (auto tsk : tsLeft) {
312  DynamicalSystem* ds = DynamicalSystem::create(tsk, taskDimsLeft[i]);
313  tasks.emplace_back(new DSSlice(ds, offsetsLeft[i], taskDimsLeft[i]));
314  i++;
315  }
316  // Right
317  std::vector<unsigned int> taskDimsRight{
318  1, 1, 1, 1, 1, 1
319  };
320  unsigned int oL = offsetsLeft.back() + taskDimsLeft.back();
321  std::vector<unsigned int> offsetsRight{
322  oL, oL + 1, oL + 2, oL + 3, oL + 4, oL + 5
323  };
324  i = 0;
325  auto& tsRight = properties->getChildList("tasksRight");
326  for (auto tsk : tsRight) {
327  DynamicalSystem* ds = DynamicalSystem::create(tsk, taskDimsRight[i]);
328  tasks.emplace_back(new DSSlice(ds, offsetsRight[i], taskDimsRight[i]));
329  i++;
330  }
331  }
332 
333  if (tasks.empty()) {
334  throw std::invalid_argument("No tasks specified!");
335  }
336 
337  // Incorporate collision costs into IK
338  if (properties->getPropertyBool("collisionAvoidanceIK", true)) {
339  std::cout << "IK considers the provided collision model" << std::endl;
340  innerAM->setupCollisionModel(collisionMdl);
341  }
342 
343  // Setup task-based action model
344  std::vector<DynamicalSystem*> taskRel;
345  for (auto& task : tasks) {
346  taskRel.push_back(task.release());
347  }
348 
349  // Create the action model
350  return new AMDynamicalSystemActivation(innerAM.release(), taskRel, tcm);
351  }
352 
353  else {
354  std::ostringstream os;
355  os << "Unsupported action model type: " << actionModelType;
356  throw std::invalid_argument(os.str());
357  }
358  }
359 
361  {
362  // Observe effector positions (and velocities)
363  std::unique_ptr<OMCombined> fullState(new OMCombined());
364 
365  if (properties->getPropertyBool("observeVelocities", true)) {
366  auto omLeftLin = new OMBodyStateLinear(graph, "Effector_L"); // in world coordinates
367  omLeftLin->setMinState({0.2, -1., 0.74}); // [m]
368  omLeftLin->setMaxState({1.8, 1., 1.5}); // [m]
369  omLeftLin->setMaxVelocity(3.); // [m/s]
370  fullState->addPart(omLeftLin);
371 
372  auto omRightLin = new OMBodyStateLinear(graph, "Effector_R"); // in world coordinates
373  omRightLin->setMinState({0.2, -1., 0.74}); // [m]
374  omRightLin->setMaxState({1.8, 1., 1.5}); // [m]
375  omRightLin->setMaxVelocity(3.); // [m/s]
376  fullState->addPart(omRightLin);
377  }
378  else {
379  auto omLeftLin = new OMBodyStateLinearPositions(graph, "Effector_L"); // in world coordinates
380  omLeftLin->setMinState({0.2, -1., 0.74}); // [m]
381  omLeftLin->setMaxState({1.8, 1., 1.5}); // [m]
382  fullState->addPart(omLeftLin);
383 
384  auto omRightLin = new OMBodyStateLinearPositions(graph, "Effector_R"); // in world coordinates
385  omRightLin->setMinState({0.2, -1., 0.74}); // [m]
386  omRightLin->setMaxState({1.8, 1., 1.5}); // [m]
387  fullState->addPart(omRightLin);
388  }
389 
390  // Observe ball positions (and velocities)
391  if (properties->getPropertyBool("observeVelocities", true)) {
392  auto omBallLin = new OMBodyStateLinear(graph, "Ball", nullptr, nullptr); // in world coordinates
393  omBallLin->setMinState({0.6, -1., 0.74}); // [m]
394  omBallLin->setMaxState({1.6, 1., 0.88}); // [m]
395  omBallLin->setMaxVelocity(5.); // [m/s]
396  fullState->addPart(OMPartial::fromMask(omBallLin, {true, true, false})); // only x, y component
397  }
398  else {
399  auto omBallLin = new OMBodyStateLinearPositions(graph, "Ball", nullptr, nullptr); // in world coordinates
400  omBallLin->setMinState({0.6, -1., 0.7}); // [m]
401  omBallLin->setMaxState({1.6, 1., 0.9}); // [m]
402  fullState->addPart(OMPartial::fromMask(omBallLin, {true, true, false})); // only x, y component
403  }
404 
405  // Observe slider position (and velocities)
406  if (properties->getPropertyBool("observeVelocities", true)) {
407  auto omSliderLin = new OMBodyStateLinear(graph, "Slider", nullptr, nullptr); // in world coordinates
408  omSliderLin->setMinState({0.9, -1., 0.7}); // [m]
409  omSliderLin->setMaxState({1.3, 0., 0.9}); // [m]
410  omSliderLin->setMaxVelocity(5.); // [m/s]
411  fullState->addPart(OMPartial::fromMask(omSliderLin, {false, true, false})); // only y component
412  }
413  else {
414  auto omSliderLin = new OMBodyStateLinearPositions(graph, "Slider", nullptr,
415  nullptr); // in world coordinates
416  omSliderLin->setMinState({0.9, -1., 0.7}); // [m]
417  omSliderLin->setMaxState({1.3, 0., 0.9}); // [m]
418  fullState->addPart(OMPartial::fromMask(omSliderLin, {false, true, false})); // only y component
419  }
420 
421  // Add force/torque measurements
422  if (properties->getPropertyBool("observeForceTorque", true)) {
423  RcsSensor* ftsL = RcsGraph_getSensorByName(graph, "WristLoadCellLBR_L");
424  if (ftsL) {
425  auto omForceTorque = new OMForceTorque(graph, ftsL->name, 1200);
426  fullState->addPart(OMPartial::fromMask(omForceTorque, {true, true, true, false, false, false}));
427  }
428  RcsSensor* ftsR = RcsGraph_getSensorByName(graph, "WristLoadCellLBR_R");
429  if (ftsR) {
430  auto omForceTorque = new OMForceTorque(graph, ftsR->name, 1200);
431  fullState->addPart(OMPartial::fromMask(omForceTorque, {true, true, true, false, false, false}));
432  }
433  }
434 
435  // Add current collision cost
436  if (properties->getPropertyBool("observeCollisionCost", true) & (collisionMdl != nullptr)) {
437  // Add the collision cost observation model
438  auto omColl = new OMCollisionCost(collisionMdl);
439  fullState->addPart(omColl);
440  }
441 
442  // Add predicted collision cost
443  if (properties->getPropertyBool("observePredictedCollisionCost", false) & (collisionMdl != nullptr)) {
444  // Get the horizon from config
445  int horizon = 20;
446  properties->getChild("collisionConfig")->getProperty(horizon, "predCollHorizon");
447  // Add the collision cost observation model
448  auto omCollPred = new OMCollisionCostPrediction(graph, collisionMdl, actionModel, horizon);
449  fullState->addPart(omCollPred);
450  }
451 
452  // Add manipulability index
453  auto ikModel = actionModel->unwrap<ActionModelIK>();
454  if (properties->getPropertyBool("observeManipulabilityIndex", false) && ikModel) {
455  bool ocm = properties->getPropertyBool("observeCurrentManipulability", true);
456  fullState->addPart(new OMManipulabilityIndex(ikModel, ocm));
457  }
458 
459  // Add the task space discrepancy observation model
460  if (properties->getPropertyBool("observeTaskSpaceDiscrepancy", true)) {
461  auto wamIK = actionModel->unwrap<ActionModelIK>();
462  if (wamIK) {
463  auto omTSDescrL = new OMTaskSpaceDiscrepancy("Effector_L", graph, wamIK->getController()->getGraph());
464  fullState->addPart(omTSDescrL);
465  auto omTSDescrR = new OMTaskSpaceDiscrepancy("Effector_R", graph, wamIK->getController()->getGraph());
466  fullState->addPart(omTSDescrR);
467  }
468  else {
469  throw std::invalid_argument("The action model needs to be of type ActionModelIK!");
470  }
471  }
472 
473  std::string actionModelType = "unspecified";
474  properties->getProperty(actionModelType, "actionModelType");
475  if (actionModelType == "ds_activation") {
476  // Add goal distances
477  if (properties->getPropertyBool("observeDynamicalSystemGoalDistance", false)) {
479  RCHECK(amAct);
480  fullState->addPart(new OMDynamicalSystemGoalDistance(amAct));
481  }
482 
483  // Add the dynamical system discrepancy observation model
484  if (properties->getPropertyBool("observeDynamicalSystemDiscrepancy", false) & (collisionMdl != nullptr)) {
485  auto castedAM = dynamic_cast<AMDynamicalSystemActivation*>(actionModel);
486  if (castedAM) {
487  auto omDSDescr = new OMDynamicalSystemDiscrepancy(castedAM);
488  fullState->addPart(omDSDescr);
489  }
490  else {
491  throw std::invalid_argument("The action model needs to be of type AMDynamicalSystemActivation!");
492  }
493  }
494  }
495 
496  return fullState.release();
497  }
498 
500  {
501  manager->addParam("Ball", new PPDSphereRadius("Table"));
502  manager->addParam("Ball", new PPDMassProperties());
503  manager->addParam("Ball", new PPDMaterialProperties());
504  manager->addParam("Slider", new PPDMassProperties());
505  }
506 
508  {
509  return new ISSBallInTube(graph, properties->getPropertyBool("fixedInitState", false));
510  }
511 
513  {
514  RcsBody* box = RcsGraph_getBodyByName(graph, "Ball");
515  RCHECK(box);
516  return new ForceDisturber(box, box);
517  }
518 
519  virtual void initViewer(Rcs::Viewer* viewer)
520  {
521 #ifdef GRAPHICS_AVAILABLE
522  // Set camera above plate
523  RcsBody* table = RcsGraph_getBodyByName(graph, "Table");
524  RCHECK(table);
525  std::string cameraView = "egoView";
526  properties->getProperty(cameraView, "egoView");
527 
528  // The camera center is 10cm above the the plate's center
529  double cameraCenter[3];
530  Vec3d_copy(cameraCenter, table->A_BI->org);
531  cameraCenter[0] -= 0.2;
532 
533  // The camera location - not specified yet
534  double cameraLocation[3];
535  Vec3d_setZero(cameraLocation);
536 
537  // Camera up vector defaults to z
538  double cameraUp[3];
539  Vec3d_setUnitVector(cameraUp, 2);
540 
541  if (cameraView == "egoView") {
542  RcsBody* railBot = RcsGraph_getBodyByName(graph, "RailBot");
543  RCHECK(railBot);
544 
545  // Rotate to world frame
546  Vec3d_transformSelf(cameraLocation, table->A_BI);
547 
548  // Move the camera approx where the Kinect would be
549  cameraLocation[0] = railBot->A_BI->org[0] - 0.5;
550  cameraLocation[1] = railBot->A_BI->org[1];
551  cameraLocation[2] = railBot->A_BI->org[2] + 1.5;
552  }
553  else {
554  RMSG("Unsupported camera view: %s", cameraView.c_str());
555  return;
556  }
557 
558  // Apply the camera position
559  viewer->setCameraHomePosition(osg::Vec3d(cameraLocation[0], cameraLocation[1], cameraLocation[2]),
560  osg::Vec3d(cameraCenter[0], cameraCenter[1], cameraCenter[2]),
561  osg::Vec3d(cameraUp[0], cameraUp[1], cameraUp[2]));
562 #endif
563  }
564 
565  void
567  std::vector<std::string>& linesOut,
568  double currentTime, const MatNd* obs,
569  const MatNd* currentAction,
570  PhysicsBase* simulator,
571  PhysicsParameterManager* physicsManager,
572  ForceDisturber* forceDisturber) override
573  {
574  // Obtain simulator name
575  const char* simName = "None";
576  if (simulator != nullptr) {
577  simName = simulator->getClassName();
578  }
579  linesOut.emplace_back(
580  string_format("physics engine: %s sim time: %2.3f s", simName, currentTime));
581 
582  unsigned int numPosCtrlJoints = 0;
583  unsigned int numTrqCtrlJoints = 0;
584  // Iterate over unconstrained joints
585  RCSGRAPH_TRAVERSE_JOINTS(graph) {
586  if (JNT->jacobiIndex != -1) {
587  if (JNT->ctrlType == RCSJOINT_CTRL_TYPE::RCSJOINT_CTRL_POSITION) {
588  numPosCtrlJoints++;
589  }
590  else if (JNT->ctrlType == RCSJOINT_CTRL_TYPE::RCSJOINT_CTRL_TORQUE) {
591  numTrqCtrlJoints++;
592  }
593  }
594  }
595  linesOut.emplace_back(
596  string_format("num joints: %d total, %d pos ctrl, %d trq ctrl", graph->nJ, numPosCtrlJoints,
597  numTrqCtrlJoints));
598 
599  unsigned int sd = observationModel->getStateDim();
600 
601  auto omLeftLin = observationModel->findOffsets<OMBodyStateLinear>(); // there are two, we find the first
602  if (omLeftLin) {
603  linesOut.emplace_back(
604  string_format("left hand pg: [% 1.3f,% 1.3f,% 1.3f] m [% 1.3f,% 1.3f,% 1.3f] m/s",
605  obs->ele[omLeftLin.pos], obs->ele[omLeftLin.pos + 1], obs->ele[omLeftLin.pos + 2],
606  obs->ele[sd + omLeftLin.vel], obs->ele[sd + omLeftLin.vel + 1],
607  obs->ele[sd + omLeftLin.vel + 2]));
608  linesOut.emplace_back(
609  string_format("right hand pg: [% 1.3f,% 1.3f,% 1.3f] m [% 1.3f,% 1.3f,% 1.3f] m/s",
610  obs->ele[omLeftLin.pos + 3], obs->ele[omLeftLin.pos + 4], obs->ele[omLeftLin.pos + 5],
611  obs->ele[sd + omLeftLin.vel + 3], obs->ele[sd + omLeftLin.vel + 4],
612  obs->ele[sd + omLeftLin.vel + 5]));
613  }
614 
615  else if (omLeftLin) {
616  linesOut.emplace_back(
617  string_format("box absolute: [% 1.3f,% 1.3f,% 1.3f] m",
618  obs->ele[omLeftLin.pos + 6], obs->ele[omLeftLin.pos + 7], obs->ele[omLeftLin.pos + 8]));
619  }
620 
621  auto omFTS = observationModel->findOffsets<OMForceTorque>();
622  if (omFTS) {
623  linesOut.emplace_back(
624  string_format("forces left: [% 3.1f, % 3.1f, % 3.1f] N right: [% 3.1f, % 3.1f, % 3.1f] N",
625  obs->ele[omFTS.pos], obs->ele[omFTS.pos + 1], obs->ele[omFTS.pos + 2],
626  obs->ele[omFTS.pos + 3], obs->ele[omFTS.pos + 4], obs->ele[omFTS.pos + 5]));
627  }
628 
629  auto omColl = observationModel->findOffsets<OMCollisionCost>();
631  if (omColl && omCollPred) {
632  linesOut.emplace_back(
633  string_format("coll cost: %3.2f pred coll cost: %3.2f",
634  obs->ele[omColl.pos], obs->ele[omCollPred.pos]));
635 
636  }
637  else if (omColl) {
638  linesOut.emplace_back(string_format("coll cost: %3.2f", obs->ele[omColl.pos]));
639  }
640  else if (omCollPred) {
641  linesOut.emplace_back(string_format("pred coll cost: %3.2f", obs->ele[omCollPred.pos]));
642  }
643 
645  if (omMI) {
646  linesOut.emplace_back(string_format("manip idx: %1.3f", obs->ele[omMI.pos]));
647  }
648 
650  if (omGD) {
651  if (properties->getPropertyBool("positionTasks", false)) {
652  linesOut.emplace_back(
653  string_format("goal distance: [% 1.2f,% 1.2f,% 1.2f,% 1.2f,% 1.2f,\n"
654  " % 1.2f,% 1.2f,% 1.2f,% 1.2f,% 1.2f,% 1.2f]",
655  obs->ele[omGD.pos], obs->ele[omGD.pos + 1], obs->ele[omGD.pos + 2],
656  obs->ele[omGD.pos + 3], obs->ele[omGD.pos + 4],
657  obs->ele[omGD.pos + 5], obs->ele[omGD.pos + 6], obs->ele[omGD.pos + 7],
658  obs->ele[omGD.pos + 8], obs->ele[omGD.pos + 9], obs->ele[omGD.pos + 10]));
659  }
660  }
661 
663  if (omTSD) {
664  linesOut.emplace_back(
665  string_format("ts delta: [% 1.3f,% 1.3f,% 1.3f] m",
666  obs->ele[omTSD.pos], obs->ele[omTSD.pos + 1], obs->ele[omTSD.pos + 2]));
667  }
668 
669  std::stringstream ss;
670  ss << "actions: [";
671  for (unsigned int i = 0; i < currentAction->m - 1; i++) {
672  ss << std::fixed << std::setprecision(2) << MatNd_get(currentAction, i, 0) << ", ";
673  if (i == 6) {
674  ss << "\n ";
675  }
676  }
677  ss << std::fixed << std::setprecision(2) << MatNd_get(currentAction, currentAction->m - 1, 0) << "]";
678  linesOut.emplace_back(string_format(ss.str()));
679 
680  if (physicsManager != nullptr) {
681  // Get the parameters that are not stored in the Rcs graph
682  BodyParamInfo* ball_bpi = physicsManager->getBodyInfo("Ball");
683  double* com = ball_bpi->body->Inertia->org;
684  double ball_radius = ball_bpi->body->shape[0]->extents[0];
685  double slip = 0;
686  ball_bpi->material.getDouble("slip", slip);
687 
688  linesOut.emplace_back(string_format(
689  "ball mass: %2.2f kg ball radius: %2.3f cm",
690  ball_bpi->body->m, ball_radius*100));
691 
692  linesOut.emplace_back(string_format(
693  "ball friction: %1.2f ball rolling friction: %1.3f",
694  ball_bpi->material.getFrictionCoefficient(),
695  ball_bpi->material.getRollingFrictionCoefficient()/ball_radius));
696 
697  linesOut.emplace_back(string_format(
698  "ball slip: %3.1f rad/(Ns) CoM offset:[% 2.1f, % 2.1f, % 2.1f] mm",
699  slip, com[0]*1000, com[1]*1000, com[2]*1000));
700  }
701  }
702 
703 };
704 
705 // Register
707 
708 }
virtual bool getProperty(std::string &out, const char *property)=0
virtual bool getPropertyBool(const char *property, bool def=false)=0
virtual void initViewer(Rcs::Viewer *viewer)
RcsBody * body
The body.
Definition: BodyParamInfo.h:64
virtual PropertySource * getChild(const char *prefix)=0
void addParam(const char *bodyName, PhysicsParameterDescriptor *desc)
double dt
The time step [s].
static TaskCombinationMethod checkTaskCombinationMethod(std::string tcmName)
TaskCombinationMethod
Definition: ActionModel.h:46
virtual InitStateSetter * createInitStateSetter()
virtual ActionModel * createActionModel()
virtual const std::vector< PropertySource * > & getChildList(const char *prefix)=0
virtual unsigned int getStateDim() const =0
void getHUDText(std::vector< std::string > &linesOut, double currentTime, const MatNd *obs, const MatNd *currentAction, PhysicsBase *simulator, PhysicsParameterManager *physicsManager, ForceDisturber *forceDisturber) override
BodyParamInfo * getBodyInfo(const char *bodyName)
static DynamicalSystem * create(PropertySource *properties, unsigned int innerTaskDim)
static OMPartial * fromMask(ObservationModel *wrapped, const std::vector< bool > &mask, bool exclude=false)
Definition: OMPartial.cpp:116
std::string string_format(const std::string &format, Args ... args)
Definition: string_format.h:45
virtual ForceDisturber * createForceDisturber()
ObservationModel * observationModel
Observation model (pluggable) used to create the observation which will be returned from step() ...
PropertySource * properties
Property source (owned)
const AM * unwrap() const
Definition: ActionModel.h:142
static ExperimentConfigRegistration< ECBallInTube > RegBallInTube("BallInTube")
virtual ObservationModel * createObservationModel()
ActionModel * actionModel
Action model (pluggable)
RcsCollisionMdl * collisionMdl
Collision model to use. Is based on the graph, so take care when using with IK etc.
PhysicsMaterial material
Material of the body&#39;s first shape.
Definition: BodyParamInfo.h:70
virtual void populatePhysicsParameters(PhysicsParameterManager *manager)
RcsGraph * graph
Graph description.