phymarxbot.cpp
1 /********************************************************************************
2  * WorldSim -- library for robot simulations *
3  * Copyright (C) 2012-2013 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * Fabrizio Papi <erkito87@gmail.com> *
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the Free Software *
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
20  ********************************************************************************/
21 
22 #include "phymarxbot.h"
23 #include "phybox.h"
24 #include "phycylinder.h"
25 #include "phyfixed.h"
26 #include "phyballandsocket.h"
27 #include "physphere.h"
28 #include "physuspension.h"
29 #include "phycompoundobject.h"
30 #include "phycone.h"
31 #include "phyhinge.h"
32 #include "mathutils.h"
33 #include "graphicalmarkers.h"
34 #include <cmath>
35 
36 namespace farsa {
37 
38 const real PhyMarXbot::basex = 0.034f;
39 const real PhyMarXbot::basey = 0.143f;
40 const real PhyMarXbot::basez = 0.048f;
41 const real PhyMarXbot::basem = 0.4f;
42 const real PhyMarXbot::bodyr = 0.085f;
43 const real PhyMarXbot::bodyh = 0.0055f;
44 const real PhyMarXbot::bodym = 0.02f;
45 const real PhyMarXbot::axledistance = 0.104f;
46 const real PhyMarXbot::trackradius = 0.022f;
47 const real PhyMarXbot::trackheight = 0.0295f;
48 const real PhyMarXbot::trackm = 0.05f;
49 const real PhyMarXbot::treaddepth = 0.004f;
50 const real PhyMarXbot::wheelr = 0.027f;
51 const real PhyMarXbot::wheelh = 0.0215f;
52 const real PhyMarXbot::wheelm = 0.02f;
53 const real PhyMarXbot::turreth = 0.0385f;
54 const real PhyMarXbot::turretm = 0.08f;
55 const real PhyMarXbot::attachdevr = bodyr;
56 const real PhyMarXbot::attachdevx = turreth * 0.8f;
57 const real PhyMarXbot::attachdevy = turreth * 0.4f;
58 const real PhyMarXbot::attachdevz = turreth * 0.2f;
59 const real PhyMarXbot::attachdevm = 0.03f;
60 
61 PhyMarXbot::PhyMarXbot( World* w, QString name, const wMatrix& basetm ) : WObject( w, name, basetm, false ) {
62  kinematicSimulation = false;
63  frontMarker = NULL;
64 
65  // --- reference frame
66  // X
67  // ^
68  // | ------
69  // | ______|____|_________
70  // | |_|_| track |_|_|_|_|
71  // | -------------------
72  // | | battery |
73  // | -------------------
74  // | |_|_| track |_|_|_|_|
75  // | | |
76  // | ------
77  // |
78  // ---------------------> Y
79  // The front of the robot is towards -Y (positive speeds of the wheel make the robot move towards -Y)
80 
81  // --- create material for the marXbot
82  // introducing a semplification for the collision: two robot collide only with the attachring
83  w->materials().createMaterial( "marXbotLowerBody" );
84  w->materials().setElasticity( "marXbotLowerBody", "default", 0.01f );
85  w->materials().setSoftness( "marXbotLowerBody", "default", 0.01f );
86  w->materials().createMaterial( "marXbotUpperBody" );
87  w->materials().enableCollision( "marXbotLowerBody", "marXbotLowerBody", false );
88  w->materials().enableCollision( "marXbotLowerBody", "marXbotUpperBody", false );
89 
90  QVector<PhyObject*> objs;
91  PhyObject* obj;
93  // --- create the body of the base of the marxbot
94  obj = new PhyBox( basex+2.0f*trackheight, axledistance, basez+trackradius*2.0f, w );
95  obj->setMass( basem+bodym );
96  tm = wMatrix::identity();
97  tm.w_pos[2] = (basez+trackradius*2.0f)/2.0f + treaddepth;
98  obj->setMatrix( tm );
99  objs << obj;
100  // merge all togheter. Using a PhyCompoundObject even if there is only one object allows
101  // to displace the transformation matrix
102  basev = new PhyCompoundObject( objs, w, "base" );
103  basev->setMatrix( basetm );
104  basev->setMaterial("marXbotLowerBody");
105  basev->setUseColorTextureOfOwner( false );
106  basev->setOwner( this, false );
107 
108  // --- create the two external wheels
109  // they are motorized and they move the robot
110  // and create four spheres for supporting the tracks
111  // NOTE: the tracks are not simulated, they are just rigid bodies and
112  // the four sphere move freely in order to approximate the real movement
113  // --- position of wheels and their IDs in the vector
114  // +-----+
115  // |3|| ||2|
116  // |1| | | |0|
117  // |5|| ||4|
118  // +-----+
119  // --------------------> X
120  // arrays of X and Y offsets for calculate the positions
121  double xoffs[6] = { 1, -1, 1, -1, 1, -1 };
122  double yoffs[6] = { 0, 0, 1, 1, -1, -1 };
123  PhyObject* awheel;
124  PhyJoint* joint;
125  for( int i=0; i<6; i++ ) {
126  // --- relative to base
127  wMatrix wtm = wMatrix::identity();
128  wtm.w_pos = wVector(
129  xoffs[i] * (basex + trackheight)/2.0f + (yoffs[i]==0 ? xoffs[i]*(trackheight/2.0+wheelh/2.0f+0.006f) : 0.0f),
130  yoffs[i] * (axledistance/2.0f),
131  0.0f );
132  if ( i<2 ) {
133  // the two motorized wheels
134  wtm.w_pos[2] = wheelr;
135  awheel = new PhyCylinder( wheelr, wheelh, w, "motorWheel" );
136  } else {
137  // the four sphere supporting the track
138  wtm.w_pos[2] = treaddepth-0.003f;
139  awheel = new PhySphere( treaddepth, w, "passiveWheel" );
140  }
141  wheelstm.append( wtm );
142  awheel->setMass( wheelm );
143  awheel->setMaterial( "marXbotLowerBody" );
144  awheel->setUseColorTextureOfOwner( false );
145  awheel->setOwner( this, false );
146  awheel->setMatrix( wtm * basetm );
147  wheels.append( awheel );
148 
149  //--- create the joints
150  if ( i<2 ) {
151  // the two motorized wheels
152  joint = new PhySuspension(
153  basev->matrix().x_ax, // rotation axis
154  wheels[i]->matrix().w_pos,
155  basev->matrix().z_ax, // suspension 'vertical' axis
156  basev, wheels[i] );
157  joint->dofs()[0]->disableLimits();
158  } else {
159  // the four sphere supporting the track
160  joint = new PhyBallAndSocket(
161  wheels[i]->matrix().w_pos,
162  basev, wheels[i] );
163  }
164  joint->setOwner( this, false );
165  joint->updateJointInfo();
166  wheelJoints.append( joint );
167  }
168 
169  // Creating the turret
170  turretv = new PhyCylinder(bodyr, turreth, w);
171  turretv->setMass(turretm);
172  turrettm = wMatrix::yaw(toRad(-90.0f));
173  turrettm.w_pos.z = 0.005f + basez + bodyh + turreth + 0.0015f;
174  turretv->setMatrix(turrettm * basetm);
175  turretv->setMaterial("marXbotUpperBody");
176  turretv->setOwner(this, false);
177  turretv->setUseColorTextureOfOwner(true);
178 
179  // --- create the joint for sensing the force
180  forcesensor = new PhyFixed( basev, turretv, w );
181  forcesensor->setOwner( this, false );
182 
183  // By default the attachement device is disabled
184  attachdev = NULL;
185  attachdevjoint = NULL;
186  // We always create the attachment device controller, it will however not work unless the attachment
187  // device is enabled
188  attachdevCtrl = new MarXbotAttachmentDeviceMotorController(this);
189  attachdevCtrl->setOwner( this, false );
190 
191  // create the motor controller
192  QVector<PhyDOF*> motors;
193  motors << wheelJoints[0]->dofs()[0] << wheelJoints[1]->dofs()[0];
194  wheelsCtrl = new WheelMotorController( motors, w );
195  wheelsCtrl->setOwner( this, false );
196 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
197  #warning QUI DECIDERE PER LE VELOCITÀ MASSIME E MINIME DELLE RUOTE
198 #endif
199  wheelsCtrl->setSpeedLimits( -10.0, -10.0, 10.0, 10.0 );
200 
201  // Connecting wheels speed signals to be able to move the robot when in kinematic
202  connect(wheelJoints[0]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setRightWheelDesideredVelocity(real)));
203  connect(wheelJoints[1]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setLeftWheelDesideredVelocity(real)));
204 
205  // Creating the proximity IR sensors
206  QVector<SingleIR> sensors;
207 
208 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
209  #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI (SPECIE PER I GROUND)
210 #endif
211  // Adding the sensors. The marxbot has 24 proximity infrared sensors
212  for (unsigned int i = 0; i < 24; i++) {
213  const double curAngle = double(i) * (360.0 / 24.0) + ((360.0 / 24.0) / 2.0);
214  const double radius = bodyr;
215 
216  wMatrix mtr = wMatrix::yaw(toRad(curAngle + 90.0)) * wMatrix::pitch(PI_GRECO / 2.0);
217  mtr.w_pos.x = radius * cos(toRad(curAngle));
218  mtr.w_pos.y = radius * sin(toRad(curAngle));
219  mtr.w_pos.z = 0.005f + basez + bodyh + turreth / 2.0f + 0.0015f;
220 
221  sensors.append(SingleIR(basev, mtr, 0.0, 0.1, 10.0, 5));
222  }
223  proximityIR = new SimulatedIRProximitySensorController(world(), sensors);
224 
225  // Now creating the ground IR sensors below the battery pack
226  sensors.clear();
227  wMatrix mtr = wMatrix::yaw(PI_GRECO);
228  const double distFromBorder = 0.003;
229 
230  // Adding the sensors. The marxbot has 4 ground infrared sensors below the battery pack
231  mtr.w_pos = wVector(basex / 2.0f + trackheight - distFromBorder, axledistance / 2.0f - distFromBorder, treaddepth);
232  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
233  mtr.w_pos = wVector(basex / 2.0f + trackheight - distFromBorder, -axledistance / 2.0f + distFromBorder, treaddepth);
234  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
235  mtr.w_pos = wVector(-basex / 2.0f - trackheight + distFromBorder, axledistance / 2.0f - distFromBorder, treaddepth);
236  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
237  mtr.w_pos = wVector(-basex / 2.0f - trackheight + distFromBorder, -axledistance / 2.0f + distFromBorder, treaddepth);
238  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
239  groundBottomIR = new SimulatedIRGroundSensorController(world(), sensors);
240 
241  // Creating the ground IR sensors below the base
242  sensors.clear();
243 
244  // Adding the sensors. The marxbot has 8 ground infrared sensors below the base
245  for (unsigned int i = 0; i < 8; i++) {
246  const double curAngle = double(i) * (360.0 / 8.0);
247  const double radius = bodyr - 0.003;
248 
249  wMatrix mtr = wMatrix::yaw(PI_GRECO);
250  mtr.w_pos.x = radius * cos(toRad(curAngle));
251  mtr.w_pos.y = radius * sin(toRad(curAngle));
252  mtr.w_pos.z = 0.005f + basez + bodyh + turreth / 2.0f + 0.0015f;
253 
254  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
255  }
256  groundAroundIR = new SimulatedIRGroundSensorController(world(), sensors);
257 
258  // Creating the traction sensor
259  tractionSensor = new TractionSensorController(world(), *forcesensor);
260 
261  w->pushObject( this );
262 
263  uniformColor.append(PhyCylinder::SegmentColor(SimpleInterval(-PI_GRECO, PI_GRECO), color()));
264 }
265 
267  // First of all signalling we are about to delete the attachment device (and all the rest)
268  attachdevCtrl->attachmentDeviceAboutToBeDestroyed();
269 
270  delete wheelsCtrl;
271  delete attachdevCtrl;
272  delete proximityIR;
273  delete groundBottomIR;
274  delete groundAroundIR;
275  foreach( PhyJoint* susp, wheelJoints ) {
276  delete susp;
277  }
278  foreach( PhyObject* w, wheels ) {
279  delete w;
280  }
281  delete forcesensor;
282  delete attachdevjoint;
283  delete turretv;
284  delete basev;
285  delete attachdev;
286 }
287 
289 {
290  // Updating motors
291  if (wheelsCtrl->isEnabled()) {
292  wheelsCtrl->update();
293  }
294  if (attachdevCtrl->isEnabled()) {
295  attachdevCtrl->update();
296  }
297 
298  if (kinematicSimulation) {
299  // In kinematic mode, we have to manually move the robot depending on the wheel velocities
300  wMatrix mtr = matrix();
301  wheeledRobotsComputeKinematicMovement(mtr, leftWheelVelocity, rightWheelVelocity, wheelr, wheelstm[0].w_pos.x - wheelstm[1].w_pos.x, world()->timeStep());
302 
303  // This will also update the position of all pieces
304  setMatrix(mtr);
305  }
306 }
307 
309 {
310  // Updating sensors
311  if (proximityIR->isEnabled()) {
312  proximityIR->update();
313  }
314  if (groundBottomIR->isEnabled()) {
315  groundBottomIR->update();
316  }
317  if (groundAroundIR->isEnabled()) {
318  groundAroundIR->update();
319  }
320 
321  // Updating the transformation matrix of the robot. It is coincident with the matrix of the base
322  tm = basev->matrix();
323 }
324 
325 void PhyMarXbot::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
326 {
327  proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
328 }
329 
330 void PhyMarXbot::setGroundBottomIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
331 {
332  groundBottomIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
333 }
334 
335 void PhyMarXbot::setGroundAroundIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
336 {
337  groundAroundIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
338 }
339 
340 void PhyMarXbot::setDrawFrontMarker(bool drawMarker)
341 {
342  if (getDrawFrontMarker() == drawMarker) {
343  return;
344  }
345 
346  if (drawMarker) {
347  frontMarker = new PlanarArrowGraphicalMarker(PhyMarXbot::bodyr, PhyMarXbot::bodyr / 6.0f, PhyMarXbot::bodyr / 4.0f, 0.7f, world());
348  frontMarker->setUseColorTextureOfOwner(false);
349  frontMarker->setColor(Qt::green);
350  frontMarker->setTexture("");
351 
352  wMatrix displacement = wMatrix::roll(-PI_GRECO / 2.0f);
353  displacement.w_pos = wVector(0.0, 0.0, basez + trackradius * 2.0f + treaddepth + turreth - 0.010f + 0.0001f);
354  frontMarker->attachToObject(this, true, displacement);
355  } else {
356  delete frontMarker;
357  frontMarker = NULL;
358  }
359 }
360 
362 {
363  return (frontMarker != NULL);
364 }
365 
367 {
368  if (attachmentDeviceEnabled() == enable) {
369  return;
370  }
371 
372  if (enable) {
373  // This little cube shows the position of the attachment fingers
374  attachdev = new PhyBox(attachdevx, attachdevy, attachdevz, world());
375  attachdev->setMass(attachdevm);
376  attachdevtm = turretv->matrix();
377  attachdevtm.w_pos.y -= attachdevr;
378  attachdev->setMatrix(attachdevtm);
379  attachdev->setOwner(this, false);
380 
381  // Creating the joint for the attachment device
382  attachdevjoint = new PhyHinge(wVector(1.0f, 0.0, 0.0), wVector(0.0, 0.0, 0.0), 0.0, turretv, attachdev, world());
383  attachdevjoint->dofs()[0]->disableLimits();
384  attachdevjoint->dofs()[0]->setDesiredPosition(0.0); // This way the attachdev doesn't rotate
385  attachdevjoint->dofs()[0]->setStiffness(0.1f); // This way the attachdev motor is not very strong
386  attachdevjoint->setOwner(this, false);
387  } else {
388  // Notifying the attachment device controller
389  attachdevCtrl->attachmentDeviceAboutToBeDestroyed();
390  // Destroying the joint and the attachment device
391  delete attachdevjoint;
392  attachdevjoint = NULL;
393  delete attachdev;
394  attachdev = NULL;
395  }
396 }
397 
399 {
400  // If the attachment device is enabled, we simply disable and then re-enable it
401  if (attachmentDeviceEnabled()) {
402  enableAttachmentDevice(false);
404  }
405 }
406 
408 {
409  if (kinematicSimulation == k) {
410  return;
411  }
412 
413  kinematicSimulation = k;
414  if (kinematicSimulation) {
415  // First disabling all joints...
416  for (int i = 0; i < wheelJoints.size(); i++) {
417  wheelJoints[i]->enable(false);
418  }
419  forcesensor->enable(false);
420  if (attachdevjoint != NULL) {
421  attachdevjoint->enable(false);
422  }
423 
424  // ... then setting all objects to kinematic behaviour
425  basev->setKinematic(true, true);
426  for (int i = 0; i < wheels.size(); i++) {
427  wheels[i]->setKinematic(true, true);
428  }
429  turretv->setKinematic(true, true);
430  if (attachdev != NULL) {
431  attachdev->setKinematic(true, true);
432  }
433  } else {
434  // First setting all objects to dynamic behaviour...
435  basev->setKinematic(false);
436  for (int i = 0; i < wheels.size(); i++) {
437  wheels[i]->setKinematic(false);
438  }
439  turretv->setKinematic(false);
440  if (attachdev != NULL) {
441  attachdev->setKinematic(false);
442  }
443 
444  // ... then enabling all joints (if the corresponding part is enabled)
445  for (int i = 0; i < wheelJoints.size(); i++) {
446  wheelJoints[i]->enable(true);
447  wheelJoints[i]->updateJointInfo();
448  }
449  forcesensor->enable(true);
450  forcesensor->updateJointInfo();
451  if (attachdevjoint != NULL) {
452  attachdevjoint->enable(true);
453  attachdevjoint->updateJointInfo();
454  }
455  }
456 }
457 
458 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
459  #warning PROBLEMA RELATIVO AI LED DEL MARXBOT: NON C È L'ATTACHRING, SOLO LA TORRETTA CHE PERÃ’ È FISSA. NEL ROBOT REALE I LED SONO SULL' ATTACHRING, QUINDI RUOTANO (CONTROLLARE!!!), QUI SONO SULLA TORRETTA QUINDI SONO FISSI
460 #endif
461 void PhyMarXbot::setLedColors(QList<QColor> c)
462 {
463  if (c.size() != 12) {
464  return;
465  }
466 
467  turretv->setUseColorTextureOfOwner(false);
468 
469  ledColorsv = c;
470  QList<PhyCylinder::SegmentColor> s;
471  const real startAngle = (PI_GRECO / 2.0f) - (PI_GRECO / 12.0f);
472  for (int i = 0; i < 12; i++) {
473  const real rangeMin = (real(i) * PI_GRECO / 6.0) + startAngle;
474  const real rangeMax = (real(i + 1) * PI_GRECO / 6.0) + startAngle;
475  s.append(PhyCylinder::SegmentColor(SimpleInterval(normalizeRad(rangeMin), normalizeRad(rangeMax)), ledColorsv[i]));
476  }
477  turretv->setSegmentsColor(Qt::white, s);
478  turretv->setUpperBaseColor(color());
479  turretv->setLowerBaseColor(color());
480 }
481 
482 QList<QColor> PhyMarXbot::ledColors() const
483 {
484  if (ledColorsv.isEmpty()) {
485  QList<QColor> c;
486  for (int i = 0; i < 12; i++) {
487  c.append(color());
488  }
489  return c;
490  } else {
491  return ledColorsv;
492  }
493 }
494 
495 const QList<PhyCylinder::SegmentColor>& PhyMarXbot::segmentsColor() const
496 {
497  if (ledColorsv.isEmpty()) {
498  uniformColor[0].color = color();
499  return uniformColor;
500  } else {
501  return turretv->segmentsColor();
502  }
503 }
504 
506 {
507  leftWheelVelocity = velocity;
508 }
509 
511 {
512  rightWheelVelocity = velocity;
513 }
514 
516  wMatrix tm = matrix();
517  basev->setMatrix( tm );
518  for( int i=0; i<wheels.size(); i++ ) {
519  wheels[i]->setMatrix( wheelstm[i] * tm );
520  }
521  foreach( PhyJoint* ajoint, wheelJoints ) {
522  ajoint->updateJointInfo();
523  }
524  turretv->setMatrix( turrettm * tm );
525  forcesensor->updateJointInfo();
526  if ((attachdev != NULL) && (attachdevjoint != NULL)) {
527  attachdev->setMatrix( attachdevtm * tm );
528  attachdevjoint->updateJointInfo();
529  }
530 }
531 
532 namespace previous {
533  const real PhyMarXbot::basex = 0.034f;
534  const real PhyMarXbot::basey = 0.143f;
535  const real PhyMarXbot::basez = 0.048f;
536  const real PhyMarXbot::basem = 0.4f;
537  const real PhyMarXbot::bodyr = 0.085f;
538  const real PhyMarXbot::bodyh = 0.0055f;
539  const real PhyMarXbot::bodym = 0.02f;
540  const real PhyMarXbot::axledistance = 0.104f;
541  const real PhyMarXbot::trackradius = 0.022f;
542  const real PhyMarXbot::trackheight = 0.0295f;
543  const real PhyMarXbot::trackm = 0.05f;
544  const real PhyMarXbot::treaddepth = 0.004f;
545  const real PhyMarXbot::wheelr = 0.027f;
546  const real PhyMarXbot::wheelh = 0.0215f;
547  const real PhyMarXbot::wheelm = 0.02f;
548  const real PhyMarXbot::attachringh = 0.0285f;
549  const real PhyMarXbot::attachringm = 0.08f;
550  const real PhyMarXbot::ledsh = 0.010f;
551  const real PhyMarXbot::ledsradius = 0.080f;
552  const real PhyMarXbot::ledsm = 0.03f;
553 
554  PhyMarXbot::PhyMarXbot( World* w, QString name, const wMatrix& basetm ) : WObject( w, name, basetm, false ) {
555  kinematicSimulation = false;
556 
557  // --- reference frame
558  // X
559  // ^
560  // | ------
561  // | ______|____|_________
562  // | |_|_| track |_|_|_|_|
563  // | -------------------
564  // | | battery |
565  // | -------------------
566  // | |_|_| track |_|_|_|_|
567  // | | |
568  // | ------
569  // |
570  // ---------------------> Y
571  // The front of the robot is towards -Y (positive speeds of the wheel make the robot move towards -Y)
572 
573  // --- create material for the marXbot
574  // introducing a semplification for the collision: two robot collide only with the attachring
575  w->materials().createMaterial( "marXbotLowerBody" );
576  w->materials().setElasticity( "marXbotLowerBody", "default", 0.01f );
577  w->materials().setSoftness( "marXbotLowerBody", "default", 0.01f );
578  w->materials().createMaterial( "marXbotUpperBody" );
579  w->materials().enableCollision( "marXbotLowerBody", "marXbotLowerBody", false );
580  w->materials().enableCollision( "marXbotLowerBody", "marXbotUpperBody", false );
581 
582  QVector<PhyObject*> objs;
583  PhyObject* obj;
584  // --- create the body of the base of the marxbot
585  #ifdef MARXBOT_DETAILED
587  // battery container
588  obj = new PhyBox( basex, basey, basez, w );
589  tm.w_pos[2] = basez/2.0f + 0.015f;
590  obj->setMass( basem );
591  obj->setMatrix( tm );
592  objs << obj;
593  // cylinder body
594  obj = new PhyCylinder( bodyr, bodyh, w );
595  obj->setMass( bodym );
596  tm = wMatrix::yaw( toRad(90.0f) );
597  tm.w_pos[2] = 0.015f + basez + bodyh/2.0f;
598  obj->setMatrix( tm );
599  objs << obj;
600  // right track
601  obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
602  tm = wMatrix::identity();
603  tm.w_pos[0] = (basex + trackheight)/2.0f;
604  tm.w_pos[2] = trackradius + treaddepth;
605  obj->setMass( trackm );
606  obj->setMatrix( tm );
607  objs << obj;
608  obj = new PhyCylinder( trackradius, trackheight, w );
609  obj->setMass( wheelm );
610  tm.w_pos[1] = axledistance/2.0;
611  obj->setMatrix( tm );
612  objs << obj;
613  obj = new PhyCylinder( trackradius, trackheight, w );
614  obj->setMass( wheelm );
615  tm.w_pos[1] = -axledistance/2.0;
616  obj->setMatrix( tm );
617  objs << obj;
618  // left track
619  obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
620  tm = wMatrix::identity();
621  tm.w_pos[0] = -(basex + trackheight)/2.0f;
622  tm.w_pos[2] = trackradius + treaddepth;
623  obj->setMass( trackm );
624  obj->setMatrix( tm );
625  objs << obj;
626  obj = new PhyCylinder( trackradius, trackheight, w );
627  obj->setMass( wheelm );
628  tm.w_pos[1] = axledistance/2.0;
629  obj->setMatrix( tm );
630  objs << obj;
631  obj = new PhyCylinder( trackradius, trackheight, w );
632  obj->setMass( wheelm );
633  tm.w_pos[1] = -axledistance/2.0;
634  obj->setMatrix( tm );
635  objs << obj;
636  #else
637  // simplified version of the marxbot physic
638  obj = new PhyBox( basex+2.0f*trackheight, axledistance, basez+trackradius*2.0f, w );
639  obj->setMass( basem+bodym );
640  tm = wMatrix::identity();
641  tm.w_pos[2] = (basez+trackradius*2.0f)/2.0f + treaddepth;
642  obj->setMatrix( tm );
643  objs << obj;
644  #endif
645  // merge all togheter
646  base = new PhyCompoundObject( objs, w, "base" );
647  base->setMatrix( basetm );
648  base->setMaterial("marXbotLowerBody");
649  base->setOwner( this, false );
650 
651  // --- create the two external wheels
652  // they are motorized and they move the robot
653  // and create four spheres for supporting the tracks
654  // NOTE: the tracks are not simulated, they are just rigid bodies and
655  // the four sphere move freely in order to approximate the real movement
656  // --- position of wheels and their IDs in the vector
657  // +-----+
658  // |3|| ||2|
659  // |1| | | |0|
660  // |5|| ||4|
661  // +-----+
662  // --------------------> X
663  // arrays of X and Y offsets for calculate the positions
664  double xoffs[6] = { 1, -1, 1, -1, 1, -1 };
665  double yoffs[6] = { 0, 0, 1, 1, -1, -1 };
666  PhyObject* awheel;
667  PhyJoint* joint;
668  for( int i=0; i<6; i++ ) {
669  // --- relative to base
670  wMatrix wtm = wMatrix::identity();
671  wtm.w_pos = wVector(
672  xoffs[i] * (basex + trackheight)/2.0f + (yoffs[i]==0 ? xoffs[i]*(trackheight/2.0+wheelh/2.0f+0.006f) : 0.0f),
673  yoffs[i] * (axledistance/2.0f),
674  0.0f );
675  if ( i<2 ) {
676  // the two motorized wheels
677  wtm.w_pos[2] = wheelr;
678  awheel = new PhyCylinder( wheelr, wheelh, w, "motorWheel" );
679  } else {
680  // the four sphere supporting the track
681  wtm.w_pos[2] = treaddepth-0.003f;
682  awheel = new PhySphere( treaddepth, w, "passiveWheel" );
683  }
684  wheelstm.append( wtm );
685  awheel->setMass( wheelm );
686  awheel->setColor( Qt::blue );
687  awheel->setMaterial( "marXbotLowerBody" );
688  awheel->setOwner( this, false );
689  awheel->setMatrix( wtm * basetm );
690  wheels.append( awheel );
691 
692  //--- create the joints
693  if ( i<2 ) {
694  // the two motorized wheels
695  joint = new PhySuspension(
696  base->matrix().x_ax, // rotation axis
697  wheels[i]->matrix().w_pos,
698  base->matrix().z_ax, // suspension 'vertical' axis
699  base, wheels[i] );
700  joint->dofs()[0]->disableLimits();
701  } else {
702  // the four sphere supporting the track
703  joint = new PhyBallAndSocket(
704  wheels[i]->matrix().w_pos,
705  base, wheels[i] );
706  }
707  joint->setOwner( this, false );
708  joint->updateJointInfo();
709  wheelJoints.append( joint );
710  }
711 
712  // --- create the attachment module with the 12 RGB LEDs part
713  #ifdef MARXBOT_DETAILED
714  objs.clear();
715  obj = new PhyCone( bodyr, attachringh+0.010f, w );
716  obj->setMass( attachringm );
717  tm = wMatrix::identity();
718  tm.w_pos[0] = 0.005f;
719  obj->setMatrix( tm );
720  objs << obj;
721  obj = new PhyCone( bodyr, attachringh+0.010f, w );
722  obj->setMass( attachringm );
723  tm = wMatrix::roll( toRad(180.0f) );
724  tm.w_pos[0] = -0.005f;
725  obj->setMatrix( tm );
726  objs << obj;
727  obj = new PhyCylinder( ledsradius, ledsh, w );
728  obj->setMass( ledsm );
729  obj->setTexture( "marXbot_12leds" );
730  obj->setUseColorTextureOfOwner( false );
731  tm.w_pos[0] = attachringh/2.0f + ledsh/2.0f + 0.0015f;
732  obj->setMatrix( tm );
733  objs << obj;
734  #else
735  objs.clear();
736  obj = new PhyCylinder( bodyr, attachringh+ledsh, w );
737  obj->setMass( attachringm );
738  tm = wMatrix::identity();
739  tm.w_pos[0] = attachringh/2.0f-0.010f;
740  obj->setMatrix( tm );
741  objs << obj;
742  #endif
743  // merge all toghether
744  attachring = new PhyCompoundObject( objs, w );
745  attachring->setMaterial("marXbotUpperBody");
746  attachring->setOwner( this, false );
747  attachring->setUseColorTextureOfOwner( false );
748  attachringtm = wMatrix::yaw( toRad(-90.0f) );
749  attachringtm.w_pos[2] = 0.015f + basez + bodyh + attachringh/2.0f + 0.0015f;
750  attachring->setMatrix( attachringtm * basetm );
751  // --- create the joint for sensing the force
752  forcesensor = new PhyFixed( base, attachring, w );
753  forcesensor->setOwner( this, false );
754 
755  // create the motor controller
756  QVector<PhyDOF*> motors;
757  motors << wheelJoints[0]->dofs()[0] << wheelJoints[1]->dofs()[0];
758  wheelsCtrl = new WheelMotorController( motors, w );
759  wheelsCtrl->setOwner( this, false );
760  #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
761  #warning QUI DECIDERE PER LE VELOCITÀ MASSIME E MINIME DELLE RUOTE
762  #endif
763  wheelsCtrl->setSpeedLimits( -10.0, -10.0, 10.0, 10.0 );
764 
765  // Connecting wheels speed signals to be able to move the robot when in kinematic
766  connect(wheelJoints[0]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setRightWheelDesideredVelocity(real)));
767  connect(wheelJoints[1]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setLeftWheelDesideredVelocity(real)));
768 
769  // Creating the proximity IR sensors
770  QVector<SingleIR> sensors;
771 
772  #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
773  #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI (SPECIE PER I GROUND)
774  #endif
775  // Adding the sensors. The marxbot has 24 proximity infrared sensors
776  for (unsigned int i = 0; i < 24; i++) {
777  const double curAngle = double(i) * (360.0 / 24.0) + ((360.0 / 24.0) / 2.0);
778  const double radius = bodyr;
779 
780  wMatrix mtr = wMatrix::yaw(toRad(curAngle + 90.0)) * wMatrix::pitch(PI_GRECO / 2.0);
781  mtr.w_pos.x = radius * cos(toRad(curAngle));
782  mtr.w_pos.y = radius * sin(toRad(curAngle));
783  mtr.w_pos.z = 0.015f + basez + bodyh/2.0f;
784 
785  sensors.append(SingleIR(base, mtr, 0.02, 0.1, 10.0, 5));
786  }
787  proximityIR = new SimulatedIRProximitySensorController(world(), sensors);
788 
789  // Now creating the ground IR sensors below the battery pack
790  sensors.clear();
791  wMatrix mtr = wMatrix::yaw(PI_GRECO);
792  const double distFromBorder = 0.003;
793 
794  // Adding the sensors. The marxbot has 4 ground infrared sensors below the battery pack
795  mtr.w_pos = wVector(basex / 2.0f - distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
796  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
797  mtr.w_pos = wVector(basex / 2.0f - distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
798  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
799  mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
800  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
801  mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
802  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
803  groundBottomIR = new SimulatedIRGroundSensorController(world(), sensors);
804 
805  // Creating the ground IR sensors below the base
806  sensors.clear();
807 
808  // Adding the sensors. The marxbot has 8 ground infrared sensors below the base
809  for (unsigned int i = 0; i < 8; i++) {
810  const double curAngle = double(i) * (360.0 / 8.0);
811  const double radius = bodyr - 0.003;
812 
813  wMatrix mtr = wMatrix::yaw(PI_GRECO);
814  mtr.w_pos.x = radius * cos(toRad(curAngle));
815  mtr.w_pos.y = radius * sin(toRad(curAngle));
816  mtr.w_pos.z = 0.015f + basez;
817 
818  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
819  }
820  groundAroundIR = new SimulatedIRGroundSensorController(world(), sensors);
821 
822  // Creating the traction sensor
823  tractionSensor = new TractionSensorController(world(), *forcesensor);
824 
825  w->pushObject( this );
826  }
827 
829  foreach( PhyJoint* susp, wheelJoints ) {
830  delete susp;
831  }
832  foreach( PhyObject* w, wheels ) {
833  delete w;
834  }
835  delete wheelsCtrl;
836  delete forcesensor;
837  delete attachring;
838  delete base;
839  delete proximityIR;
840  delete groundBottomIR;
841  delete groundAroundIR;
842  }
843 
845  {
846  // Updating motors
847  if (wheelsCtrl->isEnabled()) {
848  wheelsCtrl->update();
849  }
850 
851  if (kinematicSimulation) {
852  // In kinematic mode, we have to manually move the robot depending on the wheel velocities
853  wMatrix mtr = matrix();
854  wheeledRobotsComputeKinematicMovement(mtr, leftWheelVelocity, rightWheelVelocity, wheelr, wheelstm[0].w_pos.x - wheelstm[1].w_pos.x, world()->timeStep());
855 
856  // This will also update the position of all pieces
857  setMatrix(mtr);
858  }
859  }
860 
862  {
863  // Updating sensors
864  if (proximityIR->isEnabled()) {
865  proximityIR->update();
866  }
867  if (groundBottomIR->isEnabled()) {
868  groundBottomIR->update();
869  }
870  if (groundAroundIR->isEnabled()) {
871  groundAroundIR->update();
872  }
873 
874  // Updating the transformation matrix of the robot. It is coincident with the matrix of the base
875  tm = base->matrix();
876  }
877 
878  void PhyMarXbot::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
879  {
880  proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
881  }
882 
883  void PhyMarXbot::setGroundBottomIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
884  {
885  groundBottomIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
886  }
887 
888  void PhyMarXbot::setGroundAroundIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
889  {
890  groundAroundIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
891  }
892 
894  {
895  if (kinematicSimulation == k) {
896  return;
897  }
898 
899  kinematicSimulation = k;
900  if (kinematicSimulation) {
901  // First disabling all joints...
902  for (int i = 0; i < wheelJoints.size(); i++) {
903  wheelJoints[i]->enable(false);
904  }
905  forcesensor->enable(false);
906 
907  // ... then setting all objects to kinematic behaviour
908  base->setKinematic(true, true);
909  for (int i = 0; i < wheels.size(); i++) {
910  wheels[i]->setKinematic(true, true);
911  }
912  attachring->setKinematic(true, true);
913  } else {
914  // First setting all objects to dynamic behaviour...
915  base->setKinematic(false);
916  for (int i = 0; i < wheels.size(); i++) {
917  wheels[i]->setKinematic(false);
918  }
919  attachring->setKinematic(false);
920 
921  // ... then enabling all joints (if the corresponding part is enabled)
922  for (int i = 0; i < wheelJoints.size(); i++) {
923  wheelJoints[i]->enable(true);
924  wheelJoints[i]->updateJointInfo();
925  }
926  forcesensor->enable(true);
927  forcesensor->updateJointInfo();
928  }
929  }
930 
932  {
933  leftWheelVelocity = velocity;
934  }
935 
937  {
938  rightWheelVelocity = velocity;
939  }
940 
942  wMatrix tm = matrix();
943  base->setMatrix( tm );
944  for( int i=0; i<wheels.size(); i++ ) {
945  wheels[i]->setMatrix( wheelstm[i] * tm );
946  }
947  foreach( PhyJoint* ajoint, wheelJoints ) {
948  ajoint->updateJointInfo();
949  }
950  attachring->setMatrix( attachringtm * tm );
951  forcesensor->updateJointInfo();
952  }
953 }
954 
955 } // end namespace farsa