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.8;
57 const real PhyMarXbot::attachdevy = turreth * 0.4;
58 const real PhyMarXbot::attachdevz = turreth * 0.2;
59 const real PhyMarXbot::attachdevm = 0.03;
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 
178  // --- create the joint for sensing the force
179  forcesensor = new PhyFixed( basev, turretv, w );
180  forcesensor->setOwner( this, false );
181 
182  // By default the attachement device is disabled
183  attachdev = NULL;
184  attachdevjoint = NULL;
185  // We always create the attachment device controller, it will however not work unless the attachment
186  // device is enabled
187  attachdevCtrl = new MarXbotAttachmentDeviceMotorController(this);
188  attachdevCtrl->setOwner( this, false );
189 
190  // create the motor controller
191  QVector<PhyDOF*> motors;
192  motors << wheelJoints[0]->dofs()[0] << wheelJoints[1]->dofs()[0];
193  wheelsCtrl = new WheelMotorController( motors, w );
194  wheelsCtrl->setOwner( this, false );
195 #ifdef __GNUC__
196  #warning QUI DECIDERE PER LE VELOCITÀ MASSIME E MINIME DELLE RUOTE
197 #endif
198  wheelsCtrl->setSpeedLimits( -10.0, -10.0, 10.0, 10.0 );
199 
200  // Connecting wheels speed signals to be able to move the robot when in kinematic
201  connect(wheelJoints[0]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setRightWheelDesideredVelocity(real)));
202  connect(wheelJoints[1]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setLeftWheelDesideredVelocity(real)));
203 
204  // Creating the proximity IR sensors
205  QVector<SingleIR> sensors;
206 
207 #ifdef __GNUC__
208  #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI (SPECIE PER I GROUND)
209 #endif
210  // Adding the sensors. The marxbot has 24 proximity infrared sensors
211  for (unsigned int i = 0; i < 24; i++) {
212  const double curAngle = double(i) * (360.0 / 24.0) + ((360.0 / 24.0) / 2.0);
213  const double radius = bodyr;
214 
215  wMatrix mtr = wMatrix::yaw(deg2rad(curAngle + 90.0)) * wMatrix::pitch(deg2rad(90.0f));
216  mtr.w_pos.x = radius * cos(deg2rad(curAngle));
217  mtr.w_pos.y = radius * sin(deg2rad(curAngle));
218  mtr.w_pos.z = 0.005f + basez + bodyh + turreth / 2.0f + 0.0015f;
219 
220  sensors.append(SingleIR(basev, mtr, 0.02, 0.1, 10.0, 5));
221  }
222  proximityIR = new SimulatedIRProximitySensorController(world(), sensors);
223 
224  // Now creating the ground IR sensors below the battery pack
225  sensors.clear();
226  wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
227  const double distFromBorder = 0.003;
228 
229  // Adding the sensors. The marxbot has 4 ground infrared sensors below the battery pack
230  mtr.w_pos = wVector(basex / 2.0f + trackheight - distFromBorder, axledistance / 2.0f - distFromBorder, treaddepth);
231  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
232  mtr.w_pos = wVector(basex / 2.0f + trackheight - distFromBorder, -axledistance / 2.0f + distFromBorder, treaddepth);
233  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
234  mtr.w_pos = wVector(-basex / 2.0f - trackheight + distFromBorder, axledistance / 2.0f - distFromBorder, treaddepth);
235  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
236  mtr.w_pos = wVector(-basex / 2.0f - trackheight + distFromBorder, -axledistance / 2.0f + distFromBorder, treaddepth);
237  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
238  groundBottomIR = new SimulatedIRGroundSensorController(world(), sensors);
239 
240  // Creating the ground IR sensors below the base
241  sensors.clear();
242 
243  // Adding the sensors. The marxbot has 8 ground infrared sensors below the base
244  for (unsigned int i = 0; i < 8; i++) {
245  const double curAngle = double(i) * (360.0 / 8.0);
246  const double radius = bodyr - 0.003;
247 
248  wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
249  mtr.w_pos.x = radius * cos(deg2rad(curAngle));
250  mtr.w_pos.y = radius * sin(deg2rad(curAngle));
251  mtr.w_pos.z = 0.005f + basez + bodyh + turreth / 2.0f + 0.0015f;
252 
253  sensors.append(SingleIR(basev, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
254  }
255  groundAroundIR = new SimulatedIRGroundSensorController(world(), sensors);
256 
257  // Creating the traction sensor
258  tractionSensor = new TractionSensorController(world(), *forcesensor);
259 
260  w->pushObject( this );
261 }
262 
264  // First of all signalling we are about to delete the attachment device (and all the rest)
265  attachdevCtrl->attachmentDeviceAboutToBeDestroyed();
266 
267  delete wheelsCtrl;
268  delete attachdevCtrl;
269  delete proximityIR;
270  delete groundBottomIR;
271  delete groundAroundIR;
272  foreach( PhyJoint* susp, wheelJoints ) {
273  delete susp;
274  }
275  foreach( PhyObject* w, wheels ) {
276  delete w;
277  }
278  delete forcesensor;
279  delete attachdevjoint;
280  delete turretv;
281  delete basev;
282  delete attachdev;
283 }
284 
286 {
287  // Updating motors
288  if (wheelsCtrl->isEnabled()) {
289  wheelsCtrl->update();
290  }
291  if (attachdevCtrl->isEnabled()) {
292  attachdevCtrl->update();
293  }
294 
295  if (kinematicSimulation) {
296  // In kinematic mode, we have to manually move the robot depending on the wheel velocities
297  wMatrix mtr = matrix();
298  wheeledRobotsComputeKinematicMovement(mtr, leftWheelVelocity, rightWheelVelocity, wheelr, wheelstm[0].w_pos.x - wheelstm[1].w_pos.x, world()->timeStep());
299 
300  // This will also update the position of all pieces
301  setMatrix(mtr);
302  }
303 }
304 
306 {
307  // Updating sensors
308  if (proximityIR->isEnabled()) {
309  proximityIR->update();
310  }
311  if (groundBottomIR->isEnabled()) {
312  groundBottomIR->update();
313  }
314  if (groundAroundIR->isEnabled()) {
315  groundAroundIR->update();
316  }
317 
318  // Updating the transformation matrix of the robot. It is coincident with the matrix of the base
319  tm = basev->matrix();
320 }
321 
322 void PhyMarXbot::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
323 {
324  proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
325 }
326 
327 void PhyMarXbot::setGroundBottomIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
328 {
329  groundBottomIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
330 }
331 
332 void PhyMarXbot::setGroundAroundIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
333 {
334  groundAroundIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
335 }
336 
337 void PhyMarXbot::setDrawFrontMarker(bool drawMarker)
338 {
339  if (getDrawFrontMarker() == drawMarker) {
340  return;
341  }
342 
343  if (drawMarker) {
344  frontMarker = new PlanarArrowGraphicalMarker(PhyMarXbot::bodyr, PhyMarXbot::bodyr / 6.0f, PhyMarXbot::bodyr / 4.0f, 0.7f, world());
345  frontMarker->setUseColorTextureOfOwner(false);
346  frontMarker->setColor(Qt::green);
347  frontMarker->setTexture("");
348 
349  wMatrix displacement = wMatrix::roll(-PI_GRECO / 2.0f);
350  displacement.w_pos = wVector(0.0, 0.0, basez + trackradius * 2.0f + treaddepth + turreth - 0.010f + 0.0001f);
351  frontMarker->attachToObject(this, true, displacement);
352  } else {
353  delete frontMarker;
354  frontMarker = NULL;
355  }
356 }
357 
359 {
360  return (frontMarker != NULL);
361 }
362 
364 {
365  if (attachmentDeviceEnabled() == enable) {
366  return;
367  }
368 
369  if (enable) {
370  // This little cube shows the position of the attachment fingers
371  attachdev = new PhyBox(attachdevx, attachdevy, attachdevz, world());
372  attachdev->setMass(attachdevm);
373  attachdevtm = turretv->matrix();
374  attachdevtm.w_pos.y -= attachdevr;
375  attachdev->setMatrix(attachdevtm);
376  attachdev->setOwner(this, false);
377 
378  // Creating the joint for the attachment device
379  attachdevjoint = new PhyHinge(wVector(1.0, 0.0, 0.0), wVector(0.0, 0.0, 0.0), 0.0, turretv, attachdev, world());
380  attachdevjoint->dofs()[0]->disableLimits();
381  attachdevjoint->dofs()[0]->setDesiredPosition(0.0); // This way the attachdev doesn't rotate
382  attachdevjoint->dofs()[0]->setStiffness(0.1); // This way the attachdev motor is not very strong
383  attachdevjoint->setOwner(this, false);
384  } else {
385  // Notifying the attachment device controller
386  attachdevCtrl->attachmentDeviceAboutToBeDestroyed();
387  // Destroying the joint and the attachment device
388  delete attachdevjoint;
389  attachdevjoint = NULL;
390  delete attachdev;
391  attachdev = NULL;
392  }
393 }
394 
396 {
397  // If the attachment device is enabled, we simply disable and then re-enable it
398  if (attachmentDeviceEnabled()) {
399  enableAttachmentDevice(false);
401  }
402 }
403 
405 {
406  if (kinematicSimulation == k) {
407  return;
408  }
409 
410  kinematicSimulation = k;
411  if (kinematicSimulation) {
412  // First disabling all joints...
413  for (int i = 0; i < wheelJoints.size(); i++) {
414  wheelJoints[i]->enable(false);
415  }
416  forcesensor->enable(false);
417  if (attachdevjoint != NULL) {
418  attachdevjoint->enable(false);
419  }
420 
421  // ... then setting all objects to kinematic behaviour
422  basev->setKinematic(true, true);
423  for (int i = 0; i < wheels.size(); i++) {
424  wheels[i]->setKinematic(true, true);
425  }
426  turretv->setKinematic(true, true);
427  if (attachdev != NULL) {
428  attachdev->setKinematic(true, true);
429  }
430  } else {
431  // First setting all objects to dynamic behaviour...
432  basev->setKinematic(false);
433  for (int i = 0; i < wheels.size(); i++) {
434  wheels[i]->setKinematic(false);
435  }
436  turretv->setKinematic(false);
437  if (attachdev != NULL) {
438  attachdev->setKinematic(false);
439  }
440 
441  // ... then enabling all joints (if the corresponding part is enabled)
442  for (int i = 0; i < wheelJoints.size(); i++) {
443  wheelJoints[i]->enable(true);
444  wheelJoints[i]->updateJointInfo();
445  }
446  forcesensor->enable(true);
447  forcesensor->updateJointInfo();
448  if (attachdevjoint != NULL) {
449  attachdevjoint->enable(true);
450  attachdevjoint->updateJointInfo();
451  }
452  }
453 }
454 
456 {
457  leftWheelVelocity = velocity;
458 }
459 
461 {
462  rightWheelVelocity = velocity;
463 }
464 
466  wMatrix tm = matrix();
467  basev->setMatrix( tm );
468  for( int i=0; i<wheels.size(); i++ ) {
469  wheels[i]->setMatrix( wheelstm[i] * tm );
470  }
471  foreach( PhyJoint* ajoint, wheelJoints ) {
472  ajoint->updateJointInfo();
473  }
474  turretv->setMatrix( turrettm * tm );
475  forcesensor->updateJointInfo();
476  if ((attachdev != NULL) && (attachdevjoint != NULL)) {
477  attachdev->setMatrix( attachdevtm * tm );
478  attachdevjoint->updateJointInfo();
479  }
480 }
481 
482 namespace previous {
483  const real PhyMarXbot::basex = 0.034f;
484  const real PhyMarXbot::basey = 0.143f;
485  const real PhyMarXbot::basez = 0.048f;
486  const real PhyMarXbot::basem = 0.4f;
487  const real PhyMarXbot::bodyr = 0.085f;
488  const real PhyMarXbot::bodyh = 0.0055f;
489  const real PhyMarXbot::bodym = 0.02f;
490  const real PhyMarXbot::axledistance = 0.104f;
491  const real PhyMarXbot::trackradius = 0.022f;
492  const real PhyMarXbot::trackheight = 0.0295f;
493  const real PhyMarXbot::trackm = 0.05f;
494  const real PhyMarXbot::treaddepth = 0.004f;
495  const real PhyMarXbot::wheelr = 0.027f;
496  const real PhyMarXbot::wheelh = 0.0215f;
497  const real PhyMarXbot::wheelm = 0.02f;
498  const real PhyMarXbot::attachringh = 0.0285f;
499  const real PhyMarXbot::attachringm = 0.08f;
500  const real PhyMarXbot::ledsh = 0.010f;
501  const real PhyMarXbot::ledsradius = 0.080f;
502  const real PhyMarXbot::ledsm = 0.03f;
503 
504  PhyMarXbot::PhyMarXbot( World* w, QString name, const wMatrix& basetm ) : WObject( w, name, basetm, false ) {
505  kinematicSimulation = false;
506 
507  // --- reference frame
508  // X
509  // ^
510  // | ------
511  // | ______|____|_________
512  // | |_|_| track |_|_|_|_|
513  // | -------------------
514  // | | battery |
515  // | -------------------
516  // | |_|_| track |_|_|_|_|
517  // | | |
518  // | ------
519  // |
520  // ---------------------> Y
521  // The front of the robot is towards -Y (positive speeds of the wheel make the robot move towards -Y)
522 
523  // --- create material for the marXbot
524  // introducing a semplification for the collision: two robot collide only with the attachring
525  w->materials().createMaterial( "marXbotLowerBody" );
526  w->materials().setElasticity( "marXbotLowerBody", "default", 0.01f );
527  w->materials().setSoftness( "marXbotLowerBody", "default", 0.01f );
528  w->materials().createMaterial( "marXbotUpperBody" );
529  w->materials().enableCollision( "marXbotLowerBody", "marXbotLowerBody", false );
530  w->materials().enableCollision( "marXbotLowerBody", "marXbotUpperBody", false );
531 
532  QVector<PhyObject*> objs;
533  PhyObject* obj;
534  // --- create the body of the base of the marxbot
535  #ifdef MARXBOT_DETAILED
537  // battery container
538  obj = new PhyBox( basex, basey, basez, w );
539  tm.w_pos[2] = basez/2.0f + 0.015f;
540  obj->setMass( basem );
541  obj->setMatrix( tm );
542  objs << obj;
543  // cylinder body
544  obj = new PhyCylinder( bodyr, bodyh, w );
545  obj->setMass( bodym );
546  tm = wMatrix::yaw( toRad(90.0f) );
547  tm.w_pos[2] = 0.015f + basez + bodyh/2.0f;
548  obj->setMatrix( tm );
549  objs << obj;
550  // right track
551  obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
552  tm = wMatrix::identity();
553  tm.w_pos[0] = (basex + trackheight)/2.0f;
554  tm.w_pos[2] = trackradius + treaddepth;
555  obj->setMass( trackm );
556  obj->setMatrix( tm );
557  objs << obj;
558  obj = new PhyCylinder( trackradius, trackheight, w );
559  obj->setMass( wheelm );
560  tm.w_pos[1] = axledistance/2.0;
561  obj->setMatrix( tm );
562  objs << obj;
563  obj = new PhyCylinder( trackradius, trackheight, w );
564  obj->setMass( wheelm );
565  tm.w_pos[1] = -axledistance/2.0;
566  obj->setMatrix( tm );
567  objs << obj;
568  // left track
569  obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
570  tm = wMatrix::identity();
571  tm.w_pos[0] = -(basex + trackheight)/2.0f;
572  tm.w_pos[2] = trackradius + treaddepth;
573  obj->setMass( trackm );
574  obj->setMatrix( tm );
575  objs << obj;
576  obj = new PhyCylinder( trackradius, trackheight, w );
577  obj->setMass( wheelm );
578  tm.w_pos[1] = axledistance/2.0;
579  obj->setMatrix( tm );
580  objs << obj;
581  obj = new PhyCylinder( trackradius, trackheight, w );
582  obj->setMass( wheelm );
583  tm.w_pos[1] = -axledistance/2.0;
584  obj->setMatrix( tm );
585  objs << obj;
586  #else
587  // simplified version of the marxbot physic
588  obj = new PhyBox( basex+2.0f*trackheight, axledistance, basez+trackradius*2.0f, w );
589  obj->setMass( basem+bodym );
590  tm = wMatrix::identity();
591  tm.w_pos[2] = (basez+trackradius*2.0f)/2.0f + treaddepth;
592  obj->setMatrix( tm );
593  objs << obj;
594  #endif
595  // merge all togheter
596  base = new PhyCompoundObject( objs, w, "base" );
597  base->setMatrix( basetm );
598  base->setMaterial("marXbotLowerBody");
599  base->setOwner( this, false );
600 
601  // --- create the two external wheels
602  // they are motorized and they move the robot
603  // and create four spheres for supporting the tracks
604  // NOTE: the tracks are not simulated, they are just rigid bodies and
605  // the four sphere move freely in order to approximate the real movement
606  // --- position of wheels and their IDs in the vector
607  // +-----+
608  // |3|| ||2|
609  // |1| | | |0|
610  // |5|| ||4|
611  // +-----+
612  // --------------------> X
613  // arrays of X and Y offsets for calculate the positions
614  double xoffs[6] = { 1, -1, 1, -1, 1, -1 };
615  double yoffs[6] = { 0, 0, 1, 1, -1, -1 };
616  PhyObject* awheel;
617  PhyJoint* joint;
618  for( int i=0; i<6; i++ ) {
619  // --- relative to base
620  wMatrix wtm = wMatrix::identity();
621  wtm.w_pos = wVector(
622  xoffs[i] * (basex + trackheight)/2.0f + (yoffs[i]==0 ? xoffs[i]*(trackheight/2.0+wheelh/2.0f+0.006f) : 0.0f),
623  yoffs[i] * (axledistance/2.0f),
624  0.0f );
625  if ( i<2 ) {
626  // the two motorized wheels
627  wtm.w_pos[2] = wheelr;
628  awheel = new PhyCylinder( wheelr, wheelh, w, "motorWheel" );
629  } else {
630  // the four sphere supporting the track
631  wtm.w_pos[2] = treaddepth-0.003f;
632  awheel = new PhySphere( treaddepth, w, "passiveWheel" );
633  }
634  wheelstm.append( wtm );
635  awheel->setMass( wheelm );
636  awheel->setColor( Qt::blue );
637  awheel->setMaterial( "marXbotLowerBody" );
638  awheel->setOwner( this, false );
639  awheel->setMatrix( wtm * basetm );
640  wheels.append( awheel );
641 
642  //--- create the joints
643  if ( i<2 ) {
644  // the two motorized wheels
645  joint = new PhySuspension(
646  base->matrix().x_ax, // rotation axis
647  wheels[i]->matrix().w_pos,
648  base->matrix().z_ax, // suspension 'vertical' axis
649  base, wheels[i] );
650  joint->dofs()[0]->disableLimits();
651  } else {
652  // the four sphere supporting the track
653  joint = new PhyBallAndSocket(
654  wheels[i]->matrix().w_pos,
655  base, wheels[i] );
656  }
657  joint->setOwner( this, false );
658  joint->updateJointInfo();
659  wheelJoints.append( joint );
660  }
661 
662  // --- create the attachment module with the 12 RGB LEDs part
663  #ifdef MARXBOT_DETAILED
664  objs.clear();
665  obj = new PhyCone( bodyr, attachringh+0.010f, w );
666  obj->setMass( attachringm );
667  tm = wMatrix::identity();
668  tm.w_pos[0] = 0.005f;
669  obj->setMatrix( tm );
670  objs << obj;
671  obj = new PhyCone( bodyr, attachringh+0.010f, w );
672  obj->setMass( attachringm );
673  tm = wMatrix::roll( toRad(180.0f) );
674  tm.w_pos[0] = -0.005f;
675  obj->setMatrix( tm );
676  objs << obj;
677  obj = new PhyCylinder( ledsradius, ledsh, w );
678  obj->setMass( ledsm );
679  obj->setTexture( "marXbot_12leds" );
680  obj->setUseColorTextureOfOwner( false );
681  tm.w_pos[0] = attachringh/2.0f + ledsh/2.0f + 0.0015f;
682  obj->setMatrix( tm );
683  objs << obj;
684  #else
685  objs.clear();
686  obj = new PhyCylinder( bodyr, attachringh+ledsh, w );
687  obj->setMass( attachringm );
688  tm = wMatrix::identity();
689  tm.w_pos[0] = attachringh/2.0f-0.010f;
690  obj->setMatrix( tm );
691  objs << obj;
692  #endif
693  // merge all toghether
694  attachring = new PhyCompoundObject( objs, w );
695  attachring->setMaterial("marXbotUpperBody");
696  attachring->setOwner( this, false );
697  attachring->setUseColorTextureOfOwner( false );
698  attachringtm = wMatrix::yaw( toRad(-90.0f) );
699  attachringtm.w_pos[2] = 0.015f + basez + bodyh + attachringh/2.0f + 0.0015f;
700  attachring->setMatrix( attachringtm * basetm );
701  // --- create the joint for sensing the force
702  forcesensor = new PhyFixed( base, attachring, w );
703  forcesensor->setOwner( this, false );
704 
705  // create the motor controller
706  QVector<PhyDOF*> motors;
707  motors << wheelJoints[0]->dofs()[0] << wheelJoints[1]->dofs()[0];
708  wheelsCtrl = new WheelMotorController( motors, w );
709  wheelsCtrl->setOwner( this, false );
710  #ifdef __GNUC__
711  #warning QUI DECIDERE PER LE VELOCITÀ MASSIME E MINIME DELLE RUOTE
712  #endif
713  wheelsCtrl->setSpeedLimits( -10.0, -10.0, 10.0, 10.0 );
714 
715  // Connecting wheels speed signals to be able to move the robot when in kinematic
716  connect(wheelJoints[0]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setRightWheelDesideredVelocity(real)));
717  connect(wheelJoints[1]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setLeftWheelDesideredVelocity(real)));
718 
719  // Creating the proximity IR sensors
720  QVector<SingleIR> sensors;
721 
722  #ifdef __GNUC__
723  #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI (SPECIE PER I GROUND)
724  #endif
725  // Adding the sensors. The marxbot has 24 proximity infrared sensors
726  for (unsigned int i = 0; i < 24; i++) {
727  const double curAngle = double(i) * (360.0 / 24.0) + ((360.0 / 24.0) / 2.0);
728  const double radius = bodyr;
729 
730  wMatrix mtr = wMatrix::yaw(deg2rad(curAngle + 90.0)) * wMatrix::pitch(deg2rad(90.0f));
731  mtr.w_pos.x = radius * cos(deg2rad(curAngle));
732  mtr.w_pos.y = radius * sin(deg2rad(curAngle));
733  mtr.w_pos.z = 0.015f + basez + bodyh/2.0f;
734 
735  sensors.append(SingleIR(base, mtr, 0.02, 0.1, 10.0, 5));
736  }
737  proximityIR = new SimulatedIRProximitySensorController(world(), sensors);
738 
739  // Now creating the ground IR sensors below the battery pack
740  sensors.clear();
741  wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
742  const double distFromBorder = 0.003;
743 
744  // Adding the sensors. The marxbot has 4 ground infrared sensors below the battery pack
745  mtr.w_pos = wVector(basex / 2.0f - distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
746  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
747  mtr.w_pos = wVector(basex / 2.0f - distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
748  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
749  mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
750  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
751  mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
752  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
753  groundBottomIR = new SimulatedIRGroundSensorController(world(), sensors);
754 
755  // Creating the ground IR sensors below the base
756  sensors.clear();
757 
758  // Adding the sensors. The marxbot has 8 ground infrared sensors below the base
759  for (unsigned int i = 0; i < 8; i++) {
760  const double curAngle = double(i) * (360.0 / 8.0);
761  const double radius = bodyr - 0.003;
762 
763  wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
764  mtr.w_pos.x = radius * cos(deg2rad(curAngle));
765  mtr.w_pos.y = radius * sin(deg2rad(curAngle));
766  mtr.w_pos.z = 0.015f + basez;
767 
768  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
769  }
770  groundAroundIR = new SimulatedIRGroundSensorController(world(), sensors);
771 
772  // Creating the traction sensor
773  tractionSensor = new TractionSensorController(world(), *forcesensor);
774 
775  w->pushObject( this );
776  }
777 
779  foreach( PhyJoint* susp, wheelJoints ) {
780  delete susp;
781  }
782  foreach( PhyObject* w, wheels ) {
783  delete w;
784  }
785  delete wheelsCtrl;
786  delete forcesensor;
787  delete attachring;
788  delete base;
789  delete proximityIR;
790  delete groundBottomIR;
791  delete groundAroundIR;
792  }
793 
795  {
796  // Updating motors
797  if (wheelsCtrl->isEnabled()) {
798  wheelsCtrl->update();
799  }
800 
801  if (kinematicSimulation) {
802  // In kinematic mode, we have to manually move the robot depending on the wheel velocities
803  wMatrix mtr = matrix();
804  wheeledRobotsComputeKinematicMovement(mtr, leftWheelVelocity, rightWheelVelocity, wheelr, wheelstm[0].w_pos.x - wheelstm[1].w_pos.x, world()->timeStep());
805 
806  // This will also update the position of all pieces
807  setMatrix(mtr);
808  }
809  }
810 
812  {
813  // Updating sensors
814  if (proximityIR->isEnabled()) {
815  proximityIR->update();
816  }
817  if (groundBottomIR->isEnabled()) {
818  groundBottomIR->update();
819  }
820  if (groundAroundIR->isEnabled()) {
821  groundAroundIR->update();
822  }
823 
824  // Updating the transformation matrix of the robot. It is coincident with the matrix of the base
825  tm = base->matrix();
826  }
827 
828  void PhyMarXbot::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
829  {
830  proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
831  }
832 
833  void PhyMarXbot::setGroundBottomIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
834  {
835  groundBottomIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
836  }
837 
838  void PhyMarXbot::setGroundAroundIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
839  {
840  groundAroundIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
841  }
842 
844  {
845  if (kinematicSimulation == k) {
846  return;
847  }
848 
849  kinematicSimulation = k;
850  if (kinematicSimulation) {
851  // First disabling all joints...
852  for (int i = 0; i < wheelJoints.size(); i++) {
853  wheelJoints[i]->enable(false);
854  }
855  forcesensor->enable(false);
856 
857  // ... then setting all objects to kinematic behaviour
858  base->setKinematic(true, true);
859  for (int i = 0; i < wheels.size(); i++) {
860  wheels[i]->setKinematic(true, true);
861  }
862  attachring->setKinematic(true, true);
863  } else {
864  // First setting all objects to dynamic behaviour...
865  base->setKinematic(false);
866  for (int i = 0; i < wheels.size(); i++) {
867  wheels[i]->setKinematic(false);
868  }
869  attachring->setKinematic(false);
870 
871  // ... then enabling all joints (if the corresponding part is enabled)
872  for (int i = 0; i < wheelJoints.size(); i++) {
873  wheelJoints[i]->enable(true);
874  wheelJoints[i]->updateJointInfo();
875  }
876  forcesensor->enable(true);
877  forcesensor->updateJointInfo();
878  }
879  }
880 
882  {
883  leftWheelVelocity = velocity;
884  }
885 
887  {
888  rightWheelVelocity = velocity;
889  }
890 
892  wMatrix tm = matrix();
893  base->setMatrix( tm );
894  for( int i=0; i<wheels.size(); i++ ) {
895  wheels[i]->setMatrix( wheelstm[i] * tm );
896  }
897  foreach( PhyJoint* ajoint, wheelJoints ) {
898  ajoint->updateJointInfo();
899  }
900  attachring->setMatrix( attachringtm * tm );
901  forcesensor->updateJointInfo();
902  }
903 }
904 
905 } // end namespace farsa