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 (kinematicSimulation == k) {
398  return;
399  }
400 
401  kinematicSimulation = k;
402  if (kinematicSimulation) {
403  // First disabling all joints...
404  for (int i = 0; i < wheelJoints.size(); i++) {
405  wheelJoints[i]->enable(false);
406  }
407  forcesensor->enable(false);
408  if (attachdevjoint != NULL) {
409  attachdevjoint->enable(false);
410  }
411 
412  // ... then setting all objects to kinematic behaviour
413  basev->setKinematic(true, true);
414  for (int i = 0; i < wheels.size(); i++) {
415  wheels[i]->setKinematic(true, true);
416  }
417  turretv->setKinematic(true, true);
418  if (attachdev != NULL) {
419  attachdev->setKinematic(true, true);
420  }
421  } else {
422  // First setting all objects to dynamic behaviour...
423  basev->setKinematic(false);
424  for (int i = 0; i < wheels.size(); i++) {
425  wheels[i]->setKinematic(false);
426  }
427  turretv->setKinematic(false);
428  if (attachdev != NULL) {
429  attachdev->setKinematic(false);
430  }
431 
432  // ... then enabling all joints (if the corresponding part is enabled)
433  for (int i = 0; i < wheelJoints.size(); i++) {
434  wheelJoints[i]->enable(true);
435  wheelJoints[i]->updateJointInfo();
436  }
437  forcesensor->enable(true);
438  forcesensor->updateJointInfo();
439  if (attachdevjoint != NULL) {
440  attachdevjoint->enable(true);
441  attachdevjoint->updateJointInfo();
442  }
443  }
444 }
445 
447 {
448  leftWheelVelocity = velocity;
449 }
450 
452 {
453  rightWheelVelocity = velocity;
454 }
455 
457  wMatrix tm = matrix();
458  basev->setMatrix( tm );
459  for( int i=0; i<wheels.size(); i++ ) {
460  wheels[i]->setMatrix( wheelstm[i] * tm );
461  }
462  foreach( PhyJoint* ajoint, wheelJoints ) {
463  ajoint->updateJointInfo();
464  }
465  turretv->setMatrix( turrettm * tm );
466  forcesensor->updateJointInfo();
467  if ((attachdev != NULL) && (attachdevjoint != NULL)) {
468  attachdev->setMatrix( attachdevtm * tm );
469  attachdevjoint->updateJointInfo();
470  }
471 }
472 
473 namespace previous {
474  const real PhyMarXbot::basex = 0.034f;
475  const real PhyMarXbot::basey = 0.143f;
476  const real PhyMarXbot::basez = 0.048f;
477  const real PhyMarXbot::basem = 0.4f;
478  const real PhyMarXbot::bodyr = 0.085f;
479  const real PhyMarXbot::bodyh = 0.0055f;
480  const real PhyMarXbot::bodym = 0.02f;
481  const real PhyMarXbot::axledistance = 0.104f;
482  const real PhyMarXbot::trackradius = 0.022f;
483  const real PhyMarXbot::trackheight = 0.0295f;
484  const real PhyMarXbot::trackm = 0.05f;
485  const real PhyMarXbot::treaddepth = 0.004f;
486  const real PhyMarXbot::wheelr = 0.027f;
487  const real PhyMarXbot::wheelh = 0.0215f;
488  const real PhyMarXbot::wheelm = 0.02f;
489  const real PhyMarXbot::attachringh = 0.0285f;
490  const real PhyMarXbot::attachringm = 0.08f;
491  const real PhyMarXbot::ledsh = 0.010f;
492  const real PhyMarXbot::ledsradius = 0.080f;
493  const real PhyMarXbot::ledsm = 0.03f;
494 
495  PhyMarXbot::PhyMarXbot( World* w, QString name, const wMatrix& basetm ) : WObject( w, name, basetm, false ) {
496  kinematicSimulation = false;
497 
498  // --- reference frame
499  // X
500  // ^
501  // | ------
502  // | ______|____|_________
503  // | |_|_| track |_|_|_|_|
504  // | -------------------
505  // | | battery |
506  // | -------------------
507  // | |_|_| track |_|_|_|_|
508  // | | |
509  // | ------
510  // |
511  // ---------------------> Y
512  // The front of the robot is towards -Y (positive speeds of the wheel make the robot move towards -Y)
513 
514  // --- create material for the marXbot
515  // introducing a semplification for the collision: two robot collide only with the attachring
516  w->materials().createMaterial( "marXbotLowerBody" );
517  w->materials().setElasticity( "marXbotLowerBody", "default", 0.01f );
518  w->materials().setSoftness( "marXbotLowerBody", "default", 0.01f );
519  w->materials().createMaterial( "marXbotUpperBody" );
520  w->materials().enableCollision( "marXbotLowerBody", "marXbotLowerBody", false );
521  w->materials().enableCollision( "marXbotLowerBody", "marXbotUpperBody", false );
522 
523  QVector<PhyObject*> objs;
524  PhyObject* obj;
525  // --- create the body of the base of the marxbot
526  #ifdef MARXBOT_DETAILED
528  // battery container
529  obj = new PhyBox( basex, basey, basez, w );
530  tm.w_pos[2] = basez/2.0f + 0.015f;
531  obj->setMass( basem );
532  obj->setMatrix( tm );
533  objs << obj;
534  // cylinder body
535  obj = new PhyCylinder( bodyr, bodyh, w );
536  obj->setMass( bodym );
537  tm = wMatrix::yaw( toRad(90.0f) );
538  tm.w_pos[2] = 0.015f + basez + bodyh/2.0f;
539  obj->setMatrix( tm );
540  objs << obj;
541  // right track
542  obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
543  tm = wMatrix::identity();
544  tm.w_pos[0] = (basex + trackheight)/2.0f;
545  tm.w_pos[2] = trackradius + treaddepth;
546  obj->setMass( trackm );
547  obj->setMatrix( tm );
548  objs << obj;
549  obj = new PhyCylinder( trackradius, trackheight, w );
550  obj->setMass( wheelm );
551  tm.w_pos[1] = axledistance/2.0;
552  obj->setMatrix( tm );
553  objs << obj;
554  obj = new PhyCylinder( trackradius, trackheight, w );
555  obj->setMass( wheelm );
556  tm.w_pos[1] = -axledistance/2.0;
557  obj->setMatrix( tm );
558  objs << obj;
559  // left track
560  obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
561  tm = wMatrix::identity();
562  tm.w_pos[0] = -(basex + trackheight)/2.0f;
563  tm.w_pos[2] = trackradius + treaddepth;
564  obj->setMass( trackm );
565  obj->setMatrix( tm );
566  objs << obj;
567  obj = new PhyCylinder( trackradius, trackheight, w );
568  obj->setMass( wheelm );
569  tm.w_pos[1] = axledistance/2.0;
570  obj->setMatrix( tm );
571  objs << obj;
572  obj = new PhyCylinder( trackradius, trackheight, w );
573  obj->setMass( wheelm );
574  tm.w_pos[1] = -axledistance/2.0;
575  obj->setMatrix( tm );
576  objs << obj;
577  #else
578  // simplified version of the marxbot physic
579  obj = new PhyBox( basex+2.0f*trackheight, axledistance, basez+trackradius*2.0f, w );
580  obj->setMass( basem+bodym );
581  tm = wMatrix::identity();
582  tm.w_pos[2] = (basez+trackradius*2.0f)/2.0f + treaddepth;
583  obj->setMatrix( tm );
584  objs << obj;
585  #endif
586  // merge all togheter
587  base = new PhyCompoundObject( objs, w, "base" );
588  base->setMatrix( basetm );
589  base->setMaterial("marXbotLowerBody");
590  base->setOwner( this, false );
591 
592  // --- create the two external wheels
593  // they are motorized and they move the robot
594  // and create four spheres for supporting the tracks
595  // NOTE: the tracks are not simulated, they are just rigid bodies and
596  // the four sphere move freely in order to approximate the real movement
597  // --- position of wheels and their IDs in the vector
598  // +-----+
599  // |3|| ||2|
600  // |1| | | |0|
601  // |5|| ||4|
602  // +-----+
603  // --------------------> X
604  // arrays of X and Y offsets for calculate the positions
605  double xoffs[6] = { 1, -1, 1, -1, 1, -1 };
606  double yoffs[6] = { 0, 0, 1, 1, -1, -1 };
607  PhyObject* awheel;
608  PhyJoint* joint;
609  for( int i=0; i<6; i++ ) {
610  // --- relative to base
611  wMatrix wtm = wMatrix::identity();
612  wtm.w_pos = wVector(
613  xoffs[i] * (basex + trackheight)/2.0f + (yoffs[i]==0 ? xoffs[i]*(trackheight/2.0+wheelh/2.0f+0.006f) : 0.0f),
614  yoffs[i] * (axledistance/2.0f),
615  0.0f );
616  if ( i<2 ) {
617  // the two motorized wheels
618  wtm.w_pos[2] = wheelr;
619  awheel = new PhyCylinder( wheelr, wheelh, w, "motorWheel" );
620  } else {
621  // the four sphere supporting the track
622  wtm.w_pos[2] = treaddepth-0.003f;
623  awheel = new PhySphere( treaddepth, w, "passiveWheel" );
624  }
625  wheelstm.append( wtm );
626  awheel->setMass( wheelm );
627  awheel->setColor( Qt::blue );
628  awheel->setMaterial( "marXbotLowerBody" );
629  awheel->setOwner( this, false );
630  awheel->setMatrix( wtm * basetm );
631  wheels.append( awheel );
632 
633  //--- create the joints
634  if ( i<2 ) {
635  // the two motorized wheels
636  joint = new PhySuspension(
637  base->matrix().x_ax, // rotation axis
638  wheels[i]->matrix().w_pos,
639  base->matrix().z_ax, // suspension 'vertical' axis
640  base, wheels[i] );
641  joint->dofs()[0]->disableLimits();
642  } else {
643  // the four sphere supporting the track
644  joint = new PhyBallAndSocket(
645  wheels[i]->matrix().w_pos,
646  base, wheels[i] );
647  }
648  joint->setOwner( this, false );
649  joint->updateJointInfo();
650  wheelJoints.append( joint );
651  }
652 
653  // --- create the attachment module with the 12 RGB LEDs part
654  #ifdef MARXBOT_DETAILED
655  objs.clear();
656  obj = new PhyCone( bodyr, attachringh+0.010f, w );
657  obj->setMass( attachringm );
658  tm = wMatrix::identity();
659  tm.w_pos[0] = 0.005f;
660  obj->setMatrix( tm );
661  objs << obj;
662  obj = new PhyCone( bodyr, attachringh+0.010f, w );
663  obj->setMass( attachringm );
664  tm = wMatrix::roll( toRad(180.0f) );
665  tm.w_pos[0] = -0.005f;
666  obj->setMatrix( tm );
667  objs << obj;
668  obj = new PhyCylinder( ledsradius, ledsh, w );
669  obj->setMass( ledsm );
670  obj->setTexture( "marXbot_12leds" );
671  obj->setUseColorTextureOfOwner( false );
672  tm.w_pos[0] = attachringh/2.0f + ledsh/2.0f + 0.0015f;
673  obj->setMatrix( tm );
674  objs << obj;
675  #else
676  objs.clear();
677  obj = new PhyCylinder( bodyr, attachringh+ledsh, w );
678  obj->setMass( attachringm );
679  tm = wMatrix::identity();
680  tm.w_pos[0] = attachringh/2.0f-0.010f;
681  obj->setMatrix( tm );
682  objs << obj;
683  #endif
684  // merge all toghether
685  attachring = new PhyCompoundObject( objs, w );
686  attachring->setMaterial("marXbotUpperBody");
687  attachring->setOwner( this, false );
688  attachring->setUseColorTextureOfOwner( false );
689  attachringtm = wMatrix::yaw( toRad(-90.0f) );
690  attachringtm.w_pos[2] = 0.015f + basez + bodyh + attachringh/2.0f + 0.0015f;
691  attachring->setMatrix( attachringtm * basetm );
692  // --- create the joint for sensing the force
693  forcesensor = new PhyFixed( base, attachring, w );
694  forcesensor->setOwner( this, false );
695 
696  // create the motor controller
697  QVector<PhyDOF*> motors;
698  motors << wheelJoints[0]->dofs()[0] << wheelJoints[1]->dofs()[0];
699  wheelsCtrl = new WheelMotorController( motors, w );
700  wheelsCtrl->setOwner( this, false );
701  #ifdef __GNUC__
702  #warning QUI DECIDERE PER LE VELOCITÀ MASSIME E MINIME DELLE RUOTE
703  #endif
704  wheelsCtrl->setSpeedLimits( -10.0, -10.0, 10.0, 10.0 );
705 
706  // Connecting wheels speed signals to be able to move the robot when in kinematic
707  connect(wheelJoints[0]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setRightWheelDesideredVelocity(real)));
708  connect(wheelJoints[1]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setLeftWheelDesideredVelocity(real)));
709 
710  // Creating the proximity IR sensors
711  QVector<SingleIR> sensors;
712 
713  #ifdef __GNUC__
714  #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI (SPECIE PER I GROUND)
715  #endif
716  // Adding the sensors. The marxbot has 24 proximity infrared sensors
717  for (unsigned int i = 0; i < 24; i++) {
718  const double curAngle = double(i) * (360.0 / 24.0) + ((360.0 / 24.0) / 2.0);
719  const double radius = bodyr;
720 
721  wMatrix mtr = wMatrix::yaw(deg2rad(curAngle + 90.0)) * wMatrix::pitch(deg2rad(90.0f));
722  mtr.w_pos.x = radius * cos(deg2rad(curAngle));
723  mtr.w_pos.y = radius * sin(deg2rad(curAngle));
724  mtr.w_pos.z = 0.015f + basez + bodyh/2.0f;
725 
726  sensors.append(SingleIR(base, mtr, 0.02, 0.1, 10.0, 5));
727  }
728  proximityIR = new SimulatedIRProximitySensorController(world(), sensors);
729 
730  // Now creating the ground IR sensors below the battery pack
731  sensors.clear();
732  wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
733  const double distFromBorder = 0.003;
734 
735  // Adding the sensors. The marxbot has 4 ground infrared sensors below the battery pack
736  mtr.w_pos = wVector(basex / 2.0f - distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
737  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
738  mtr.w_pos = wVector(basex / 2.0f - distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
739  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
740  mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
741  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
742  mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
743  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
744  groundBottomIR = new SimulatedIRGroundSensorController(world(), sensors);
745 
746  // Creating the ground IR sensors below the base
747  sensors.clear();
748 
749  // Adding the sensors. The marxbot has 8 ground infrared sensors below the base
750  for (unsigned int i = 0; i < 8; i++) {
751  const double curAngle = double(i) * (360.0 / 8.0);
752  const double radius = bodyr - 0.003;
753 
754  wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
755  mtr.w_pos.x = radius * cos(deg2rad(curAngle));
756  mtr.w_pos.y = radius * sin(deg2rad(curAngle));
757  mtr.w_pos.z = 0.015f + basez;
758 
759  sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
760  }
761  groundAroundIR = new SimulatedIRGroundSensorController(world(), sensors);
762 
763  // Creating the traction sensor
764  tractionSensor = new TractionSensorController(world(), *forcesensor);
765 
766  w->pushObject( this );
767  }
768 
770  foreach( PhyJoint* susp, wheelJoints ) {
771  delete susp;
772  }
773  foreach( PhyObject* w, wheels ) {
774  delete w;
775  }
776  delete wheelsCtrl;
777  delete forcesensor;
778  delete attachring;
779  delete base;
780  delete proximityIR;
781  delete groundBottomIR;
782  delete groundAroundIR;
783  }
784 
786  {
787  // Updating motors
788  if (wheelsCtrl->isEnabled()) {
789  wheelsCtrl->update();
790  }
791 
792  if (kinematicSimulation) {
793  // In kinematic mode, we have to manually move the robot depending on the wheel velocities
794  wMatrix mtr = matrix();
795  wheeledRobotsComputeKinematicMovement(mtr, leftWheelVelocity, rightWheelVelocity, wheelr, wheelstm[0].w_pos.x - wheelstm[1].w_pos.x, world()->timeStep());
796 
797  // This will also update the position of all pieces
798  setMatrix(mtr);
799  }
800  }
801 
803  {
804  // Updating sensors
805  if (proximityIR->isEnabled()) {
806  proximityIR->update();
807  }
808  if (groundBottomIR->isEnabled()) {
809  groundBottomIR->update();
810  }
811  if (groundAroundIR->isEnabled()) {
812  groundAroundIR->update();
813  }
814 
815  // Updating the transformation matrix of the robot. It is coincident with the matrix of the base
816  tm = base->matrix();
817  }
818 
819  void PhyMarXbot::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
820  {
821  proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
822  }
823 
824  void PhyMarXbot::setGroundBottomIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
825  {
826  groundBottomIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
827  }
828 
829  void PhyMarXbot::setGroundAroundIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
830  {
831  groundAroundIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
832  }
833 
835  {
836  if (kinematicSimulation == k) {
837  return;
838  }
839 
840  kinematicSimulation = k;
841  if (kinematicSimulation) {
842  // First disabling all joints...
843  for (int i = 0; i < wheelJoints.size(); i++) {
844  wheelJoints[i]->enable(false);
845  }
846  forcesensor->enable(false);
847 
848  // ... then setting all objects to kinematic behaviour
849  base->setKinematic(true, true);
850  for (int i = 0; i < wheels.size(); i++) {
851  wheels[i]->setKinematic(true, true);
852  }
853  attachring->setKinematic(true, true);
854  } else {
855  // First setting all objects to dynamic behaviour...
856  base->setKinematic(false);
857  for (int i = 0; i < wheels.size(); i++) {
858  wheels[i]->setKinematic(false);
859  }
860  attachring->setKinematic(false);
861 
862  // ... then enabling all joints (if the corresponding part is enabled)
863  for (int i = 0; i < wheelJoints.size(); i++) {
864  wheelJoints[i]->enable(true);
865  wheelJoints[i]->updateJointInfo();
866  }
867  forcesensor->enable(true);
868  forcesensor->updateJointInfo();
869  }
870  }
871 
873  {
874  leftWheelVelocity = velocity;
875  }
876 
878  {
879  rightWheelVelocity = velocity;
880  }
881 
883  wMatrix tm = matrix();
884  base->setMatrix( tm );
885  for( int i=0; i<wheels.size(); i++ ) {
886  wheels[i]->setMatrix( wheelstm[i] * tm );
887  }
888  foreach( PhyJoint* ajoint, wheelJoints ) {
889  ajoint->updateJointInfo();
890  }
891  attachring->setMatrix( attachringtm * tm );
892  forcesensor->updateJointInfo();
893  }
894 }
895 
896 } // end namespace farsa