arena.cpp
130 m_smallCylinderRadius(ConfigurationHelper::getDouble(params, prefix + "smallCylinderRadius", defaultSmallCylinderRadius)),
131 m_bigCylinderRadius(ConfigurationHelper::getDouble(params, prefix + "bigCylinderRadius", defaultBigCylinderRadius)),
132 m_lightBulbRadius(ConfigurationHelper::getDouble(params, prefix + "lightBulbRadius", defaultLightBulbRadius)),
133 m_collisionHandler(stringToCollisionHandler(ConfigurationHelper::getString(params, prefix + "collisionHandler", "SimpleCollisions"))),
141 ConfigurationHelper::throwUserConfigError(prefix + "collisionHandler", params.getValue(prefix + "collisionHandler"), "Invalid collision handler value. It must be either SimpleCollisions or CircleCollisions");
167 Descriptor d = addTypeDescription(type, "The class modelling an arena in which robots can live");
168 d.describeReal("z").def(0.0).help("The z coordinate of the plane in the world frame of reference", "This is the z coordinate of the upper part of the plane in the world frame of reference");
169 d.describeReal("smallCylinderRadius").def(defaultSmallCylinderRadius).limits(0.0001, +Infinity).help("The radius of small cylinders", "This is the value to use for the radius of small cylinders. The default value is the one used in evorobot. If you change this, be careful which sample files you use.");
170 d.describeReal("bigCylinderRadius").def(defaultBigCylinderRadius).limits(0.0001, +Infinity).help("The radius of big cylinders", "This is the value to use for the radius of big cylinders. The default value is the one used in evorobot. If you change this, be careful which sample files you use.");
171 d.describeReal("lightBulbRadius").def(defaultLightBulbRadius).limits(0.0001, +Infinity).help("The radius of light bulbs");
172 d.describeEnum( "collisionHandler" ).def("SimpleCollisions").values( QStringList() << "SimpleCollisions" << "CircleCollisions" ).help("The type of collision handler to use", "This can be either SimpleCollisions (which puts robots back to their position before collision) or CircleCollisions (which handles collisions between circular objects like robots and cylinders computing the results based on objects masses)");
179 // First of all adding robots to the list of usable resources. This will call the resourceChanged callback
180 // because robots already exist, however they are not in the m_robotResourceWrappers map so the callback will
201 // If the robot actually exists, adding a wrapper, otherwise we simply add the robot to the map to
205 WheeledRobot2DWrapper* wrapper = new WheeledRobot2DWrapper(this, r, r->robotHeight(), r->robotRadius());
236 Box2DWrapper* Arena::createWall(QColor color, wVector start, wVector end, real thickness, real height)
245 Box2DWrapper* b = createBox(color, (end - start).norm(), thickness, height, Box2DWrapper::Wall);
247 // Moving the wall and setting the texture. We have to compute the rotation around the Z axis of the
278 // Creating the cylinder, then we only have to change its z position and set the material to nonCollidable
279 Cylinder2DWrapper* c = createCylinder(color, radius, targetAreasHeight, Cylinder2DWrapper::CircularTargetArea);
293 // Creating the box, then we only have to change its z position and set the material to nonCollidable
294 Box2DWrapper* b = createBox(color, width, depth, targetAreasHeight, Box2DWrapper::RectangularTargetArea);
364 QVector<PhyObject2DWrapper*> Arena::getKinematicRobotCollisions(WheeledRobot2DWrapper* robot) const
369 QVector<PhyObject2DWrapper*> Arena::getKinematicRobotCollisions(QString robotResourceName) const
374 QSet<PhyObject2DWrapper*> Arena::getKinematicRobotCollisionsSet(WheeledRobot2DWrapper* robot) const
379 QSet<PhyObject2DWrapper*> Arena::getKinematicRobotCollisionsSet(QString robotResourceName) const
384 throw ArenaException(QString("The arena doesn't contain the robot named %1 (perhaps you used \"robot\"? You must use the complete name, e.g. agent[0]:robot)").arg(robotResourceName).toLatin1().data());
388 Cylinder2DWrapper* Arena::createCylinder(QColor color, real radius, real height, Cylinder2DWrapper::Type type)
414 Box2DWrapper* Arena::createBox(QColor color, real width, real depth, real height, Box2DWrapper::Type type)
494 WheeledRobot2DWrapper* wrapper = new WheeledRobot2DWrapper(this, r, r->robotHeight(), r->robotRadius());
536 // Here we use a naive approach: we check collision of every object with every robot. This is not
537 // the best possible algorithm (complexity is O(n^2)...), but it's the way things are done in evorobot
551 if ((obj == robot) || ((obj->phyObject() != NULL) && (obj->phyObject()->isCollidable() == false))) {
558 // Getting the distance between the robot and the object. If computeDistanceAndOrientationFromRobot
567 if (m_kinematicRobotCollisions.contains(robot) && m_kinematicRobotCollisions[robot].contains(obj)) {
611 // Here we use a naive approach: we check collision of every object with every robot like in the other implementation
612 // (simpleCollisions). If the robot collides with a non-static object, we move the object forward and the robot a bit
613 // backward. The percentage of the robot displacement which is transferred to the object is defined by the constant
616 // If the robot collides with another robot we move both robots backward to resolve the collision, if it collides with
617 // a static object, we move only the colliding robot bacward. In both cases we add some noise to the position and
618 // orientation of the robot after the collision. The percentage of noise is defined by the constant below
629 // The vectors with distances and angles of colliding objects (these should all be negative values)
639 if ((obj == robot) || ((obj->phyObject() != NULL) && (obj->phyObject()->isCollidable() == false))) {
646 // Getting the distance between the robot and the object. If computeDistanceAndOrientationFromRobot
655 if (m_kinematicRobotCollisions.contains(robot) && m_kinematicRobotCollisions[robot].contains(obj)) {
674 // If the robot collides with something else we have to check if it only collided with movable objects (we then
695 // Moving robot back (the hypothesis is that the robot can rotate freely but not move forward as
711 // Here we move both robots back (along the direction of their velocity) of a quantity which is sufficient
712 // to remove the collision. We then add a small random noise to both position and orientation. To compute
715 // where r1 and r2 are the radii of the two robots, c1 and c2 are the positions on the plane of the centers
716 // of the two robots at the moment of the collision, v1 and v2 are the velocities of the two robots in the
717 // current timestep and k is the factor multiplying the two velocities that tells how much to move the robots
718 // backward. This means that we should find k so that when the robots are moved back along the respective
719 // velocity vectors by k*v1 and k*v2, the distance between their centers should be equal to r1 + r2. The
720 // solution to the equation above gives two values of k. Only the positive one (which should be between 0 and
721 // 1, if the robots were not colliding in the previous timestep) whould be taken (the negative one corrsponds
750 // k is how much I have to move the robots backwards. k1 and k2 must always have different signs, because
751 // the positive one is how much I have to move robots backwards to remove the collision, while the negative
752 // one is how much I have to move them forward. I simply take the bigger of the two, which will be positive.
753 // It could happend that the biggest is 0 (or nearly so): for example if robots are already very near and
754 // they move at a very slow velocity when colliding. This is not a problem, robots will not be moved in this
758 // Sanity check. Here we have to allow small negative values (which will be ignored) that are possible in
761 Logger::warning(QString("Wrong factor when resolving collisions, setting a value to NaN. r1 = %1, r2 = %2, r = %3, c1 = %4, c2 = %5, v1 = %6, v2 = %7, dcx = %8, dcy = %9, dvx = %10, dvy = %11, a = %12, b = %13, c = %14, sqrtDelta = %15, k1 = %16, k2 = %17, k = %18").arg(r1).arg(r2).arg(r).arg(c1).arg(c2).arg(v1).arg(v2).arg(dcx).arg(dcy).arg(dvx).arg(dvy).arg(a).arg(b).arg(c).arg(sqrtDelta).arg(k1).arg(k2).arg(k));
764 #warning For the moment we don t kill the simulation, just for testing purpouse. We set the position of one robot to NaN
779 robotMtr = robotMtr.rotateAround(wVector::Z(), robotMtr.w_pos, globalRNG->getDouble(-noiseOnOrientation, noiseOnOrientation));
785 robotMtr = robotMtr.rotateAround(wVector::Z(), robotMtr.w_pos, globalRNG->getDouble(-noiseOnOrientation, noiseOnOrientation));
794 // Qui per il muro bisogna usare l'angolo tra muro e robot per poter calcolare di quanto si deve spostare il robot indietro.
805 // Now computing how much the robot should be moved backward and adding some noise as a portion of the robot displacement. The
806 // minus sign when computing k is because the distance is negative in case of collisions. We check the robotDisplacement.norm()
807 // is not too small to avoid numerical problems. If it is, simply moveing to the previous location (no noise on position since
813 robotMtr = robotMtr.rotateAround(wVector::Z(), robotMtr.w_pos, globalRNG->getDouble(-noiseOnOrientation, noiseOnOrientation));
821 const wVector robotPos = robotMtr.w_pos - robotDisplacement.scale(k + globalRNG->getDouble(0.0, noiseOnPosition));
822 robotMtr = robotMtr.rotateAround(wVector::Z(), robotMtr.w_pos, globalRNG->getDouble(-noiseOnOrientation, noiseOnOrientation));
834 Box2DWrapper* Arena::createPlane(ConfigurationParameters& params, QString prefix, real z, Arena* arena)
843 ConfigurationHelper::throwUserMissingResourceError("world", "We need a world to create the arena!");
871 Box2DWrapper* Arena::createPlane2(ConfigurationParameters& params, QString prefix, real z, Arena* arena)
885 ConfigurationHelper::throwUserMissingResourceError("world", "We need a world to create the arena!");
893 plane->setPosition(wVector( w*cellSize-planeWidth/2.0, h*cellSize-planeHeight/2.0, z - (planeThickness / 2.0)));
907 world->setSize(wVector(-planeWidth, -planeHeight, -planeThickness), wVector(planeWidth, planeHeight, +6.0));
void usableResources(QStringList resources)
friend friend class ResourcesLocker
static wMatrix identity()
static void throwUserMissingResourceError(QString resourceName, QString description)
FARSA_UTIL_API RandomGenerator * globalRNG
The subclass of PhyObject2DWrapper wrapping a box.
Definition: wheeledexperimenthelper.h:390
void setTexture(QString textureName)
Set the texture to use when rendering this.
Definition: wheeledexperimenthelper.cpp:456
The subclass of PhyObject2DWrapper wrapping a wheeled robot.
Definition: wheeledexperimenthelper.h:896
static const double Infinity
Cylinder2DWrapper * createSmallCylinder(QColor color, real height=-1.0)
Creates a small cylinder.
Definition: arena.cpp:259
virtual PhyCylinder * phyObject()
Returns a pointer to the wrapped PhyObject.
Definition: wheeledexperimenthelper.cpp:729
const WheeledRobot2DWrapper * getRobotWrapper(QString robotName) const
Returns a pointer to the wrapper of a robot given the robot resource name.
Definition: arena.cpp:217
FARSA_DEPRECATED QVector< PhyObject2DWrapper * > getKinematicRobotCollisions(WheeledRobot2DWrapper *robot) const
Returns the list of objects that collided with the given kinematic robot at the previous timestep...
Definition: arena.cpp:364
FARSA_UTIL_TEMPLATE const T max(const T &t1, const U &t2)
Cylinder2DWrapper * createCircularTargetArea(real radius, QColor color)
Creates a circular target area.
Definition: arena.cpp:274
static wMatrix roll(real ang)
static void throwUserConfigError(QString paramName, QString paramValue, QString description)
const wMatrix & matrix() const
void addUsableResources(QStringList resources)
void FARSA_UTIL_TEMPLATE throwUserRuntimeError(QString reason)
static void error(QString msg)
The subclass of PhyObject2DWrapper wrapping a cylinder.
Definition: wheeledexperimenthelper.h:592
Cylinder2DWrapper * createBigCylinder(QColor color, real height=-1.0)
Creates a big cylinder.
Definition: arena.cpp:264
A class wrapping a PhyObject to add methods suitable for wheeled robots simulations.
Definition: wheeledexperimenthelper.h:51
Box2DWrapper * createWall(QColor color, wVector start, wVector end, real thickness, real height=-1.0)
Creates a wall.
Definition: arena.cpp:236
Box2DWrapper * createRectangularTargetArea(real width, real depth, QColor color)
Creates a rectangular target area.
Definition: arena.cpp:289
virtual void save(ConfigurationParameters ¶ms, QString prefix)
Saves the actual status of parameters into the ConfigurationParameters object passed.
Definition: arena.cpp:156
static double getDouble(ConfigurationParameters ¶ms, QString paramPath, double def=0)
static Descriptor addTypeDescription(QString type, QString shortHelp, QString longHelp=QString(""))
QString getValue(QString path, bool alsoMatchParents=false) const
float real
static wMatrix yaw(real ang)
void handleKinematicRobotCollisions()
Checks collisions of kinematic robots.
Definition: arena.cpp:348
FARSA_UTIL_TEMPLATE const T min(const T &t1, const U &t2)
void setMatrix(const wMatrix &newm)
virtual PhyObject * phyObject()=0
Returns a pointer to the wrapped PhyObject.
The subclass of PhyObject2DWrapper wrapping a sphere.
Definition: wheeledexperimenthelper.h:749
double getDouble(double min, double max)
Cylinder2DWrapper * createCylinder(real radius, QColor color, real height=-1.0)
Creates a cylinder.
Definition: arena.cpp:269
virtual PhyBox * phyObject()
Returns a pointer to the wrapped PhyObject.
Definition: wheeledexperimenthelper.cpp:505
QSet< PhyObject2DWrapper * > getKinematicRobotCollisionsSet(WheeledRobot2DWrapper *robot) const
Returns the set of objects that collided with the given kinematic robot at the previous timestep...
Definition: arena.cpp:374
static void warning(QString msg)
void prepareToHandleKinematicRobotCollisions()
Call this before advancing the world to prepare stuffs needed by a call to handleKinematicRobotCollis...
Definition: arena.cpp:332
static void describe(QString type)
Adds to Factory::typeDescriptions() the descriptions of all parameters and subgroups.
Definition: arena.cpp:162