phyepuck.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 "phyepuck.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 "mathutils.h"
32 #include "graphicalmarkers.h"
33 #include <cmath>
34 
35 namespace farsa {
36 
37 // All measures have been taken on the LARAL e-puck or the official specifications. Lengths are in
38 // meters, weights in kilograms.
39 const real PhyEpuck::batteryplacex = 0.043f;
40 const real PhyEpuck::batteryplacey = 0.055f;
41 const real PhyEpuck::batteryplacez = 0.033f;
42 const real PhyEpuck::batterym = 0.042f;
43 const real PhyEpuck::batteryplacedistancefromground = 0.0015f;
44 const real PhyEpuck::bodyr = 0.035f;
45 const real PhyEpuck::bodyh = 0.021f;
46 const real PhyEpuck::wholebodym = 0.078f;
47 const real PhyEpuck::wheelr = 0.0205f;
48 const real PhyEpuck::wheelh = 0.003f;
49 const real PhyEpuck::wheelm = 0.010f;
50 const real PhyEpuck::axletrack = 0.053f;
51 const real PhyEpuck::passivewheelr = 0.005f;
52 const real PhyEpuck::passivewheelm = 0.005f;
53 
54 PhyEpuck::PhyEpuck(World* world, QString name, const wMatrix& transformation) :
55  WObject(world, name, transformation, false),
56  m_body(NULL),
57  m_wheels(),
58  m_wheelsTransformation(),
59  m_wheelJoints(),
60  m_wheelsCtrl(NULL),
61  m_proximityIR(NULL),
62  m_groundIR(NULL),
63  m_kinematicSimulation(false),
64  m_leftWheelVelocity(0.0f),
65  m_rightWheelVelocity(0.0f),
66  m_frontMarker(NULL)
67 {
68  // --- reference frame
69  // X
70  // ^
71  // | ------
72  // | | |
73  // | -------------------
74  // | | battery |
75  // | | |
76  // | -------------------
77  // | | |
78  // | ------
79  // |
80  // +---------------------> Y
81  // The front of the robot is towards -Y (positive speeds of the wheel make the robot move towards -Y)
82  // and the camera is in -Y
83 
84  // Creating a material for the e-puck
85  world->materials().createMaterial("epuckMaterial");
86  world->materials().setProperties("epuckMaterial", "default", 0.0f, 0.0f, 0.01f, 0.01f, true);
87  world->materials().createMaterial("epuckTire");
88  world->materials().setProperties("epuckTire", "default", 1.2f, 0.9f, 0.01f, 0.01f, true);
89 
90  // Now creating the body of the e-puck. It is made up of two pieces: a box modelling the battery
91  // pack and a short cylinder modelling the upper part (where the electronic board is). We put the
92  // frame of reference of the body (which is equal to that of the whole robot) on the ground to have
93  // move stability and to simplify moving the robot (no need to apply displacements to put it on a
94  // plane)
95  {
96  QVector<PhyObject*> bodyObjs;
98  // First we create the battery pack
100  tm.w_pos.z = (batteryplacez / 2.0f) + batteryplacedistancefromground;
101  obj->setMatrix(tm);
102  bodyObjs << obj;
103  // Then we create the upper part
104  obj = new PhyCylinder(bodyr, bodyh, world);
105  tm = wMatrix::yaw(toRad(90.0f));
106  tm.w_pos.z = batteryplacez + batteryplacedistancefromground + (bodyh / 2.0f);
107  obj->setMatrix( tm );
108  bodyObjs << obj;
109  // Finally we create the compound object actually modelling the body
110  m_body = new PhyCompoundObject(bodyObjs, world, "base");
111  m_body->setMass(batterym + wholebodym);
112  m_body->setMaterial("epuckMaterial");
113  m_body->setOwner(this, false);
114  m_body->setMatrix(transformation);
115  }
116 
117  // Creating all the wheels. We first create the two motorized wheels and then the two passive ones.
118  // The position of the wheels and their indexes are as follows (remember that the front of the
119  // robot is towards -Y):
120  //
121  // X
122  // ^
123  // | ------
124  // | | 0 |
125  // | -------------------
126  // | | battery |
127  // | | 3 2 |
128  // | -------------------
129  // | | 1 |
130  // | ------
131  // |
132  // +---------------------> Y
133 
134  // Creating the first motorized wheel and its joint
135  {
136  // The matrix is relative to the base. First creating the wheel
138  tm.w_pos = wVector(axletrack / 2.0f, 0.0f, wheelr);
139  PhyObject* wheel = new PhyCylinder(wheelr, wheelh, world, "motorWheel");
140  wheel->setMass(wheelm);
141  wheel->setColor(Qt::blue);
142  wheel->setMaterial("epuckTire");
143  wheel->setOwner(this, false);
144  wheel->setMatrix(tm * m_body->matrix());
145  m_wheels.append(wheel);
146  m_wheelsTransformation.append(tm);
147 
148  // Now creating the joint
149  PhyJoint* joint = new PhySuspension(m_body->matrix().x_ax, wheel->matrix().w_pos, m_body->matrix().z_ax, m_body, wheel);
150  joint->dofs()[0]->disableLimits();
151  joint->setOwner(this, false);
152  joint->updateJointInfo();
153  m_wheelJoints.append(joint);
154  }
155 
156  // Creating the second motorized wheel and its joint
157  {
158  // The matrix is relative to the base. First creating the wheel
160  tm.w_pos = wVector(-axletrack / 2.0f, 0.0f, wheelr);
161  PhyObject* wheel = new PhyCylinder(wheelr, wheelh, world, "motorWheel");
162  wheel->setMass(wheelm);
163  wheel->setColor(Qt::blue);
164  wheel->setMaterial("epuckTire");
165  wheel->setOwner(this, false);
166  wheel->setMatrix(tm * m_body->matrix());
167  m_wheels.append(wheel);
168  m_wheelsTransformation.append(tm);
169 
170  // Now creating the joint
171  PhyJoint* joint = new PhySuspension(m_body->matrix().x_ax, wheel->matrix().w_pos, m_body->matrix().z_ax, m_body, wheel);
172  joint->dofs()[0]->disableLimits();
173  joint->setOwner(this, false);
174  joint->updateJointInfo();
175  m_wheelJoints.append(joint);
176  }
177 
178  // Creating the first passive wheel and its joint
179  {
180  // The matrix is relative to the base. First creating the wheel
182  tm.w_pos = wVector(0.0f, (batteryplacey / 2.0f) - passivewheelr, passivewheelr);
183  PhyObject* wheel = new PhySphere(passivewheelr, world, "passiveWheel");
184  wheel->setMass(passivewheelm);
185  wheel->setColor(Qt::blue);
186  wheel->setMaterial("epuckTire");
187  wheel->setOwner(this, false);
188  wheel->setMatrix(tm * m_body->matrix());
189  m_wheels.append(wheel);
190  m_wheelsTransformation.append(tm);
191 
192  // Now creating the joint
193  PhyJoint* joint = new PhyBallAndSocket(wheel->matrix().w_pos, m_body, wheel);
194  joint->setOwner(this, false);
195  joint->updateJointInfo();
196  m_wheelJoints.append(joint);
197  }
198 
199  // Creating the second passive wheel and its joint
200  {
201  // The matrix is relative to the base. First creating the wheel
203  tm.w_pos = wVector(0.0f, -((batteryplacey / 2.0f) - passivewheelr), passivewheelr);
204  PhyObject* wheel = new PhySphere(passivewheelr, world, "passiveWheel");
205  wheel->setMass(passivewheelm);
206  wheel->setColor(Qt::blue);
207  wheel->setMaterial("epuckTire");
208  wheel->setOwner(this, false);
209  wheel->setMatrix(tm * m_body->matrix());
210  m_wheels.append(wheel);
211  m_wheelsTransformation.append(tm);
212 
213  // Now creating the joint
214  PhyJoint* joint = new PhyBallAndSocket(wheel->matrix().w_pos, m_body, wheel);
215  joint->setOwner(this, false);
216  joint->updateJointInfo();
217  m_wheelJoints.append(joint);
218  }
219 
220  // Now we can create the motor controller
221  QVector<PhyDOF*> motors;
222  motors << m_wheelJoints[0]->dofs()[0] << m_wheelJoints[1]->dofs()[0];
223  m_wheelsCtrl = new WheelMotorController(motors, world);
224  m_wheelsCtrl->setOwner(this, false);
225  // The min and max speed in rad/s have been derived for the e-puck wheel considering as maximum linear
226  // displacement 14 cm/s (that for the give wheel radius is approximately 1.1 ratations per second)
227  const real maxAngularSpeed = 1.1f * 2.0f * PI_GRECO;
228  m_wheelsCtrl->setSpeedLimits(-maxAngularSpeed, -maxAngularSpeed, maxAngularSpeed, maxAngularSpeed);
229 
230  // Connecting wheels speed signals to be able to move the robot when in kinematic
231  connect(m_wheelJoints[0]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setRightWheelDesideredVelocity(real)));
232  connect(m_wheelJoints[1]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setLeftWheelDesideredVelocity(real)));
233 
234  // Creating the proximity IR sensors
235  QVector<SingleIR> sensors;
236 
237 #ifdef __GNUC__
238  #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI
239 #endif
240  // Adding the sensors. The epuck has 8 proximity infrared sensors
241  const double sensorsAngles[] = {-90.0, -54.0, -18.0, 18.0, 54.0, 90.0, 150.0, 210.0};
242  for (unsigned int i = 0; i < 8; i++) {
243  const double curAngle = sensorsAngles[i] - 90.0; //double(i) * (360.0 / 8.0) + ((360.0 / 8.0) / 2.0);
244  const double radius = bodyr;
245 
246  wMatrix mtr = wMatrix::yaw(deg2rad(curAngle + 90.0)) * wMatrix::pitch(deg2rad(90.0f));
247  mtr.w_pos.x = radius * cos(deg2rad(curAngle));
248  mtr.w_pos.y = radius * sin(deg2rad(curAngle));
250 
251  sensors.append(SingleIR(m_body, mtr, 0.01, 0.05, 10.0, 5));
252  }
253  m_proximityIR = new SimulatedIRProximitySensorController(world, sensors);
254 
255  // Now creating the three ground IR sensors
256  sensors.clear();
257  wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
258 
259  // Adding the sensors. The e-puck has 3 ground infrared sensors in the front part
260  mtr.w_pos = wVector(-batteryplacex / 2.0f, -batteryplacey / 2.0f, batteryplacedistancefromground);
261  sensors.append(SingleIR(m_body, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
262  mtr.w_pos = wVector(0.0f, -batteryplacey / 2.0f, batteryplacedistancefromground);
263  sensors.append(SingleIR(m_body, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
265  sensors.append(SingleIR(m_body, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
266  m_groundIR = new SimulatedIRGroundSensorController(world, sensors);
267 
268  world->pushObject(this);
269 }
270 
272 {
273  foreach (PhyJoint* j, m_wheelJoints) {
274  delete j;
275  }
276  foreach (PhyObject* w, m_wheels) {
277  delete w;
278  }
279  delete m_wheelsCtrl;
280  delete m_body;
281  delete m_proximityIR;
282  delete m_groundIR;
283 }
284 
286 {
287  // Updating motors
288  if (m_wheelsCtrl->isEnabled()) {
289  m_wheelsCtrl->update();
290  }
291 
292  if (m_kinematicSimulation) {
293  // In kinematic mode, we have to manually move the robot depending on the wheel velocities
294  wMatrix mtr = matrix();
295  wheeledRobotsComputeKinematicMovement(mtr, m_leftWheelVelocity, m_rightWheelVelocity, wheelr, axletrack, world()->timeStep());
296 
297  // This will also update the position of all pieces
298  setMatrix(mtr);
299  }
300 }
301 
303 {
304  // Updating sensors
305  if (m_proximityIR->isEnabled()) {
306  m_proximityIR->update();
307  }
308  if (m_groundIR->isEnabled()) {
309  m_groundIR->update();
310  }
311 
312  // Updating the transformation matrix of the robot. It is coincident with the matrix of the body
313  tm = m_body->matrix();
314 }
315 
316 void PhyEpuck::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
317 {
318  m_proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
319 }
320 
321 void PhyEpuck::setGroundIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
322 {
323  m_groundIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
324 }
325 
326 void PhyEpuck::setDrawFrontMarker(bool drawMarker)
327 {
328  if (getDrawFrontMarker() == drawMarker) {
329  return;
330  }
331 
332  if (drawMarker) {
333  m_frontMarker = new PlanarArrowGraphicalMarker(bodyr, bodyr / 6.0f, bodyr / 4.0f, 0.7f, world());
334  m_frontMarker->setUseColorTextureOfOwner(false);
335  m_frontMarker->setColor(Qt::green);
336  m_frontMarker->setTexture("");
337 
338  wMatrix displacement = wMatrix::roll(-PI_GRECO / 2.0f);
339  displacement.w_pos = wVector(0.0, 0.0, batteryplacedistancefromground + batteryplacez + bodyh + 0.0001f);
340  m_frontMarker->attachToObject(this, true, displacement);
341  } else {
342  delete m_frontMarker;
343  m_frontMarker = NULL;
344  }
345 }
346 
348 {
349  return (m_frontMarker != NULL);
350 }
351 
353 {
354  if (m_kinematicSimulation == k) {
355  return;
356  }
357 
358  m_kinematicSimulation = k;
359  if (m_kinematicSimulation) {
360  // First disabling all joints...
361  for (int i = 0; i < m_wheelJoints.size(); i++) {
362  m_wheelJoints[i]->enable(false);
363  }
364 
365  // ... then setting all objects to kinematic behaviour
366  m_body->setKinematic(true, true);
367  for (int i = 0; i < m_wheels.size(); i++) {
368  m_wheels[i]->setKinematic(true, true);
369  }
370  } else {
371  // First setting all objects to dynamic behaviour...
372  m_body->setKinematic(false);
373  for (int i = 0; i < m_wheels.size(); i++) {
374  m_wheels[i]->setKinematic(false);
375  }
376 
377  // ... then enabling all joints (if the corresponding part is enabled)
378  for (int i = 0; i < m_wheelJoints.size(); i++) {
379  m_wheelJoints[i]->enable(true);
380  m_wheelJoints[i]->updateJointInfo();
381  }
382  }
383 }
384 
386 {
387  m_leftWheelVelocity = velocity;
388 }
389 
391 {
392  m_rightWheelVelocity = velocity;
393 }
394 
396 {
397  wMatrix tm = matrix();
398  m_body->setMatrix(tm);
399  for (int i = 0; i < m_wheels.size(); i++) {
400  m_wheels[i]->setMatrix(m_wheelsTransformation[i] * tm);
401  }
402  foreach (PhyJoint* j, m_wheelJoints) {
403  j->updateJointInfo();
404  }
405 }
406 
407 } // end namespace farsa