Navigate to a given point using the OGM and virtual forces

Dependencies:   ISR_Mini-explorer mbed

Fork of VirtualForces by Georgios Tsamis

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "robot.h" // Initializes the robot. This include should be used in all main.cpp!
00003 #include "math.h"
00004 
00005 using namespace std;
00006 
00007 //makes the angle inAngle between pi and minus pi
00008 float rad_angle_check_pi_and_minus_pi(float inAngle);
00009 void initialise_parameters();
00010 //fill initialLogValues with the values we already know (here the bordurs)
00011 void fill_initial_log_values();
00012 //generate a position randomly and makes the robot go there while updating the map
00013 void randomize_and_map();
00014 //make the robot do a pi/2 flip
00015 void do_half_flip();
00016 //go the the given position while updating the map
00017 void go_to_point_with_angle(float target_x, float target_y, float target_angle);
00018 //Updates sonar values 
00019 void update_sonar_values(float leftMm, float frontMm, float rightMm);
00020 //function that check if a cell A(x,y) is in the range of the front sonar S(xs,ys) (with an angle depending on the sonar used, front 0, left pi/3, right -pi/3) returns the probability it's occupied/empty [0;1]
00021 float compute_probability_t(float x, float y,float xs,float ys, float angleFromSonarPosition, float distanceObstacleDetected);
00022 //print the map
00023 void print_final_map();
00024 //print the map with the robot marked on it
00025 void print_final_map_with_robot_position();
00026 //print the map with the robot and the target marked on it
00027 void print_final_map_with_robot_position_and_target();
00028 //go to a given line by updating angularLeft and angularRight
00029 void go_to_line(float* angularLeft,float* angularRight,float line_a, float line_b, float line_c);
00030 //calculate virtual force field and move
00031 void vff(bool* reached);
00032 void test_got_to_line(bool* reached);
00033 
00034 //MATHS heavy functions
00035 float dist(float robot_x, float robot_y, float target_x, float target_y);
00036 //returns the probability [0,1] that the cell is occupied from the log value lt
00037 float log_to_proba(float lt);
00038 //returns the log value that the cell is occupied from the probability value [0,1]
00039 float proba_to_log(float p);
00040 //returns the new log value
00041 float compute_log_estimation_lt(float previousLogValue,float currentProbability,float originalLogvalue );
00042 //makes the angle inAngle between 0 and 2pi
00043 float rad_angle_check(float inAngle);
00044 //returns the angle between the vectors (x,y) and (xs,ys)
00045 float compute_angle_between_vectors(float x, float y,float xs,float ys);
00046 float x_robot_in_orthonormal_x(float x, float y);
00047 float y_robot_in_orthonormal_y(float x, float y);
00048 float robot_center_x_in_orthonormal_x();
00049 float robot_center_y_in_orthonormal_y();
00050 float robot_sonar_front_x_in_orthonormal_x();
00051 float robot_sonar_front_y_in_orthonormal_y();
00052 float robot_sonar_right_x_in_orthonormal_x();
00053 float robot_sonar_right_y_in_orthonormal_y();
00054 float robot_sonar_left_x_in_orthonormal_x();
00055 float robot_sonar_left_y_in_orthonormal_y();
00056 float estimated_width_indice_in_orthonormal_x(int i);
00057 float estimated_height_indice_in_orthonormal_y(int j);
00058 //update angleError,distanceFromTarget,d2, beta
00059 void compute_angles_and_distance(float target_x, float target_y, float target_angle,float dt,float* angleError,float* distanceFromTarget,float* d2,float* beta);
00060 //update angularLeft and angularRight
00061 void compute_linear_angular_velocities(float angleError,float distanceFromTarget,float beta, float* angularLeft, float* angularRight);
00062 //update foceX and forceY if necessary
00063 void update_force(int widthIndice, int heightIndice, float range, float* forceX, float* forceY, float xRobotOrtho, float yRobotOrtho );
00064 //compute the X and Y force
00065 void compute_forceX_and_forceY(float* forceX, float* forceY);
00066 //robotX and robotY are from Odometria, calculate line_a, line_b and line_c
00067 void calculate_line(float forceX, float forceY, float robotX, float robotY,float *line_a, float *line_b, float *line_c);
00068 //return 1 if positiv, -1 if negativ
00069 float sign1(float value);
00070 //return 1 if positiv, 0 if negativ
00071 int sign2(float value);
00072 //set target in ortho space, in reference to the robot (so if the robot is in the middle, you want to him to go 10cm down and 15 right, set_target_to(15,-10)
00073 void set_target_to(float x, float y);
00074 void try_to_reach_target();
00075 
00076 const float pi=3.14159;
00077 
00078 //spec of the sonar
00079 //TODO MEASURE THE DISTANCE on X and Y of the robot space, between each sonar and the center of the robot and add it to calculus in updateSonarValues
00080 const float RANGE_SONAR=50;//cm
00081 const float RANGE_SONAR_MIN=10;//Rmin cm
00082 const float INCERTITUDE_SONAR=10;//cm
00083 const float ANGLE_SONAR=pi/3;//Omega rad
00084 
00085 //those distance and angle are approximation in need of measurements, in the orthonormal space
00086 const float ANGLE_FRONT_TO_LEFT=10*pi/36;//50 degrees
00087 const float DISTANCE_SONAR_LEFT_X=-4;
00088 const float DISTANCE_SONAR_LEFT_Y=4;
00089 
00090 const float ANGLE_FRONT_TO_RIGHT=-10*pi/36;//-50 degrees
00091 const float DISTANCE_SONAR_RIGHT_X=4;
00092 const float DISTANCE_SONAR_RIGHT_Y=4;
00093 
00094 const float ANGLE_FRONT_TO_FRONT=0;
00095 const float DISTANCE_SONAR_FRONT_X=0;
00096 const float DISTANCE_SONAR_FRONT_Y=5;
00097 
00098 //TODO adjust the size of the map for computation time (25*25?)
00099 const float WIDTH_ARENA=120;//cm
00100 const float HEIGHT_ARENA=90;//cm
00101 
00102 //const int SIZE_MAP=25;
00103 const int NB_CELL_WIDTH=24;
00104 const int NB_CELL_HEIGHT=18;
00105 
00106 //position and orientation of the robot when put on the map (ODOMETRY doesn't know those) it's in the robot space
00107 //this configuration suppose that the robot is in the middle of the arena facing up (to be sure you can use print_final_map_with_robot_position
00108 //const float DEFAULT_X=HEIGHT_ARENA/2;
00109 //const float DEFAULT_Y=WIDTH_ARENA/2;
00110 const float DEFAULT_X=20;//lower right
00111 const float DEFAULT_Y=20;//lower right
00112 const float DEFAULT_THETA=0;
00113 
00114 //used to create the map 250 represent the 250cm of the square where the robot is tested
00115 //float sizeCell=250/(float)SIZE_MAP;
00116 float sizeCellWidth=WIDTH_ARENA/(float)NB_CELL_WIDTH;
00117 float sizeCellHeight=HEIGHT_ARENA/(float)NB_CELL_HEIGHT;
00118 
00119 float map[NB_CELL_WIDTH][NB_CELL_HEIGHT];//contains the log values for each cell
00120 float initialLogValues[NB_CELL_WIDTH][NB_CELL_HEIGHT];
00121 
00122 //Diameter of a wheel and distance between the 2
00123 const float RADIUS_WHEELS=3.25;
00124 const float DISTANCE_WHEELS=7.2;
00125 
00126 const int MAX_SPEED=200;//TODO TWEAK THE SPEED SO IT DOES NOT FUCK UP
00127 
00128 //TODO all those global variables are making me sad
00129 const float KRHO=12, KA=30, KB=-13, KV=150, KH=150; //Kappa values
00130 
00131 //CONSTANT FORCE FIELD
00132 const float FORCE_CONSTANT_REPULSION=80;//TODO tweak it
00133 const float FORCE_CONSTANT_ATTRACTION=25;//TODO tweak it
00134 const float RANGE_FORCE=50;//TODO tweak it
00135 
00136 //those target are in comparison to the robot (for exemple a robot in 50,50 with a taget of 0,0 would not need to move)
00137 float targetX;//this is in the robot space top left
00138 float targetY;//this is in the robot space top left
00139 float targetXOrtho;
00140 float targetYOrtho;
00141 
00142 bool direction;
00143 
00144 int main(){
00145     initialise_parameters();   
00146     //try to reach the target     
00147     set_target_to(0,50);//up right
00148     print_final_map_with_robot_position_and_target();
00149     try_to_reach_target();
00150     set_target_to(0,-50);//lower right
00151     print_final_map_with_robot_position_and_target();
00152     try_to_reach_target();
00153     set_target_to(-50,50);//up left
00154     print_final_map_with_robot_position_and_target();
00155     try_to_reach_target();
00156     //print the map forever
00157     while(1){
00158          print_final_map_with_robot_position_and_target();
00159     }
00160 }
00161 
00162 void try_to_reach_target(){
00163     bool reached=false;
00164     int print=0;
00165     while (!reached) {
00166         vff(&reached);
00167         //test_got_to_line(&reached);
00168         if(print==10){
00169             leftMotor(1,0);
00170             rightMotor(1,0);
00171             pc.printf("\r\n theta=%f", theta);
00172             pc.printf("\r\n IN ORTHO:");
00173             pc.printf("\r\n X Robot=%f", robot_center_x_in_orthonormal_x());
00174             pc.printf("\r\n Y Robot=%f", robot_center_y_in_orthonormal_y());
00175             pc.printf("\r\n X Target=%f", targetXOrtho);
00176             pc.printf("\r\n Y Target=%f", targetYOrtho);
00177             print_final_map_with_robot_position_and_target();
00178             print=0;
00179         }else
00180             print+=1;
00181     }
00182     //Stop at the end
00183     leftMotor(1,0);
00184     rightMotor(1,0);
00185     pc.printf("\r\n target reached");
00186 }
00187 
00188 //target in ortho space
00189 void set_target_to(float x, float y){
00190     targetX=y;
00191     targetY=-x;
00192     targetXOrtho=x_robot_in_orthonormal_x(targetX,targetY);
00193     targetYOrtho=y_robot_in_orthonormal_y(targetX,targetY);
00194     
00195     pc.printf("\r\nangletarget= %f", atan2(x,y));
00196     float angleError = atan2(x,y)-theta;
00197     if(angleError>pi) angleError-=2*pi;
00198     if(angleError<-pi) angleError+=2*pi;
00199         
00200     if(angleError<(pi/2) && angleError>(-pi/2)) direction=true;
00201     else direction=false;
00202     pc.printf("\r\nangleError= %f", angleError);
00203 }
00204 
00205 void initialise_parameters(){
00206     i2c1.frequency(100000);
00207     initRobot(); //Initializing the robot
00208     pc.baud(9600); // baud for the pc communication
00209 
00210     measure_always_on();//TODO check if needed
00211     wait(0.5);
00212     //fill the map with the initial log values
00213     fill_initial_log_values();
00214 
00215     theta=DEFAULT_THETA;
00216     X=DEFAULT_X;
00217     Y=DEFAULT_Y;
00218 }
00219 
00220 //fill initialLogValues with the values we already know (here the bordurs)
00221 void fill_initial_log_values(){
00222     //Fill map, we know the border are occupied
00223     for (int i = 0; i<NB_CELL_WIDTH; i++) {
00224         for (int j = 0; j<NB_CELL_HEIGHT; j++) {
00225             if(j==0 || j==NB_CELL_HEIGHT-1 || i==0 || i==NB_CELL_WIDTH-1)
00226                 initialLogValues[i][j] = proba_to_log(1);
00227             else
00228                 initialLogValues[i][j] = proba_to_log(0.5);
00229         }
00230     }
00231 }
00232 
00233 //generate a position randomly and makes the robot go there while updating the map
00234 void randomize_and_map() {
00235     //TODO check that it's aurelien's work
00236     float target_x = (rand()%(int)(HEIGHT_ARENA*10))/10;//for decimal precision
00237     float target_y = (rand()%(int)(WIDTH_ARENA*10))/10;
00238     float target_angle = 2*((float)(rand()%31416)-15708)/10000.0;
00239     
00240     go_to_point_with_angle(targetX, targetY, target_angle);
00241 }
00242 
00243 
00244 void do_half_flip(){
00245     Odometria();
00246     float theta_plus_h_pi=theta+pi/2;//theta is between -pi and pi
00247     if(theta_plus_h_pi > pi)
00248         theta_plus_h_pi=-(2*pi-theta_plus_h_pi);
00249     leftMotor(0,100);
00250     rightMotor(1,100);
00251     while(abs(theta_plus_h_pi-theta)>0.05){
00252         Odometria();
00253        // pc.printf("\n\r diff=%f", abs(theta_plus_pi-theta));
00254     }
00255     leftMotor(1,0);
00256     rightMotor(1,0);    
00257 }
00258 
00259 //go the the given position while updating the map
00260 //TODO clean this procedure it's ugly as hell and too long
00261 void go_to_point_with_angle(float target_x, float target_y, float target_angle) {
00262     set_target_to(target_x,target_y);
00263     Odometria();
00264     float angleError = atan2((target_y-Y),(target_x-X))-theta;
00265     if(!cos(angleError))
00266         angleError = atan(sin(angleError)/cos(angleError));
00267     else
00268         angleError=pi/2;
00269     if(isnan(angleError)) pc.printf("\r\n nan line 264");
00270     float distanceFromTarget = dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrtho,targetYOrtho);
00271     float beta = -angleError-theta+target_angle;
00272     //beta = atan(sin(beta)/cos(beta));
00273     bool keep_going=true;
00274     float leftMm;
00275     float frontMm;
00276     float rightMm;
00277     float angularLeft=0; 
00278     float angularRight=0;
00279     Timer t;
00280     float dt=0.5;//TODO better name please
00281     float d2;//TODO better name please
00282     do {
00283         //Timer stuff
00284         dt = t.read();
00285         t.reset();
00286         t.start();
00287         
00288         //Updating X,Y and theta with the odometry values
00289         Odometria();
00290         leftMm = get_distance_left_sensor();
00291         frontMm = get_distance_front_sensor();
00292         rightMm = get_distance_right_sensor();
00293 
00294         //pc.printf("\n\r leftMm=%f", leftMm);
00295         //pc.printf("\n\r frontMm=%f", frontMm);
00296         //pc.printf("\n\r rightMm=%f", rightMm);
00297     
00298         //if in dangerzone 
00299         if(frontMm < 120 || leftMm <120 || rightMm <120){
00300             leftMotor(1,0);
00301             rightMotor(1,0);
00302             update_sonar_values(leftMm, frontMm, rightMm);
00303             //TODO Giorgos maybe you can also test the do_half_flip() function
00304             Odometria();
00305             //do a flip TODO
00306             keep_going=false;
00307             do_half_flip();   
00308         }else{
00309             //if not in danger zone continue as usual
00310             update_sonar_values(leftMm, frontMm, rightMm);
00311             compute_angles_and_distance(target_x, target_y, target_angle,dt,&angleError,&distanceFromTarget,&d2,&beta);//Compute the angles and the distance from target
00312             compute_linear_angular_velocities(angleError,distanceFromTarget,beta,&angularLeft,&angularRight); //Using the angles and distance, compute the velocities needed (linear & angular)
00313             
00314             //pc.printf("\n\r X=%f", X);
00315             //pc.printf("\n\r Y=%f", Y);
00316     
00317             //pc.printf("\n\r a_r=%f", angularRight);
00318             //pc.printf("\n\r a_l=%f", angularLeft);
00319     
00320             //Updating motor velocities
00321             leftMotor(sign2(angularLeft),abs(angularLeft));
00322             rightMotor(sign2(angularRight),abs(angularRight));
00323     
00324             wait(0.2);
00325             //Timer stuff
00326             t.stop();
00327         }
00328     } while(d2>1 && (abs(target_angle-theta)>0.01) && keep_going);
00329 
00330     //Stop at the end
00331     leftMotor(1,0);
00332     rightMotor(1,0);
00333 }
00334 
00335 //Updates sonar values
00336 void update_sonar_values(float leftMm, float frontMm, float rightMm){
00337     float currProba;
00338     float i_in_orthonormal;
00339     float j_in_orthonormal;
00340     for(int i=0;i<NB_CELL_WIDTH;i++){
00341         for(int j=0;j<NB_CELL_HEIGHT;j++){
00342                 //check if the point A(x,y) in the world space is within the range of the sonar (which has the coordinates xs, ys in the world space)
00343             //check that again
00344             //compute for front sonar
00345             i_in_orthonormal=estimated_width_indice_in_orthonormal_x(i);
00346             j_in_orthonormal=estimated_height_indice_in_orthonormal_y(j);
00347 
00348             currProba=compute_probability_t(i_in_orthonormal,j_in_orthonormal,robot_sonar_front_x_in_orthonormal_x(),robot_sonar_front_y_in_orthonormal_y(),ANGLE_FRONT_TO_FRONT,frontMm/10);
00349             if(isnan(currProba)) pc.printf("\r\n currProba is nan");
00350             map[i][j]=map[i][j]+proba_to_log(currProba)+initialLogValues[i][j];//map is filled as map[0][0] get the data for the point closest to the origin
00351             //compute for right sonar
00352             currProba=compute_probability_t(i_in_orthonormal,j_in_orthonormal,robot_sonar_right_x_in_orthonormal_x(),robot_sonar_right_y_in_orthonormal_y(),ANGLE_FRONT_TO_RIGHT,rightMm/10);
00353             map[i][j]=map[i][j]+proba_to_log(currProba)+initialLogValues[i][j];
00354              //compute for left sonar
00355             currProba=compute_probability_t(i_in_orthonormal,j_in_orthonormal,robot_sonar_left_x_in_orthonormal_x(),robot_sonar_left_y_in_orthonormal_y(),ANGLE_FRONT_TO_LEFT,leftMm/10);
00356             if(isnan(currProba)) pc.printf("\r\n nan line 354");
00357             map[i][j]=map[i][j]+proba_to_log(currProba)+initialLogValues[i][j];
00358             if(isnan(proba_to_log(currProba))) pc.printf("\r\nnan in line 355");
00359         }
00360     }
00361 }
00362 
00363 //makes the angle inAngle between pi and minus pi
00364 float rad_angle_check_pi_and_minus_pi(float inAngle){
00365     //cout<<"before :"<<inAngle;
00366     if(inAngle > 0){
00367         while(inAngle > (pi))
00368             inAngle-=pi;
00369     }else{
00370         while(inAngle < 0)
00371             inAngle+=pi;
00372     }
00373     //cout<<" after :"<<inAngle<<endl;
00374     return inAngle;
00375 }
00376 
00377 //ODOMETRIA MUST HAVE BEEN CALLED
00378 //function that check if a cell A(x,y) is in the range of the front sonar S(xs,ys) (with an angle depending on the sonar used, front 0, left pi/3, right -pi/3) returns the probability it's occupied/empty [0;1]
00379 float compute_probability_t(float x, float y,float xs,float ys, float angleFromSonarPosition, float distanceObstacleDetected){
00380 
00381     float anglePointToSonar=compute_angle_between_vectors(x,y,xs,ys);//angle beetween the point and the sonar beam
00382     float alphaBeforeAdjustment=anglePointToSonar-theta-angleFromSonarPosition;
00383     anglePointToSonar=rad_angle_check(alphaBeforeAdjustment);//TODO I feel you don't need to do that but I m not sure
00384     alphaBeforeAdjustment=rad_angle_check_pi_and_minus_pi(alphaBeforeAdjustment);
00385     //if(abs(alphaBeforeAdjustment)>ANGLE_SONAR/2) pc.printf("\r\n it is!");
00386     float distancePointToSonar=sqrt(pow(x-xs,2)+pow(y-ys,2));
00387 
00388     //check if the distance between the cell and the robot is within the circle of range RADIUS_WHEELS
00389     //check if absolute difference between the angles is no more than Omega/2
00390     if( distancePointToSonar < (RANGE_SONAR)&& (anglePointToSonar <= ANGLE_SONAR/2 || anglePointToSonar >= rad_angle_check(-ANGLE_SONAR/2))){
00391         if( distancePointToSonar < (distanceObstacleDetected - INCERTITUDE_SONAR)){
00392         //point before obstacle, probably empty
00393         /*****************************************************************************/
00394             float Ea=1.f-pow((2*alphaBeforeAdjustment)/ANGLE_SONAR,2);
00395             float Er;
00396             if(distancePointToSonar < RANGE_SONAR_MIN){
00397                 //point before minimum sonar range
00398                 Er=0.f;
00399             }else{
00400                 //point after minimum sonar range
00401                 Er=1.f-pow((distancePointToSonar-RANGE_SONAR_MIN)/(distanceObstacleDetected-INCERTITUDE_SONAR-RANGE_SONAR_MIN),2);
00402             }
00403          /*****************************************************************************/
00404             if((1.f-Er*Ea)/2.f>1) pc.printf("\r\n E>1");
00405             if((1.f-Er*Ea)/2.f<0) pc.printf("\r\n E<0");
00406             return (1.f-Er*Ea)/2.f;
00407         }else{
00408             //probably occupied
00409         /*****************************************************************************/
00410             float Oa=1.f-pow((2*alphaBeforeAdjustment)/ANGLE_SONAR,2);
00411             float Or;
00412             if( distancePointToSonar <= (distanceObstacleDetected + INCERTITUDE_SONAR)){
00413                 //point between distanceObstacleDetected +- INCERTITUDE_SONAR
00414                 Or=1-pow((distancePointToSonar-distanceObstacleDetected)/(INCERTITUDE_SONAR),2);
00415             }else{
00416                 //point after in range of the sonar but after the zone detected
00417                 Or=0;
00418             }
00419         /*****************************************************************************/
00420             if((1+Or*Oa)/2>1) pc.printf("\r\n O>1");
00421             if((1+Or*Oa)/2<0) pc.printf("\r\n O<0");
00422             return (1+Or*Oa)/2;
00423         }
00424     }
00425    //not checked by the sonar
00426    return 0.5;
00427 }
00428 
00429 void print_final_map() {
00430     float currProba;
00431     pc.printf("\n\r");
00432     for (int y = NB_CELL_HEIGHT -1; y>-1; y--) {
00433         for (int x= 0; x<NB_CELL_WIDTH; x++) {
00434                 currProba=log_to_proba(map[x][y]);
00435             if ( currProba < 0.5) {
00436                 pc.printf("   ");
00437             } else {
00438                 if(currProba==0.5)
00439                     pc.printf(" . ");
00440                 else
00441                     pc.printf(" X ");
00442             }
00443         }
00444         pc.printf("\n\r");
00445     }
00446 }
00447 
00448 void print_final_map_with_robot_position() {
00449     float currProba;
00450     Odometria();
00451     float Xrobot=robot_center_x_in_orthonormal_x();
00452     float Yrobot=robot_center_y_in_orthonormal_y();
00453     
00454     float heightIndiceInOrthonormal;
00455     float widthIndiceInOrthonormal;
00456     
00457     float widthMalus=-(3*sizeCellWidth/2);
00458     float widthBonus=sizeCellWidth/2;
00459     
00460     float heightMalus=-(3*sizeCellHeight/2);
00461     float heightBonus=sizeCellHeight/2;
00462 
00463     pc.printf("\n\r");
00464     for (int y = NB_CELL_HEIGHT -1; y>-1; y--) {
00465         for (int x= 0; x<NB_CELL_WIDTH; x++) {
00466             heightIndiceInOrthonormal=estimated_height_indice_in_orthonormal_y(y);
00467             widthIndiceInOrthonormal=estimated_width_indice_in_orthonormal_x(x);
00468             if(Yrobot >= (heightIndiceInOrthonormal+heightMalus) && Yrobot <= (heightIndiceInOrthonormal+heightBonus) && Xrobot >= (widthIndiceInOrthonormal+widthMalus) && Xrobot <= (widthIndiceInOrthonormal+widthBonus))                    
00469                 pc.printf(" R ");
00470             else{
00471                 currProba=log_to_proba(map[x][y]);
00472                 if ( currProba < 0.5)
00473                     pc.printf("   ");
00474                 else{
00475                     if(currProba==0.5)
00476                         pc.printf(" . ");
00477                     else
00478                         pc.printf(" X ");
00479                 } 
00480             }
00481         }
00482         pc.printf("\n\r");
00483     }
00484 }
00485 
00486 void print_final_map_with_robot_position_and_target() {
00487     float currProba;
00488     Odometria();
00489     float Xrobot=robot_center_x_in_orthonormal_x();
00490     float Yrobot=robot_center_y_in_orthonormal_y();
00491     
00492     float heightIndiceInOrthonormal;
00493     float widthIndiceInOrthonormal;
00494     
00495     float widthMalus=-(3*sizeCellWidth/2);
00496     float widthBonus=sizeCellWidth/2;
00497     
00498     float heightMalus=-(3*sizeCellHeight/2);
00499     float heightBonus=sizeCellHeight/2;
00500 
00501     pc.printf("\n\r");
00502     for (int y = NB_CELL_HEIGHT -1; y>-1; y--) {
00503         for (int x= 0; x<NB_CELL_WIDTH; x++) {
00504             heightIndiceInOrthonormal=estimated_height_indice_in_orthonormal_y(y);
00505             widthIndiceInOrthonormal=estimated_width_indice_in_orthonormal_x(x);
00506             if(Yrobot >= (heightIndiceInOrthonormal+heightMalus) && Yrobot <= (heightIndiceInOrthonormal+heightBonus) && Xrobot >= (widthIndiceInOrthonormal+widthMalus) && Xrobot <= (widthIndiceInOrthonormal+widthBonus))
00507                 pc.printf(" R ");
00508             else{
00509                 if(targetYOrtho >= (heightIndiceInOrthonormal+heightMalus) && targetYOrtho <= (heightIndiceInOrthonormal+heightBonus) && targetXOrtho >= (widthIndiceInOrthonormal+widthMalus) && targetXOrtho <= (widthIndiceInOrthonormal+widthBonus))                    
00510                     pc.printf(" T ");
00511                 else{
00512                     currProba=log_to_proba(map[x][y]);
00513                     if ( currProba < 0.5)
00514                         pc.printf("   ");
00515                     else{
00516                         if(currProba==0.5)
00517                             pc.printf(" . ");
00518                         else
00519                             pc.printf(" X ");
00520                     } 
00521                 }
00522             }
00523         }
00524         pc.printf("\n\r");
00525     }
00526 }
00527 
00528 //MATHS heavy functions
00529 /**********************************************************************/
00530 //Distance computation function
00531 float dist(float robot_x, float robot_y, float target_x, float target_y){
00532     return sqrt(pow(target_y-robot_y,2) + pow(target_x-robot_x,2));
00533 }
00534 
00535 //returns the probability [0,1] that the cell is occupied from the log value lt
00536 float log_to_proba(float lt){
00537     float temp=1-1/(1+exp(lt));
00538     if(isnan(temp)){
00539         //pc.printf("\r\n nan in line 514");
00540         //pc.printf("\r\nlt= %f, 1+exp(lt)= %f", lt, 1+exp(lt));
00541     }
00542     return temp;
00543 }
00544 
00545 //returns the log value that the cell is occupied from the probability value [0,1]
00546 float proba_to_log(float p){
00547     float temp;
00548     if(p==1) temp=log(0.99/(1-0.99));
00549     else temp=log(p/(1-p));
00550     if(isnan(temp)) pc.printf("\r\n temp=%f, p=%f", temp,p);
00551     return temp;
00552 }
00553 
00554 //returns the new log value
00555 float compute_log_estimation_lt(float previousLogValue,float currentProbability,float originalLogvalue ){
00556     return previousLogValue+proba_to_log(currentProbability)-originalLogvalue;
00557 }
00558 
00559 //makes the angle inAngle between 0 and 2pi
00560 float rad_angle_check(float inAngle){
00561     //cout<<"before :"<<inAngle;
00562     if(inAngle > 0){
00563         while(inAngle > (2*pi))
00564             inAngle-=2*pi;
00565     }else{
00566         while(inAngle < 0)
00567             inAngle+=2*pi;
00568     }
00569     //cout<<" after :"<<inAngle<<endl;
00570     return inAngle;
00571 }
00572 
00573 //returns the angle between the vectors (x,y) and (xs,ys)
00574 float compute_angle_between_vectors(float x, float y,float xs,float ys){
00575     //alpha angle between ->x and ->SA
00576     //vector S to A ->SA
00577     float vSAx=x-xs;
00578     float vSAy=y-ys;
00579     //norme SA
00580     float normeSA=sqrt(pow(vSAx,2)+pow(vSAy,2));
00581     //vector ->x (1,0)
00582     float cosAlpha=1*vSAy/*+0*vSAx*//normeSA;;
00583     //vector ->y (0,1)
00584     float sinAlpha=/*0*vSAy+*/1*vSAx/normeSA;//+0*vSAx;
00585     if (sinAlpha < 0)
00586         return -acos(cosAlpha);
00587     else
00588         return acos(cosAlpha);
00589 }
00590 /*
00591 
00592 
00593 Robot space:      orthonormal space:
00594       ^                 ^
00595       |x                |y
00596    <- R                 O ->
00597     y                     x
00598 */
00599 //Odometria must bu up to date
00600 float x_robot_in_orthonormal_x(float x, float y){
00601     return robot_center_x_in_orthonormal_x()-y;
00602 }
00603 
00604 //Odometria must bu up to date
00605 float y_robot_in_orthonormal_y(float x, float y){
00606     return robot_center_y_in_orthonormal_y()+x;
00607 }
00608 
00609 float robot_center_x_in_orthonormal_x(){
00610     return NB_CELL_WIDTH*sizeCellWidth-Y;
00611 }
00612 
00613 float robot_center_y_in_orthonormal_y(){
00614     return X;
00615 }
00616 
00617 float robot_sonar_front_x_in_orthonormal_x(){
00618     return robot_center_x_in_orthonormal_x()+DISTANCE_SONAR_FRONT_X;
00619 }
00620 float robot_sonar_front_y_in_orthonormal_y(){
00621     return robot_center_y_in_orthonormal_y()+DISTANCE_SONAR_FRONT_Y;
00622 }
00623 
00624 float robot_sonar_right_x_in_orthonormal_x(){
00625     return robot_center_x_in_orthonormal_x()+DISTANCE_SONAR_RIGHT_X;
00626 }
00627 float robot_sonar_right_y_in_orthonormal_y(){
00628     return robot_center_y_in_orthonormal_y()+DISTANCE_SONAR_RIGHT_Y;
00629 }
00630 
00631 float robot_sonar_left_x_in_orthonormal_x(){
00632     return robot_center_x_in_orthonormal_x()+DISTANCE_SONAR_LEFT_X;
00633 }
00634 float robot_sonar_left_y_in_orthonormal_y(){
00635     return robot_center_y_in_orthonormal_y()+DISTANCE_SONAR_LEFT_Y;
00636 }
00637 
00638 float estimated_width_indice_in_orthonormal_x(int i){
00639     return sizeCellWidth/2+i*sizeCellWidth;
00640 }
00641 float estimated_height_indice_in_orthonormal_y(int j){
00642     return sizeCellHeight/2+j*sizeCellHeight;
00643 }
00644 
00645 //update angleError,distanceFromTarget,d2, beta
00646 void compute_angles_and_distance(float target_x, float target_y, float target_angle,float dt,float* angleError,float* distanceFromTarget,float* d2,float* beta){
00647     *angleError = atan2((target_y-Y),(target_x-X))-theta;
00648     if(!cos(*angleError))
00649         *angleError = atan(sin(*angleError)/cos(*angleError));
00650     else
00651         *angleError=pi/2;
00652     if(isnan(*angleError)) pc.printf("\r\n nan line 613");
00653     *distanceFromTarget = dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrtho,targetYOrtho);
00654     *d2 = *distanceFromTarget;
00655     *beta = -*angleError-theta+target_angle;        
00656     
00657     //Computing angle error and distance towards the target value
00658     *distanceFromTarget += dt*(-KRHO*cos(*angleError)**distanceFromTarget);
00659     float temp = *angleError;
00660     *angleError += dt*(KRHO*sin(*angleError)-KA**angleError-KB**beta);
00661     *beta += dt*(-KRHO*sin(temp));
00662    //pc.printf("\n\r d2=%f", d2);
00663     //pc.printf("\n\r dt=%f", dt);
00664 }
00665 
00666 //update angularLeft and angularRight
00667 void compute_linear_angular_velocities(float angleError,float distanceFromTarget,float beta,float* angularLeft, float* angularRight){
00668     //Computing linear and angular velocities
00669     float linear;
00670     float angular;
00671     if(angleError>=-1.5708 && angleError<=1.5708){
00672         linear=KRHO*distanceFromTarget;
00673         angular=KA*angleError+KB*beta;
00674     }
00675     else{
00676         linear=-KRHO*distanceFromTarget;
00677         angular=-KA*angleError-KB*beta;
00678     }
00679     //TODO check those signs
00680     *angularLeft=(linear-0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00681     *angularRight=(linear+0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00682     
00683     float aL=*angularLeft;
00684     float aR=*angularRight;
00685     //Normalize speed for motors
00686     if(abs(*angularLeft)>abs(*angularRight)) {  
00687         *angularRight=MAX_SPEED*abs(aR/aL)*sign1(aR);
00688         *angularLeft=MAX_SPEED*sign1(aL);
00689     }
00690     else {
00691         *angularLeft=MAX_SPEED*abs(aL/aR)*sign1(aL);
00692         *angularRight=MAX_SPEED*sign1(aR);
00693     }    
00694 }
00695 
00696 void update_force(int widthIndice, int heightIndice, float range, float* forceX, float* forceY, float xRobotOrtho, float yRobotOrtho ){
00697     //get the coordonate of the map and the robot in the ortonormal space
00698     float xCenterCell=estimated_width_indice_in_orthonormal_x(widthIndice);
00699     float yCenterCell=estimated_height_indice_in_orthonormal_y(heightIndice);
00700     //compute the distance beetween the cell and the robot
00701     float distanceCellToRobot=sqrt(pow(xCenterCell-xRobotOrtho,2)+pow(yCenterCell-yRobotOrtho,2));
00702     //check if the cell is in range
00703     if(distanceCellToRobot <= range) {
00704         float probaCell=log_to_proba(map[widthIndice][heightIndice]);
00705         //if(isnan(probaCell)) pc.printf("\r\nnan in probaCell");
00706         float xForceComputed=FORCE_CONSTANT_REPULSION*probaCell*(xCenterCell-xRobotOrtho)/pow(distanceCellToRobot,3);
00707         //if(isnan(xForceComputed)) pc.printf("\r\nnan in line 673");
00708         float yForceComputed=FORCE_CONSTANT_REPULSION*probaCell*(yCenterCell-yRobotOrtho)/pow(distanceCellToRobot,3);
00709         //if(isnan(yForceComputed)) pc.printf("\r\nnan in line 675");
00710         *forceX+=xForceComputed;
00711         *forceY+=yForceComputed;
00712     }
00713 }
00714 
00715 //compute the force on X and Y
00716 void compute_forceX_and_forceY(float* forceX, float* forceY){
00717      //we put the position of the robot in an orthonormal space
00718      float xRobotOrtho=robot_center_x_in_orthonormal_x();
00719      float yRobotOrtho=robot_center_y_in_orthonormal_y();
00720 
00721      float forceRepulsionComputedX=0;
00722      float forceRepulsionComputedY=0;
00723      //for each cell of the map we compute a force of repulsion
00724      for(int i=0;i<NB_CELL_WIDTH;i++){
00725         for(int j=0;j<NB_CELL_HEIGHT;j++){
00726             update_force(i,j,RANGE_FORCE,&forceRepulsionComputedX,&forceRepulsionComputedY,xRobotOrtho,yRobotOrtho);
00727         }
00728     }
00729     //update with attraction force
00730     *forceX=-forceRepulsionComputedX;
00731     *forceY=-forceRepulsionComputedY;
00732     float distanceTargetRobot=sqrt(pow(targetXOrtho-xRobotOrtho,2)+pow(targetYOrtho-yRobotOrtho,2));
00733     if(distanceTargetRobot != 0){
00734         *forceX+=FORCE_CONSTANT_ATTRACTION*(targetXOrtho-xRobotOrtho)/distanceTargetRobot;
00735         *forceY+=FORCE_CONSTANT_ATTRACTION*(targetYOrtho-yRobotOrtho)/distanceTargetRobot;
00736     }
00737     float amplitude=sqrt(pow(*forceX,2)+pow(*forceY,2));
00738     if(amplitude!=0){//avoid division by 0 if forceX and forceY  == 0
00739         *forceX=*forceX/amplitude;
00740         *forceY=*forceY/amplitude;
00741     }
00742 }
00743 
00744 void test_got_to_line(bool* reached){
00745     float line_a=1;
00746     float line_b=2;
00747     float line_c=-140;
00748     //we update the odometrie
00749     Odometria();
00750     float angularRight=0;
00751     float angularLeft=0;
00752 
00753     go_to_line(&angularLeft,&angularRight,line_a,line_b,line_c);
00754     pc.printf("\r\n line: %f x + %f y + %f =0", line_a, line_b, line_c);
00755 
00756     leftMotor(sign2(angularLeft),abs(angularLeft));
00757     rightMotor(sign2(angularRight),abs(angularRight));
00758     
00759     pc.printf("\r\n dist=%f", dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrtho,targetYOrtho));
00760 
00761     //wait(0.1);
00762     Odometria();
00763     if(dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrtho,targetYOrtho)<10)
00764         *reached=true;
00765 }
00766 void vff(bool* reached){
00767     float line_a=0;
00768     float line_b=0;
00769     float line_c=0;
00770     //Updating X,Y and theta with the odometry values
00771     float forceX=0;
00772     float forceY=0;
00773     //we update the odometrie
00774     Odometria();
00775     //we check the sensors
00776     float leftMm = get_distance_left_sensor();
00777     float frontMm = get_distance_front_sensor();
00778     float rightMm = get_distance_right_sensor();
00779     float angularRight=0;
00780     float angularLeft=0;
00781     //update the probabilities values 
00782     update_sonar_values(leftMm, frontMm, rightMm);
00783     //we compute the force on X and Y
00784     compute_forceX_and_forceY(&forceX, &forceY);
00785     //we compute a new ine
00786     calculate_line(forceX, forceY, X, Y,&line_a,&line_b,&line_c);
00787     go_to_line(&angularLeft,&angularRight,line_a,line_b,line_c);
00788 
00789     //Updating motor velocities
00790     
00791     leftMotor(sign2(angularLeft),abs(angularLeft));
00792     rightMotor(sign2(angularRight),abs(angularRight));
00793 
00794     //wait(0.1);
00795     Odometria();
00796     if(dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrtho,targetYOrtho)<10)
00797         *reached=true;
00798 }
00799 
00800 //return 1 if positiv, -1 if negativ
00801 float sign1(float value){
00802     if(value>=0) 
00803         return 1;
00804     else 
00805         return -1;
00806 }
00807 
00808 //return 1 if positiv, 0 if negativ
00809 int sign2(float value){
00810     if(value>=0) 
00811         return 1;
00812     else 
00813         return 0;
00814 }
00815 
00816 //currently line_c is not used
00817 void go_to_line(float* angularLeft,float* angularRight,float line_a, float line_b, float line_c){
00818     float lineAngle;
00819     float angleError;
00820     float linear;
00821     float angular;
00822     
00823     if(line_b!=0){
00824         if(direction)
00825             lineAngle=atan(-line_a/line_b);
00826         else
00827             lineAngle=atan(line_a/-line_b);
00828     }
00829     else{
00830         lineAngle=1.5708;
00831     }
00832     
00833     //Computing angle error
00834     angleError = lineAngle-theta;
00835     if(!cos(angleError))
00836         angleError = atan(sin(angleError)/cos(angleError));
00837     else
00838         angleError=pi/2;
00839     if(isnan(angleError)) pc.printf("\r\n nan line 794");
00840 
00841     //Calculating velocities
00842     linear=KV*(3.1416);
00843     angular=KH*angleError;
00844     //TODO if we put it like the poly says it fails, if we switch the plus and minus it works ...
00845     *angularLeft=(linear-0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00846     *angularRight=(linear+0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00847     
00848     float aL=*angularLeft;
00849     float aR=*angularRight;
00850     //Normalize speed for motors
00851     if(abs(*angularLeft)>abs(*angularRight)) {  
00852         *angularRight=MAX_SPEED*abs(aR/aL)*sign1(aR);
00853         *angularLeft=MAX_SPEED*sign1(aL);
00854     }
00855     else {
00856         *angularLeft=MAX_SPEED*abs(aL/aR)*sign1(aL);
00857         *angularRight=MAX_SPEED*sign1(aR);
00858     }
00859     pc.printf("\r\n line: %f x + %f y + %f =0 , X=%f; Y=%f", line_a, line_b, line_c,robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y());
00860 }
00861 
00862 //robotX and robotY are from Odometria, calculate line_a, line_b and line_c
00863 void calculate_line(float forceX, float forceY, float robotX, float robotY,float *line_a, float *line_b, float *line_c){
00864     /*
00865     in the teachers maths it is 
00866     
00867     *line_a=forceY;
00868     *line_b=-forceX;
00869     
00870     because a*x+b*y+c=0
00871     a impact the vertical and b the horizontal
00872     and he has to put them like this because
00873     Robot space:      orthonormal space:
00874       ^                 ^
00875       |x                |y
00876    <- R                 O ->
00877     y                     x
00878     but since our forceX, forceY are already computed in the orthonormal space I m not sure we need to 
00879     */
00880     *line_a=forceX;
00881     *line_b=forceY;
00882     //TODO check that
00883     //because the line computed always pass by the robot center we dont need lince_c
00884     //float xRobotOrtho=robot_center_x_in_orthonormal_x();
00885     //float yRobotOrtho=robot_center_y_in_orthonormal_y();
00886     //*line_c=forceX*yRobotOrtho+forceY*xRobotOrtho;    
00887     *line_c=0;
00888 }