RcsPySim
A robot control and simulation library
ECMiniGolf.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"
34 #include "initState/ISSMiniGolf.h"
37 #include "observation/OMCombined.h"
40 #include "observation/OMPartial.h"
48 #include "util/string_format.h"
49 
50 #include <Rcs_Mat3d.h>
51 #include <Rcs_Vec3d.h>
52 #include <Rcs_typedef.h>
53 #include <Rcs_macros.h>
54 #include <TaskDistance1D.h>
55 #include <TaskEuler1D.h>
56 #include <TaskFactory.h>
57 #include <TaskPosition1D.h>
58 #include <TaskVelocity1D.h>
59 
60 #ifdef GRAPHICS_AVAILABLE
61 
62 #include <RcsViewer.h>
63 
64 #endif
65 
66 #include <sstream>
67 #include <iomanip>
68 #include <stdexcept>
69 #include <cmath>
70 
71 namespace Rcs
72 {
73 
75 {
76 
78  {
79  std::string actionModelType = "unspecified";
80  properties->getProperty(actionModelType, "actionModelType");
81 
82  // Common for the action models
83  RcsBody* ground = RcsGraph_getBodyByName(graph, "Ground");
84  RCHECK(ground);
85  RcsBody* club = RcsGraph_getBodyByName(graph, "Club");
86  RCHECK(club);
87  RcsBody* clubTip = RcsGraph_getBodyByName(graph, "ClubTip");
88  RCHECK(clubTip);
89  RcsBody* ball = RcsGraph_getBodyByName(graph, "Ball");
90  RCHECK(ball);
91 
92  if (actionModelType == "joint_pos") {
93  return new AMJointControlPosition(graph);
94  }
95 
96  else if (actionModelType == "ik") {
97  // Create the action model. Every but the x tasks have been fixed tasks originally, but now are constant
98  // outputs on the policy. This way, we can use the same policy structure in the pre-strike ControlPolicy
99  // on the real robot.
100  auto amIK = new AMIKGeneric(graph);
101  if (properties->getPropertyBool("positionTasks", true)) {
102  if (properties->getPropertyBool("relativeZdTask", true)) {
103  // Driving
104  auto tmpTask = new TaskVelocity1D("Zd", graph, ball, clubTip, nullptr);
105  tmpTask->resetParameter(Task::Parameters(-100.0, 100.0, 1.0, "Z Velocity [m/s]"));
106  amIK->addTask(tmpTask);
107  // Centering
108  amIK->addTask(new TaskPosition1D("Y", graph, ball, clubTip, nullptr));
109  amIK->addTask(new TaskDistance1D(graph, club, ground, 2));
110  amIK->addTask(TaskFactory::createTask(
111  R"(<Task name="ClubTip_Polar" controlVariable="POLAR" effector="ClubTip" active="true" />)",
112  graph)
113  );
114  }
115  else {
116  // Driving
117  amIK->addTask(new TaskPosition1D("X", graph, clubTip, nullptr, nullptr));
118  // Centering
119 // amIK->addTask(new TaskPosition1D("X", graph, ball, clubTip, nullptr));
120  amIK->addTask(new TaskPosition1D("Y", graph, ball, clubTip, nullptr));
121  amIK->addTask(new TaskDistance1D(graph, club, ground, 2));
122  amIK->addTask(TaskFactory::createTask(
123  R"(<Task name="ClubTip_Polar" controlVariable="POLAR" effector="ClubTip" active="true" />)",
124  graph)
125  );
126  /*
127  amIK->addTask(new TaskPosition1D("X", graph, clubTip, refBody, refFrame));
128  amIK->addTask(new TaskPosition1D("Y", graph, ball, clubTip, ground));
129  amIK->addTask(new TaskDistance1D(graph, club, ground, 2));
130  amIK->addTask(new TaskEuler1D("C", graph, clubTip, nullptr, ground));
131  */
132  }
133  }
134 
135  else {
136  throw std::invalid_argument("Velocity tasks are not implemented for AMIKGeneric in this environment.");
137  }
138 
139  // Incorporate collision costs into IK
140  if (properties->getPropertyBool("collisionAvoidanceIK", false)) {
141  REXEC(4) {
142  std::cout << "IK considers the provided collision model" << std::endl;
143  }
144  amIK->setupCollisionModel(collisionMdl);
145  }
146 
147  return amIK;
148  }
149 
150  else {
151  std::ostringstream os;
152  os << "Unsupported action model type: " << actionModelType;
153  throw std::invalid_argument(os.str());
154  }
155  }
156 
158  {
159  auto fullState = new OMCombined();
160 
161  // Observe the ball
162  if (properties->getPropertyBool("observeVelocities", false)) {
163  auto omLinBall = new OMBodyStateLinear(graph, "Ball", nullptr);
164  omLinBall->setMinState({-5, -5, 0}); // [m]
165  omLinBall->setMaxState({3, 3, 0.1}); // [m]
166  omLinBall->setMaxVelocity(10); // [m/s]
167  fullState->addPart(omLinBall);
168  }
169  else {
170  auto omLinBall = new OMBodyStateLinearPositions(graph, "Ball", nullptr);
171  omLinBall->setMinState({-3, -3, 0}); // [m]
172  omLinBall->setMaxState({3, 3, 0.1}); // [m]
173  fullState->addPart(omLinBall);
174  }
175 
176  // Observe the club
177  if (properties->getPropertyBool("observeVelocities", false)) {
178  auto omLinClub = new OMBodyStateLinear(graph, "ClubTip", nullptr);
179  omLinClub->setMinState({-3, -3, 0}); // [m]
180  omLinClub->setMaxState({3, 3, 2}); // [m]
181  omLinClub->setMaxVelocity(5); // [m/s]
182  fullState->addPart(omLinClub);
183  }
184  else {
185  auto omLinClub = new OMBodyStateLinearPositions(graph, "ClubTip", nullptr);
186  omLinClub->setMinState({-3, -3, 0}); // [m]
187  omLinClub->setMaxState({3, 3, 2}); // [m]
188  fullState->addPart(omLinClub);
189  }
190 
191  // Observe the club
192  if (properties->getPropertyBool("observeVelocities", false)) {
193  auto omAng = new OMBodyStateAngular(graph, "ClubTip", nullptr);
194  omAng->setMaxVelocity(20); // [rad/s]
195  fullState->addPart(omAng);
196  }
197  else {
198  auto omAng = new OMBodyStateAngularPositions(graph, "ClubTip", nullptr);
199  fullState->addPart(omAng);
200  }
201 
202  // Observe the robot's joints
203  std::list<std::string> listOfJointNames = {"base-m3", "m3-m4", "m4-m5", "m5-m6", "m6-m7", "m7-m8", "m8-m9"};
204  for (std::string jointName : listOfJointNames) {
205  fullState->addPart(new OMJointStatePositions(graph, jointName.c_str(), false));
206  }
207 
208  std::string actionModelType = "unspecified";
209  properties->getProperty(actionModelType, "actionModelType");
210 
211  // Add force/torque measurements
212  if (properties->getPropertyBool("observeForceTorque", false)) {
213  RcsSensor* fts = RcsGraph_getSensorByName(graph, "WristLoadCellSchunk");
214  if (fts) {
215  auto omForceTorque = new OMForceTorque(graph, fts->name, 1000);
216  fullState->addPart(OMPartial::fromMask(omForceTorque, {true, true, true, false, false, false}));
217  }
218  }
219 
220  return fullState;
221  }
222 
224  {
225  manager->addParam("Ball", new PPDSphereRadius("Ground"));
226  manager->addParam("Ball", new PPDMassProperties());
227  manager->addParam("Ball", new PPDMaterialProperties());
228  manager->addParam("Club", new PPDMassProperties());
229  manager->addParam("Ground", new PPDMaterialProperties());
230  manager->addParam("ObstacleLeft", new PPDBodyPosition(true, true, false));
231  manager->addParam("ObstacleLeft", new PPDBodyOrientation(false, false, true));
232  manager->addParam("ObstacleRight", new PPDBodyPosition(true, true, false));
233  manager->addParam("ObstacleRight", new PPDBodyOrientation(false, false, true));
234  }
235 
237  {
238  return new ISSMiniGolf(graph, properties->getPropertyBool("fixedInitState", false));
239  }
240 
241  virtual void initViewer(Rcs::Viewer* viewer)
242  {
243 #ifdef GRAPHICS_AVAILABLE
244  // Set the camera center
245  double cameraCenter[3];
246  cameraCenter[0] = 1.5;
247  cameraCenter[1] = 0.5;
248  cameraCenter[2] = 0.0;
249 
250  // Set the camera position
251  double cameraLocation[3];
252  cameraLocation[0] = -1.5;
253  cameraLocation[1] = 4.5;
254  cameraLocation[2] = 2.8;
255 
256  // Camera up vector defaults to z
257  double cameraUp[3];
258  Vec3d_setUnitVector(cameraUp, 2);
259 
260  // Apply camera position
261  viewer->setCameraHomePosition(osg::Vec3d(cameraLocation[0], cameraLocation[1], cameraLocation[2]),
262  osg::Vec3d(cameraCenter[0], cameraCenter[1], cameraCenter[2]),
263  osg::Vec3d(cameraUp[0], cameraUp[1], cameraUp[2]));
264 #endif
265  }
266 
267  void
269  std::vector<std::string>& linesOut, double currentTime, const MatNd* obs, const MatNd* currentAction,
270  PhysicsBase* simulator, PhysicsParameterManager* physicsManager, ForceDisturber* forceDisturber) override
271  {
272  // Obtain simulator name
273  const char* simName;
274  if (simulator != nullptr) {
275  simName = simulator->getClassName();
276  }
277  else {
278  simName = "Robot";
279  }
280 
281  linesOut.emplace_back(
282  string_format("physics engine: %s sim time: %2.3f s", simName, currentTime));
283 
284  unsigned int numPosCtrlJoints = 0;
285  unsigned int numTrqCtrlJoints = 0;
286  // Iterate over unconstrained joints
287  RCSGRAPH_TRAVERSE_JOINTS(graph) {
288  if (JNT->jacobiIndex != -1) {
289  if (JNT->ctrlType == RCSJOINT_CTRL_TYPE::RCSJOINT_CTRL_POSITION) {
290  numPosCtrlJoints++;
291  }
292  else if (JNT->ctrlType == RCSJOINT_CTRL_TYPE::RCSJOINT_CTRL_TORQUE) {
293  numTrqCtrlJoints++;
294  }
295  }
296  }
297  linesOut.emplace_back(
298  string_format("num joints: %d total, %d pos ctrl, %d trq ctrl", graph->nJ, numPosCtrlJoints,
299  numTrqCtrlJoints));
300 
301 // unsigned int sd = observationModel->getStateDim();
302 
303  auto omLinBall = observationModel->findOffsets<OMBodyStateLinear>(); // finds the first OMBodyStateLinear
304  if (omLinBall) {
305  linesOut.emplace_back(string_format("ball pos: [% 1.3f,% 1.3f,% 1.3f] m",
306  obs->ele[omLinBall.pos],
307  obs->ele[omLinBall.pos + 1],
308  obs->ele[omLinBall.pos + 2]));
309  linesOut.emplace_back(string_format("club tip pos: [% 1.3f,% 1.3f,% 1.3f] m",
310  obs->ele[omLinBall.pos + 3],
311  obs->ele[omLinBall.pos + 4],
312  obs->ele[omLinBall.pos + 5]));
313  }
314 
316  if (omAng) {
317  linesOut.emplace_back(string_format("club tip ang: [% 1.3f,% 1.3f,% 1.3f] deg",
318  RCS_RAD2DEG(obs->ele[omAng.pos]),
319  RCS_RAD2DEG(obs->ele[omAng.pos + 1]),
320  RCS_RAD2DEG(obs->ele[omAng.pos + 2])));
321  }
322 
324  if (omFT) {
325  linesOut.emplace_back(
326  string_format("forces: [% 3.1f,% 3.1f,% 3.1f] N",
327  obs->ele[omFT.pos], obs->ele[omFT.pos + 1], obs->ele[omFT.pos + 2]));
328  }
329 
330  std::stringstream ss;
331  ss << "actions: [";
332  for (unsigned int i = 0; i < currentAction->m - 1; i++) {
333  ss << std::fixed << std::setprecision(3) << MatNd_get(currentAction, i, 0) << ", ";
334  if (i == 6) {
335  ss << "\n ";
336  }
337  }
338  ss << std::fixed << std::setprecision(3) << MatNd_get(currentAction, currentAction->m - 1, 0) << "]";
339  linesOut.emplace_back(string_format(ss.str()));
340 
341  if (physicsManager != nullptr) {
342  // Get the parameters that are not stored in the Rcs graph
343  BodyParamInfo* ball_bpi = physicsManager->getBodyInfo("Ball");
344  BodyParamInfo* club_bpi = physicsManager->getBodyInfo("Club");
345  BodyParamInfo* ground_bpi = physicsManager->getBodyInfo("Ground");
346 
347  double ballSlip = 0;
348  ball_bpi->material.getDouble("slip", ballSlip);
349  double groundSlip = 0;
350  ground_bpi->material.getDouble("slip", groundSlip);
351 
352  linesOut.emplace_back(
353  string_format("ball mass: %1.2f kg club mass: %1.2f kg",
354  ball_bpi->body->m, club_bpi->body->m));
355  linesOut.emplace_back(string_format("ball friction: %1.3f ground friction: %1.3f",
356  ball_bpi->material.getFrictionCoefficient(),
357  ground_bpi->material.getFrictionCoefficient()));
358  linesOut.emplace_back(string_format("ball rolling friction: %1.6f ball slip: %1.5f rad/(Ns)",
359  ball_bpi->material.getRollingFrictionCoefficient(),
360  ballSlip));
361  linesOut.emplace_back(string_format("ball restitution: %1.3f ground slip: %1.5f rad/(Ns)",
362  ball_bpi->material.getRestitution(), groundSlip));
363  }
364  }
365 };
366 
367 // Register
369 
370 }
virtual bool getProperty(std::string &out, const char *property)=0
virtual bool getPropertyBool(const char *property, bool def=false)=0
void getHUDText(std::vector< std::string > &linesOut, double currentTime, const MatNd *obs, const MatNd *currentAction, PhysicsBase *simulator, PhysicsParameterManager *physicsManager, ForceDisturber *forceDisturber) override
Definition: ECMiniGolf.cpp:268
RcsBody * body
The body.
Definition: BodyParamInfo.h:64
static ExperimentConfigRegistration< ECMiniGolf > RegMiniGolf("MiniGolf")
void addParam(const char *bodyName, PhysicsParameterDescriptor *desc)
virtual ActionModel * createActionModel()
Definition: ECMiniGolf.cpp:77
BodyParamInfo * getBodyInfo(const char *bodyName)
virtual InitStateSetter * createInitStateSetter()
Definition: ECMiniGolf.cpp:236
virtual void initViewer(Rcs::Viewer *viewer)
Definition: ECMiniGolf.cpp:241
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
ObservationModel * observationModel
Observation model (pluggable) used to create the observation which will be returned from step() ...
PropertySource * properties
Property source (owned)
virtual void populatePhysicsParameters(PhysicsParameterManager *manager)
Definition: ECMiniGolf.cpp:223
virtual ObservationModel * createObservationModel()
Definition: ECMiniGolf.cpp:157
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
RcsGraph * graph
Graph description.