Army ant simulation
RobotController.cpp
1 /*
2  * RobotController.cpp
3  *
4  * Created on: 28 sept. 2018
5  * Author: lucie
6  *
7  * 29 Jan. 2019:
8  * - changed the constructor and the create method to add a pointer on the terrain m_terrainBody
9  * - in the robotPushing(Robot& r) method, added a check to pass the eventual other (contacted) robot in bridge state
10  * if (! (contactList->other==m_terrainBody)){
11  * Robot* r_other = static_cast<Robot*>( contactList->other->GetUserData() );
12  * setRobotState(*r_other, BRIDGE);
13  * }
14  * 13 Feb. 2019:
15  * - changed the way the bridge dissolution is checked to be more efficient:
16  * -added members : m_nbRobInBridge updated each time a new robot enter or leave the bridge (in setRobotState(.) and step(.))
17  *
18  * - Improved the contact handler findContactRobots(b2Contact* contact) by changing the way we determine which robots are involved:
19  * instead of looping over the robots of the robotController, call getUserData() directly from the contacted body
20  *
21  *
22  *
23  */
24 
25 #include "RobotController.h"
26 #include "Box2D/Box2D.h"
27 #include "constants.h"
28 #include "helpers.h"
29 #include <iostream>
30 
31 RobotController::RobotController() {
32 }
33 
34 RobotController::RobotController(config::sController controllerParam, config::sRobot robotParam, b2Body* terrain, double m_to_px) {
35  m_controllerParam = controllerParam;
36  m_robotParam = robotParam;
37  m_robotVector.reserve(controllerParam.max_robot_window);
38  m_M_TO_PX = m_to_px;
39  printf("size of vector %d, \n", m_robotVector.size());
40  m_terrainBody = terrain;
41 
42 }
43 
44 void RobotController::create(config::sController controllerParam, config::sRobot robotParam, b2Body* terrain, double m_to_px) {
45  m_controllerParam = controllerParam;
46  m_robotParam = robotParam;
47  m_robotVector.reserve(controllerParam.max_robot_window);
48  m_M_TO_PX = m_to_px;
49  printf("size of vector %d, \n", m_robotVector.size());
50  m_terrainBody = terrain;
51 
52 }
53 
54 RobotController::~RobotController() {
55  // TODO Auto-generated destructor stub
56  int i = 0 ;
57  for (i=0; i<m_robotVector.size(); i++){
58 // if(!(m_robot[i].m_previousGripJoint==nullptr)){
59 // m_robot[i].getBody()->GetWorld()->DestroyJoint(m_robot[i].m_previousGripJoint);
60  m_robotVector[i]->m_previousGripJoint = nullptr;
61 // }
62 // if(!(m_robot[i].m_currentGripJoint==nullptr)){
63 // m_robot[i].getBody()->GetWorld()->DestroyJoint(m_robot[i].m_currentGripJoint);
64  m_robotVector[i]->m_currentGripJoint = nullptr;
65 // }
66  }
67 }
68 
69 void RobotController::setNbRobots(int nb_robots){
70  m_controllerParam.max_robot_window = nb_robots;
71  m_robotVector.reserve(nb_robots);
72 }
73 
74 void RobotController::setScale(double m_to_px){
75  m_M_TO_PX = m_to_px;
76 }
77 
78 bool RobotController::createRobot(b2World* world, int delay, double posX, double posY, double angle){
79 
80  if (m_robotVector.size() >= m_controllerParam.max_robot_window){
81 // printf("the max number of robot in the screen has already been reached");
82  return false;
83  }
84  else{
85  Robot *r = new Robot();
86  m_robotVector.push_back(r);
87 // (world, posX, posY)
88  m_nbRobots ++;
89  m_robotVector[m_robotVector.size()-1]->createBody(world, m_robotParam, posX, posY, angle);
90  m_robotVector[m_robotVector.size()-1]->setId(m_nbRobots);
91  m_robotVector[m_robotVector.size()-1]->setDelay(delay);
92  m_robotVector[m_robotVector.size()-1]->m_age = m_currentIt;
93  printf("Robot created \n");
94  return true;
95  }
96 }
97 
99 
100  if (pos_id > m_robotVector.size()-1){
101  throw std::string("you have only " + std::to_string(m_robotVector.size())
102  + " active robots, you cannot access robot "+ std::to_string(pos_id));
103  }
104  else{
105  return m_robotVector[pos_id];
106  }
107 
108 }
109 
111  for (int i=0; i<m_robotVector.size(); i++){
112  if(m_robotVector[i]->getId()==id){
113  return m_robotVector[i];
114  }
115  }
116  return nullptr;
117 }
118 
119 void RobotController::drawRobots(sf::RenderWindow& window, double m_to_px){
120  int i =0;
121  for (i=0; i<m_robotVector.size(); i++){
122  m_robotVector[i]->drawBody(window, m_to_px);
123  m_robotVector[i]->drawGripJoint(window, m_to_px);
124  }
125 }
126 
127 
128 void RobotController::findContactRobots(b2Contact* contact){
129  int i =0;
130  b2Body* bodyContactA = contact->GetFixtureA()->GetBody();
131  b2Body* bodyContactB = contact->GetFixtureB()->GetBody();
132  Robot* rA = nullptr;
133  Robot* rB = nullptr;
134 
135  bool robotA = false;
136  bool robotB = false;
137 
138  bool contactorA = false;
139  bool contactorB = false;
140 
141  if(!(bodyContactA == m_terrainBody)){
142  robotA = true;
143  rA=static_cast<Robot*>(bodyContactA->GetUserData());
144  }
145 
146  if(!(bodyContactB == m_terrainBody)){
147  robotB = true;
148  rB=static_cast<Robot*>(bodyContactB->GetUserData());
149  }
150 
151  if(robotA){
152  contactorA = (rA->isMoving()||rA->m_start)
153  && (rA->contactOnGripSide(contact));//||m_robotVector[A].m_start);
154  }
155 
156  if(robotB){
157  contactorB = (rB->isMoving()||rB->m_start)
158  && (rB->contactOnGripSide(contact));//||m_robotVector[A].m_start);
159  }
160 
161  if (robotA && robotB && (rA==rB)){
162  printf("contact within robot\n");
163  return;
164  }
165 
166  // start Finite-state machine
167  if (contactorA && contactorB){
168 
169  double angleA = rA->getBody()->GetAngle() - rA->m_referenceAngle;
170 
171  double angleB = rB->getBody()->GetAngle() - rB->m_referenceAngle;
172 
173  if(abs(angleA) > m_controllerParam.angle_limit && angleB > m_controllerParam.angle_limit){
174  rA->gripSide(contact, bodyContactB, m_M_TO_PX);
175  rA->setContact(true);
176  rB->gripSide(contact, bodyContactA, m_M_TO_PX);
177  rB->setContact(true);
178  setRobotState(*rA, BRIDGE);
179  setRobotState(*rB, BRIDGE); //TODO becareful changed rule
180  }
181  else if(abs(angleA) > m_controllerParam.angle_limit){
182  rA->gripSide(contact, bodyContactB, m_M_TO_PX);
183  rA->setContact(true);
184  setRobotState(*rA, BRIDGE); //WALK
185  setRobotState(*rB, BRIDGE); //TODO becareful changed rule
186  }
187 
188  else if(abs(angleB) > m_controllerParam.angle_limit){
189  rB->gripSide(contact, bodyContactA, m_M_TO_PX);
190  rB->setContact(true);
191  setRobotState(*rA, BRIDGE);
192  setRobotState(*rB, BRIDGE); //WALK
193  }
194 
195  }
196 
197  else if (contactorB){
198 
199  double angleB = rB->getBody()->GetAngle() - rB->m_referenceAngle;
200  if(abs(angleB) > m_controllerParam.angle_limit){
201  // if (m_robotVector[B].m_start){m_robotVector[B].m_start = false;}
202  rB->gripSide(contact, bodyContactA, m_M_TO_PX);
203  setRobotState(*rB, WALK);
204 
205  if (robotA){
206  setRobotState(*rA, BRIDGE);
207  }
208  }
209  }
210 
211  else if (contactorA){
212 
213  double angleA = rA->getBody()->GetAngle() - rA->m_referenceAngle;
214 // std::cout<<"angle robot: "<<moduloAngle(m_robotVector[A].getBody()->GetAngle())*RAD_TO_DEG<<std::endl;
215 // std::cout<<"angle A: "<<angleA*RAD_TO_DEG<<std::endl;
216 
217  if(abs(angleA) > m_controllerParam.angle_limit|| angleA==0){
218  // if (m_robotVector[A].m_start){m_robotVector[A].m_start = false;}
219  rA->gripSide(contact, bodyContactB, m_M_TO_PX);
220  setRobotState(*rA, WALK);
221 
222  if (robotB){
223  setRobotState(*rB, BRIDGE);
224  }
225  }
226  }
227  //printf("end of contact\n");
228 }
229 
231 
232  e_state S = robotState;
233  switch(S){
234  case WALK:
235 
236  if(!(robot.m_start)){
237  robot.setDelay(int(m_controllerParam.walk_delay*FPS));
238  }
239  robot.m_moving = false;
240  robot.setContact(true);
241  robot.setState(WALK);
242 // m_bridgeEntry = true;
243 // robot.setSpeed(2*PI);
244 // robot.m_referenceAngle = robot.getMotor(robot.m_movingSide)->GetJointAngle();
245 // robot.allowMotorRotation(LEFT);
246 
247 // robot.blockMotorRotation(LEFT);
248 // robot.blockMotorRotation(RIGHT);
249 
250 // robot.turnOffMotor(LEFT);
251 // robot.turnOffMotor(RIGHT);
252  //printf("case WALK, \n");
253  break;
254 
255  case BRIDGE:
256  robot.setDelay(int(m_controllerParam.bridge_delay*FPS));
257  robot.m_moving = false;
258  m_bridgeEntry = true;
259 
260  if (robot.getId() > m_idLastRobot){
261  m_idLastRobot = robot.getId();
262  m_stableTime = m_currentIt/FPS;
263  }
264  if (!(robot.getState()== BRIDGE)){
265  m_nbRobInBridge++;
266  robot.m_bridgeAge = m_currentIt;
267 
268  if(!robot.getMotor(robot.m_movingSide)){
269  printf("Pourquoi putain de nul \n");
270  }
271 
272 // robot.blockMotorRotation(LEFT);
273 // robot.blockMotorRotation(RIGHT);
274 
275  robot.limitMotorRotation(LEFT, 30/RAD_TO_DEG);
276  robot.limitMotorRotation(RIGHT, 30/RAD_TO_DEG);
277 
278  /*works even when consider the motor of the moving wheel instead of the one of the wheel that is attached because of the condition
279  * that the wheels cannot rotate --> abs(angle of left wheel) == abs(angle of right wheel)*/
280 // if(robot.getMotor(robot.m_movingSide)->GetJointAngle()){
281 // robot.m_referenceAngleJoint = robot.getMotor(robot.m_movingSide)->GetJointAngle();
282 // }
283 // else{
284 // robot.m_referenceAngleJoint = robot.getBody()->GetAngle();
285 // }
286 // robot.limitMotorRotation(robot.m_movingSide,30/RAD_TO_DEG);
287  robot.setState(BRIDGE);
288  }
289 
290  break;
291  }
292 }
293 
294 
295 
297  if (robot.isContact()){
298  if(robot.m_start){
299  robot.m_start = false;
300  }
301  robot.setContact(false);
302  side s = robot.m_movingSide;
303  b2World* world = robot.getBody()->GetWorld();
304  if(robot.nbJoint(s)== 0){
305 
306  b2PrismaticJointDef gripJointDef= robot.getJointDef(s);
307 // printf("create grip 1\n");
308  if((&gripJointDef == nullptr)){
309  return;
310  }
311  b2PrismaticJoint* gripJoint = static_cast<b2PrismaticJoint*>(world->CreateJoint( &gripJointDef ));
312 // printf("create grip 2\n");
313 // robot.setContact(false);
314  robot.incrementNbJoint(s);
315 
316 // robot.m_referenceAngle = robot.getMotor(robot.m_movingSide)->GetJointAngle();
317  robot.m_previousGripJoint = robot.m_currentGripJoint;
318  robot.m_currentGripJoint = gripJoint;
319  robot.m_referenceAngle = robot.getBody()->GetAngle();
320 
321  }
322  else{
323  printf("already a joint \n");
324  }
325  }
326 }
327 
329  if (robot.getDelay()==0 && (!robot.isMoving())){
330  robot.m_ready = true;
331  }
332 
333  else {
334  //robot.m_ready = false;
335  //printf("delai: %d tick left\n", robot.getDelay());
336  int delay = robot.getDelay()-1;
337  robot.setDelay(delay);
338  //printf("delai: %d tick left\n", robot.getDelay());
339  }
340 
341 }
342 
344  m_robotVector.push_back(robot);
345 }
346 
348  if(!m_robotToDestroy.empty()){
349  printf("remove 0 \n");
350 
351  for (int i=0; i<m_robotToDestroy.size(); i++){
352  int id = m_robotToDestroy[i];
353 
354  std::vector<Robot*>::iterator pRob = m_robotVector.begin()+id;
355  delete *pRob;
356  if(!(id == m_robotVector.size()-1)){
357  printf("remove 0b \n");
358  std::swap(m_robotVector[id], m_robotVector.back()); // check if same ?
359  printf("remove 0c \n");
360  }
361 
362  printf("remove 1 \n");
363  m_robotVector.pop_back();
364  printf("remove 2 \n");
365 
366  }
367  m_robotToDestroy.clear();
368  }
369 }
370 
371 void RobotController::robotOut(double end_x, int id){
372  int pos = (m_robotVector[id]->getBody()->GetWorldCenter()).x * m_M_TO_PX;
373  if(pos > end_x){
374  m_robotToDestroy.push_back(id);
375 // removeRobot(id);
376  }
377 }
378 
380  if(robot.m_movingSide == LEFT){
381  robot.m_movingSide = RIGHT;
382  }
383  else if(robot.m_movingSide == RIGHT){
384  robot.m_movingSide = LEFT;
385  }
386 // printf("invert moving whell \n \n");
387 }
388 
390 // printf("controller.destroyJoint \n");
391 // if(!(robot.m_previousGripJoint == nullptr)){
392  if(robot.nbJoint(s)>0){
393  if(robot.m_previousGripJoint){
394  robot.getBody()->GetWorld()->DestroyJoint(robot.m_previousGripJoint);
395  robot.m_previousGripJoint = nullptr;
396  robot.resetNbJoint(s);
397 // printf("a joint has been deleted \n");
398  }
399  }
400 }
401 
403  if(robot.isGrabbed()){
404  robot.setDelay(int(m_controllerParam.bridge_delay*60));
405  robot.setState(BRIDGE);
406  return true;
407  }
408  return false;
409 }
410 
412  if (m_stableTime > 0){
413  if (m_currentIt/FPS > (m_stableTime + m_controllerParam.stability_condition)){
414  return true;
415  }
416  }
417  return false;
418 }
419 
421  if (getNbRobots(BRIDGE) < 1 && !m_isDissolved){
422  m_isDissolved = true;
423  return true;
424  }
425  return false;
426 }
427 
429  return m_stableTime;
430 }
431 
433  return m_dissolutionTime;
434 }
435 
436 void RobotController::step(double end_x){
437 
438  for (int i=0; i<m_robotVector.size(); i++){
439 
440  if(m_robotVector[i]->getId()==-1){
441  printf("continue for loop \n");
442  continue;
443  }
444 
445  createGripRobots(*m_robotVector[i]);
446  wait_delay(*m_robotVector[i]);
447  checkGrabbed(*m_robotVector[i]); //TODO check if more optimized if check only for robots in bridge state
448 
449 
450  if(m_robotVector[i]->isReady()){
451 
452  if(m_robotVector[i]->getState()==BRIDGE){
453  m_nbRobInBridge--;
454  if(m_nbRobInBridge==0){
455  m_dissolutionTime = m_currentIt*FPS;
456  }
457  }
458 
459  m_robotVector[i]->m_ready=false;
460 // m_robotVector[i]->m_pushing_delay = - int(m_controllerParam.time_before_pushing*FPS+(m_currentIt-m_robotVector[i]->m_age)/600);
461 
462  m_robotVector[i]->setState(WALK);
463  m_robotVector[i]->m_bridgeAge = 0;
464 
465  m_robotVector[i]->m_moving=true;
466  if (m_robotVector[i]->checkGripp(m_robotVector[i]->m_movingSide)){
467  invertMovingWheel(*m_robotVector[i]);
468  }
469  else{
470  printf("\n wrong moving wheel \n");}
471  destroyJoints(*m_robotVector[i], m_robotVector[i]->m_movingSide);
472  m_robotVector[i]->moveBodyWithMotor();
473 // }
474  }
475 
476  if(m_robotVector[i]->isMoving()){
477  if(m_robotVector[i]->getDelay() == int(- m_controllerParam.time_before_pushing*FPS)){ //m_robotVector[i]->m_pushing_delay){ //
479 // invertMovingWheel(m_robotVector.at(i));
480  printf("\n Robot moving for too long, it is pushing \n");
481  if(robotPushing(*m_robotVector[i])){
482  setRobotState(*m_robotVector[i],WALK);
483  }
484  }
485  }
486 // m_robot[i].drawJoint(window);
487  robotOut(end_x, i);
488 // printf(joint);
489  }
490  m_currentIt ++;
491 
492 }
493 
495 
496  b2ContactEdge* contactList = r.getWheel(r.m_movingSide)->GetContactList();
497  b2Contact* contact = contactList->contact;
498  for (int i=0; i<10; i++){
499  if(contact->IsTouching() &&!(contactList->other == r.getBody()) && (r.contactOnGripSide(contact))){
500  double angle = abs(r.getBody()->GetAngle() - r.m_referenceAngle);
501  if(angle > m_angle_min ){
502 
503  if (! (contactList->other==m_terrainBody)){
504  Robot* r_other = static_cast<Robot*>( contactList->other->GetUserData() );
505  if(r_other->getId()>0){
506  setRobotState(*r_other, BRIDGE);
507  r.setContact(true);
508  r.gripSide(contact, contactList->other, m_M_TO_PX);
509  r.setDelay(m_controllerParam.walk_delay);
510  return true;
511  }
512  }
513  else{
514  r.setContact(true);
515  r.gripSide(contact, contactList->other, m_M_TO_PX);
516  r.setDelay(m_controllerParam.walk_delay);
517  return true;
518  }
519  }
520  }
521  if(contactList->next == nullptr){
522  r.setDelay(0);
523  return false;
524  }
525  contactList = contactList->next;
526  contact = contactList->contact;
527  }
528  r.setDelay(0);
529  return false;
530 }
531 
533  float x=r->getBody()->GetPosition().x;
534  if(x < (m_robotParam.body_length + posX)){
535  return true;
536  }
537  return false;
538 }
540  m_isStable = stable;
541 }
543  int n = 0;
544  for (int i=0; i<m_robotVector.size(); i++){
545  if(m_robotVector[i]->getState() == s){
546  n++;
547  }
548  }
549  return n;
550 }
551 
553  return m_robotVector.size();
554 }
555 
557  float h = INT_MAX;
558  int id = 0;
559  int nb_blocked = 0;
560  for (int i=0; i<m_robotVector.size(); i++){
561  if(m_robotVector[i]->getState() == BRIDGE){
562  if(m_robotVector[i]->getPosition().y < h){
563  h=m_robotVector[i]->getPosition().y;
564  id=m_robotVector[i]->getId();
565  }
566  }
567  }
568  for (int i=0; i<m_robotVector.size(); i++){
569  if(m_robotVector[i]->getState() == WALK){
570  if(m_robotVector[i]->getPosition().y > h && m_robotVector[i]->getId()<id){
571  nb_blocked ++;
572  }
573  }
574  }
575  return nb_blocked;
576 }
577 
578 
side
Definition: Robot.h:30
bool robotStacking(Robot *r, float posX)
void robotOut(double end_x, int id)
void findContactRobots(b2Contact *contact)
bool isGrabbed()
Definition: Robot.cpp:938
double getDissolutionTime()
int getNbRobots(e_state s)
Robot * getRobotWithId(int id)
void setBridgeStability(bool stable)
void setDelay(int delay)
Definition: Robot.cpp:1023
bool checkGrabbed(Robot &robot)
void setNbRobots(int nb_robots)
int getId()
Definition: Robot.cpp:1053
e_state
Definition: Robot.h:26
void drawRobots(sf::RenderWindow &window, double m_to_px)
Robot * getRobot(int pos_id)
void addRobot(Robot *robot)
bool isMoving()
Definition: Robot.cpp:1085
bool createRobot(b2World *world, int delay, double posX, double posY, double angle=0)
b2PrismaticJointDef getJointDef(side s)
Definition: Robot.cpp:1056
void wait_delay(Robot &robot)
Definition: Robot.h:40
e_state getState()
Definition: Robot.cpp:1069
b2Body * getWheel(side s)
Definition: Robot.cpp:1072
void limitMotorRotation(side s, double limit_angle_rad)
Definition: Robot.cpp:543
void resetNbJoint(side s)
Definition: Robot.cpp:1007
void incrementNbJoint(side s)
Definition: Robot.cpp:999
void setContact(bool contact)
Definition: Robot.cpp:1020
bool isContact()
Definition: Robot.cpp:1082
b2RevoluteJoint * getMotor(side s)
Definition: Robot.cpp:982
void setRobotState(Robot &robot, e_state robotState)
bool gripSide(b2Contact *contact, b2Body *otherBody, double m_to_px)
Definition: Robot.cpp:641
void destroyJoints(Robot &robot, side s)
void invertMovingWheel(Robot &robot)
int getDelay()
Definition: Robot.cpp:1048
b2Body * getBody()
Definition: Robot.cpp:1041
int nbJoint(side s)
Definition: Robot.cpp:991
Implement the RobotController class. This class act as a supervisor for the Robots.
void step(double end_x)
void setScale(double m_to_px)
double getStabilizationTime()
void setState(e_state state)
Definition: Robot.cpp:1033
b2PrismaticJoint * m_previousGripJoint
Definition: Robot.h:287
bool robotPushing(Robot &r)
void createGripRobots(Robot &robot)