phykhepera.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 "phykhepera.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 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
38  #warning NON HO TUTTE LE MISURE DEL ROBOT, ALCUNI VALORI LI HO DECISI IO
39 #endif
40 // Lengths are in meters, weights in kilograms.
42 const real PhyKhepera::bodyr = 0.035f;
43 const real PhyKhepera::bodyh = 0.030f;
44 const real PhyKhepera::bodym = 0.066f;
45 const real PhyKhepera::wheelr = 0.015f;
46 const real PhyKhepera::wheelh = 0.003f;
47 const real PhyKhepera::wheelm = 0.005f;
48 const real PhyKhepera::axletrack = 0.055f;
49 const real PhyKhepera::passivewheelr = 0.003f;
50 const real PhyKhepera::passivewheelm = 0.002f;
51 
52 PhyKhepera::PhyKhepera(World* world, QString name, const wMatrix& transformation) :
53  WObject(world, name, transformation, false),
54  m_body(NULL),
55  m_bodyTransformation(),
56  m_bodyInvTransformation(),
57  m_wheels(),
58  m_wheelsTransformation(),
59  m_wheelJoints(),
60  m_wheelsCtrl(NULL),
61  m_proximityIR(NULL),
62  m_kinematicSimulation(false),
63  m_leftWheelVelocity(0.0f),
64  m_rightWheelVelocity(0.0f),
65  m_frontMarker(NULL)
66 {
67  // --- reference frame
68  // X
69  // ^
70  // | ------
71  // | | |
72  // | -------------------
73  // | | battery |
74  // | | |
75  // | -------------------
76  // | | |
77  // | ------
78  // |
79  // +---------------------> Y
80  // The front of the robot is towards -Y (positive speeds of the wheel cause the robot to move towards -Y)
81 
82  // Creating a material for the khepera
83  world->materials().createMaterial("kheperaMaterial");
84  world->materials().setProperties("kheperaMaterial", "default", 0.0f, 0.0f, 0.01f, 0.01f, true);
85  world->materials().createMaterial("kheperaTire");
86  world->materials().setProperties("kheperaTire", "default", 1.2f, 0.9f, 0.01f, 0.01f, true);
87 
88  // Now creating the body of the khepera. It is made up of a single cylinder. We put the
89  // frame of reference of the body (which is equal to that of the whole robot) on the ground to have
90  // more stability and to simplify moving the robot (no need to apply displacements to put it on a
91  // plane)
92  {
93  // Creating the body
94  m_body = new PhyCylinder(bodyr, bodyh, world, "body");
95  m_bodyTransformation = wMatrix::yaw(toRad(90.0f));
96  m_bodyTransformation.w_pos.z = bodydistancefromground + (bodyh / 2.0f);
97  m_body->setMatrix(m_bodyTransformation * matrix());
98  m_body->setMass(bodym);
99  m_body->setMaterial("kheperaMaterial");
100  m_body->setOwner(this, false);
101  m_bodyInvTransformation = m_bodyTransformation.inverse();
102  }
103 
104  // Creating all the wheels. We first create the two motorized wheels and then the two passive ones.
105  // The position of the wheels and their indexes are as follows (remember that the front of the
106  // robot is towards -Y):
107  //
108  // X
109  // ^
110  // | ------
111  // | | 0 |
112  // | -------------------
113  // | | battery |
114  // | | 3 2 |
115  // | -------------------
116  // | | 1 |
117  // | ------
118  // |
119  // +---------------------> Y
120 
121  // Creating the first motorized wheel and its joint
122  {
123  // The matrix is relative to the robot frame of reference. First creating the wheel
125  tm.w_pos = wVector(axletrack / 2.0f, 0.0f, wheelr);
126  PhyObject* wheel = new PhyCylinder(wheelr, wheelh, world, "motorWheel");
127  wheel->setMass(wheelm);
128  wheel->setColor(Qt::blue);
129  wheel->setMaterial("kheperaTire");
130  wheel->setOwner(this, false);
131  wheel->setMatrix(tm * matrix());
132  m_wheels.append(wheel);
133  m_wheelsTransformation.append(tm);
134 
135  // Now creating the joint
136  PhyJoint* joint = new PhySuspension(wVector::Z(), m_body->matrix().untransformVector(wheel->matrix().w_pos), wVector::X(), m_body, wheel);
137  joint->dofs()[0]->disableLimits();
138  joint->setOwner(this, false);
139  joint->updateJointInfo();
140  m_wheelJoints.append(joint);
141  }
142 
143  // Creating the second motorized wheel and its joint
144  {
145  // The matrix is relative to the robot frame of reference. First creating the wheel
147  tm.w_pos = wVector(-axletrack / 2.0f, 0.0f, wheelr);
148  PhyObject* wheel = new PhyCylinder(wheelr, wheelh, world, "motorWheel");
149  wheel->setMass(wheelm);
150  wheel->setColor(Qt::blue);
151  wheel->setMaterial("kheperaTire");
152  wheel->setOwner(this, false);
153  wheel->setMatrix(tm * matrix());
154  m_wheels.append(wheel);
155  m_wheelsTransformation.append(tm);
156 
157  // Now creating the joint
158  PhyJoint* joint = new PhySuspension(wVector::Z(), m_body->matrix().untransformVector(wheel->matrix().w_pos), wVector::X(), m_body, wheel);
159  joint->dofs()[0]->disableLimits();
160  joint->setOwner(this, false);
161  joint->updateJointInfo();
162  m_wheelJoints.append(joint);
163  }
164 
165  // Creating the first passive wheel and its joint
166  {
167  // The matrix is relative to the robot frame of reference. First creating the wheel
169  tm.w_pos = wVector(0.0f, bodyr - passivewheelr, passivewheelr);
170  PhyObject* wheel = new PhySphere(passivewheelr, world, "passiveWheel");
171  wheel->setMass(passivewheelm);
172  wheel->setColor(Qt::blue);
173  wheel->setMaterial("kheperaTire");
174  wheel->setOwner(this, false);
175  wheel->setMatrix(tm * matrix());
176  m_wheels.append(wheel);
177  m_wheelsTransformation.append(tm);
178 
179  // Now creating the joint
180  PhyJoint* joint = new PhyBallAndSocket(m_body->matrix().untransformVector(wheel->matrix().w_pos), m_body, wheel);
181  joint->setOwner(this, false);
182  joint->updateJointInfo();
183  m_wheelJoints.append(joint);
184  }
185 
186  // Creating the second passive wheel and its joint
187  {
188  // The matrix is relative to the robot frame of reference. First creating the wheel
190  tm.w_pos = wVector(0.0f, -(bodyr - passivewheelr), passivewheelr);
191  PhyObject* wheel = new PhySphere(passivewheelr, world, "passiveWheel");
192  wheel->setMass(passivewheelm);
193  wheel->setColor(Qt::blue);
194  wheel->setMaterial("kheperaTire");
195  wheel->setOwner(this, false);
196  wheel->setMatrix(tm * matrix());
197  m_wheels.append(wheel);
198  m_wheelsTransformation.append(tm);
199 
200  // Now creating the joint
201  PhyJoint* joint = new PhyBallAndSocket(m_body->matrix().untransformVector(wheel->matrix().w_pos), m_body, wheel);
202  joint->setOwner(this, false);
203  joint->updateJointInfo();
204  m_wheelJoints.append(joint);
205  }
206 
207  // Now we can create the motor controller
208  QVector<PhyDOF*> motors;
209  motors << m_wheelJoints[0]->dofs()[0] << m_wheelJoints[1]->dofs()[0];
210  m_wheelsCtrl = new WheelMotorController(motors, world);
211  m_wheelsCtrl->setOwner(this, false);
212  // The min and max speed in rad/s have been derived for the e-puck wheel considering as maximum linear
213  // displacement 14 cm/s (that for the give wheel radius is approximately 1.1 ratations per second)
214 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
215  #warning QUI DECIDERE LA VELOCITÀ MASSIMA DEL KHEPERA, PER IL MOMENTO È LA STESSA DELL E-PUCK
216 #endif
217  const real maxAngularSpeed = 1.1f * 2.0f * PI_GRECO;
218  m_wheelsCtrl->setSpeedLimits(-maxAngularSpeed, -maxAngularSpeed, maxAngularSpeed, maxAngularSpeed);
219 
220  // Connecting wheels speed signals to be able to move the robot when in kinematic
221  connect(m_wheelJoints[0]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setRightWheelDesideredVelocity(real)));
222  connect(m_wheelJoints[1]->dofs()[0], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setLeftWheelDesideredVelocity(real)));
223 
224  // Creating the proximity IR sensors
225  QVector<SingleIR> sensors;
226 
227 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
228  #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI
229 #endif
230  // Adding the sensors. The khepera has 8 proximity infrared sensors
231  const double sensorsAngles[] = {-60.0, -36.0, -12.0, 12.0, 36.0, 60.0, 160.0, 200.0};
232  for (unsigned int i = 0; i < 8; i++) {
233  const double curAngle = sensorsAngles[i] - 90.0; //double(i) * (360.0 / 8.0) + ((360.0 / 8.0) / 2.0);
234  const double radius = bodyr;
235 
236  wMatrix mtr = wMatrix::yaw(toRad(curAngle)) * wMatrix::roll(PI_GRECO / 2.0);
237  mtr.w_pos.x = -bodydistancefromground /*- (bodyh / 2.0f) + 0.005*/;
238  mtr.w_pos.y = radius * sin(toRad(curAngle));
239  mtr.w_pos.z = radius * cos(toRad(curAngle));
240 
241  sensors.append(SingleIR(m_body, mtr, 0.00, 0.05, 10.0, 5));
242  }
243  m_proximityIR = new SimulatedIRProximitySensorController(world, sensors);
244 
245  world->pushObject(this);
246 }
247 
249 {
250  foreach (PhyJoint* j, m_wheelJoints) {
251  delete j;
252  }
253  foreach (PhyObject* w, m_wheels) {
254  delete w;
255  }
256  delete m_wheelsCtrl;
257  delete m_body;
258  delete m_proximityIR;
259 }
260 
262 {
263  // Updating motors
264  if (m_wheelsCtrl->isEnabled()) {
265  m_wheelsCtrl->update();
266  }
267 
268  if (m_kinematicSimulation) {
269  // In kinematic mode, we have to manually move the robot depending on the wheel velocities
270  wMatrix mtr = matrix();
271  wheeledRobotsComputeKinematicMovement(mtr, m_leftWheelVelocity, m_rightWheelVelocity, wheelr, axletrack, world()->timeStep());
272 
273  // This will also update the position of all pieces
274  setMatrix(mtr);
275  }
276 }
277 
279 {
280  // Updating sensors
281  if (m_proximityIR->isEnabled()) {
282  m_proximityIR->update();
283  }
284 
285  // Updating the transformation matrix of the robot. It is coincident with the matrix of the body
286  tm = m_bodyInvTransformation * m_body->matrix();
287 }
288 
289 void PhyKhepera::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
290 {
291  m_proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
292 }
293 
294 void PhyKhepera::setDrawFrontMarker(bool drawMarker)
295 {
296  if (getDrawFrontMarker() == drawMarker) {
297  return;
298  }
299 
300  if (drawMarker) {
301  m_frontMarker = new PlanarArrowGraphicalMarker(bodyr, bodyr / 6.0f, bodyr / 4.0f, 0.7f, world());
302  m_frontMarker->setUseColorTextureOfOwner(false);
303  m_frontMarker->setColor(Qt::green);
304  m_frontMarker->setTexture("");
305 
306  wMatrix displacement = wMatrix::roll(-PI_GRECO / 2.0f);
307  displacement.w_pos = wVector(0.0, 0.0, bodyh + bodydistancefromground + 0.0001f);
308  m_frontMarker->attachToObject(this, true, displacement);
309  } else {
310  delete m_frontMarker;
311  m_frontMarker = NULL;
312  }
313 }
314 
316 {
317  return (m_frontMarker != NULL);
318 }
319 
321 {
322  if (m_kinematicSimulation == k) {
323  return;
324  }
325 
326  m_kinematicSimulation = k;
327  if (m_kinematicSimulation) {
328  // First disabling all joints...
329  for (int i = 0; i < m_wheelJoints.size(); i++) {
330  m_wheelJoints[i]->enable(false);
331  }
332 
333  // ... then setting all objects to kinematic behaviour
334  m_body->setKinematic(true, true);
335  for (int i = 0; i < m_wheels.size(); i++) {
336  m_wheels[i]->setKinematic(true, true);
337  }
338  } else {
339  // First setting all objects to dynamic behaviour...
340  m_body->setKinematic(false);
341  for (int i = 0; i < m_wheels.size(); i++) {
342  m_wheels[i]->setKinematic(false);
343  }
344 
345  // ... then enabling all joints (if the corresponding part is enabled)
346  for (int i = 0; i < m_wheelJoints.size(); i++) {
347  m_wheelJoints[i]->enable(true);
348  m_wheelJoints[i]->updateJointInfo();
349  }
350  }
351 }
352 
354 {
355  m_leftWheelVelocity = velocity;
356 }
357 
359 {
360  m_rightWheelVelocity = velocity;
361 }
362 
364 {
365  wMatrix tm = matrix();
366  m_body->setMatrix(m_bodyTransformation * tm);
367  for (int i = 0; i < m_wheels.size(); i++) {
368  m_wheels[i]->setMatrix(m_wheelsTransformation[i] * tm);
369  }
370  foreach (PhyJoint* j, m_wheelJoints) {
371  j->updateJointInfo();
372  }
373 }
374 
375 } // end namespace farsa
void doKinematicSimulation(bool k)
Changes the robot model from dynamic to kinematic and vice-versa.
Definition: phykhepera.cpp:320
FARSA_UTIL_TEMPLATE real toRad(real x)
World's Object class.
Definition: wobject.h:39
static wMatrix identity()
create an identity matrix
Definition: wmatrix.h:460
void setKinematic(bool b, bool c=false)
Changes between kinematic/dynamic behaviour for the object.
Definition: phyobject.cpp:56
static const real passivewheelm
The mass of the passive wheels.
Definition: phykhepera.h:103
wMatrix tm
Trasformation matrix.
Definition: wobject.h:193
PhySphere class.
Definition: physphere.h:37
void setUseColorTextureOfOwner(bool b)
set if the object will be rendered with the color and texture of our owner (if we have one) ...
Definition: wobject.cpp:97
void setMass(real)
Set the mass without touching the Inertia data.
Definition: phyobject.cpp:219
void setRightWheelDesideredVelocity(real velocity)
Sets the desidered velocity of the right wheel.
Definition: phykhepera.cpp:358
World * world()
Return the world.
Definition: wobject.cpp:61
static const real passivewheelr
The radius of the passive wheels.
Definition: phykhepera.h:95
static const real axletrack
The distance between the two motorized wheels.
Definition: phykhepera.h:87
static const real bodyh
The height of the body of the robot.
Definition: phykhepera.h:62
void setLeftWheelDesideredVelocity(real velocity)
Sets the desidered velocity of the left wheel.
Definition: phykhepera.cpp:353
void setDrawFrontMarker(bool drawMarker)
Whether to draw a marker in the front part of the robot or not.
Definition: phykhepera.cpp:294
virtual void updateJointInfo()=0
Update the Joint informations (each PhyDOF will be updated)
void attachToObject(WObject *object, bool makeOwner=false, const wMatrix &displacement=wMatrix::identity())
Attaches this object to another WObject.
void setTexture(QString textureName)
Set the texture to use for this WObject when rendered.
Definition: wobject.cpp:73
wMatrix inverse() const
calculate the inverse of transformation matrix
Definition: wmatrix.h:258
World class.
Definition: world.h:223
PhyKhepera(World *world, QString name, const wMatrix &transformation=wMatrix::identity())
Creates a khepera II robot.
Definition: phykhepera.cpp:52
void setColor(QColor c)
Set the color to use on rendering.
Definition: wobject.cpp:81
virtual QVector< PhyDOF * > dofs()
Return descriptions of DOF.
Definition: phyjoint.h:391
static wMatrix roll(real ang)
create a rotation around Z axis of ang radians
Definition: wmatrix.h:512
bool isEnabled()
Returns true if the sensor is enabled.
void setSpeedLimits(QVector< double > minSpeeds, QVector< double > maxSpeeds)
sets the minimum and maximum velocities for each wheel
static const real bodydistancefromground
The distance of the body from the ground.
Definition: phykhepera.h:52
static const real wheelm
The mass of one motorized wheel.
Definition: phykhepera.h:82
PhyJoint class.
Definition: phyjoint.h:359
wMatrix class
Definition: wmatrix.h:48
const wMatrix & matrix() const
return a reference to the transformation matrix
Definition: wobject.cpp:47
virtual void update()
Updates sensor reading.
PhySuspension class PhySuspension is a joint implementing the system of springs, shock absorbers and ...
Definition: physuspension.h:41
static wVectorT< false > X()
X axis vector.
static const real wheelh
The height of the motorized wheels.
Definition: phykhepera.h:77
void setOwner(Ownable *owner, bool destroy=true)
Sets the owner of this object.
Definition: ownable.cpp:47
virtual void preUpdate()
Pre-updates the robot.
Definition: phykhepera.cpp:261
bool isEnabled()
return true is if enable (hence if it is on)
wVector untransformVector(const wVector &v) const
invert the rotation and translation on the vector v
Definition: wmatrix.h:368
bool createMaterial(QString name)
Create a new material It return false if already exists a material with name passed.
Definition: world.cpp:40
static const real wheelr
The radius of the motorized wheels.
Definition: phykhepera.h:72
A single proximity IR sensor.
float real
MaterialDB & materials()
return the MaterialDB object for managing World's materials
Definition: world.h:334
static const real bodyr
The radius of the body of the robot.
Definition: phykhepera.h:57
static wMatrix yaw(real ang)
create a rotation around Y axis of ang radians
Definition: wmatrix.h:503
virtual void update()
apply the velocities on the wheels
void setProperties(QString mat1, QString mat2, real fs, real fk, real el, real sf, bool en=true)
set Frictions, Elasticity, Softness and Enabled/Disable collision between materials ...
Definition: world.cpp:131
PhyCylinder class.
Definition: phycylinder.h:53
void setMatrix(const wMatrix &newm)
set a new matrix
Definition: wobject.cpp:109
A graphical object displaying a planar arrow.
virtual void changedMatrix()
The function called when the transformation matrix of the robot is changed.
Definition: phykhepera.cpp:363
PhyBallAndSocket class.
static wVectorT< false > Z()
Z axis vector.
static const real bodym
The mass of the robot without the wheels.
Definition: phykhepera.h:67
bool getDrawFrontMarker() const
Returns whether a marker in the front part of the robot is drawn or not.
Definition: phykhepera.cpp:315
Dedicated controller for wheeled robots.
void setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay=false, bool drawRealRay=false)
Sets whether proximity IR sensors are drawn or not and how.
Definition: phykhepera.cpp:289
virtual ~PhyKhepera()
Destructor.
Definition: phykhepera.cpp:248
PhyObject class.
Definition: phyobject.h:46
virtual void postUpdate()
Post-updates the robot.
Definition: phykhepera.cpp:278
void setGraphicalProperties(bool drawSensor, bool drawRay=false, bool drawRealRay=false)
Sets graphical properties of all sensors.