All the lab works are here!

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 //update angularLeft and angularRight
00008 float get_error_angles(float x, float y,float theta);
00009 void test_procedure_Lab_2();
00010 void procedure_Lab_3();
00011 void procedure_Lab_2();
00012 void turn_to_target(float angleToTarget);
00013 void initialise_parameters();
00014 //fill initialLogValues with the values we already know (here the bordurs)
00015 void fill_initial_log_values();
00016 //generate a position randomly and makes the robot go there while updating the map
00017 void randomize_and_map();
00018 //make the robot do a pi/2 flip
00019 void do_half_flip();
00020 //go the the given position while updating the map
00021 void go_to_point_with_angle(float target_x, float target_y, float target_angle);
00022 void compute_angles_and_distance(float target_x, float target_y, float target_angle);
00023 void compute_linear_angular_velocities();
00024 //Updates sonar values 
00025 void update_sonar_values(float leftMm, float frontMm, float rightMm);
00026 //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]
00027 float compute_probability_t(float x, float y,float xs,float ys, float angleFromSonarPosition, float distanceObstacleDetected);
00028 //print the map
00029 void print_final_map();
00030 //print the map with the robot marked on it
00031 void print_final_map_with_robot_position();
00032 //print the map with the robot and the target marked on it
00033 void print_final_map_with_robot_position_and_target();
00034 //go to a given line by updating angularLeft and angularRight
00035 void go_to_line(float* angularLeft,float* angularRight,float line_a, float line_b, float line_c);
00036 //calculate virtual force field and move
00037 void vff(bool* reached);
00038 void test_got_to_line(bool* reached);
00039 //Go to a given X,Y position, regardless of the final angle
00040 void go_to_point(float target_x, float target_y);
00041 //go to line and follow it, from lab 1
00042 void go_to_line_lab_1(float line_a, float line_b, float line_c);
00043 
00044 //MATHS heavy functions
00045 float dist(float robot_x, float robot_y, float target_x, float target_y);
00046 float distFromLine(float robot_x, float robot_y, float line_a, float line_b, float line_c);
00047 //returns the probability [0,1] that the cell is occupied from the log value lt
00048 float log_to_proba(float lt);
00049 //returns the log value that the cell is occupied from the probability value [0,1]
00050 float proba_to_log(float p);
00051 //returns the new log value
00052 float compute_log_estimation_lt(float previousLogValue,float currentProbability,float originalLogvalue );
00053 //makes the angle inAngle between 0 and 2pi
00054 float rad_angle_check(float inAngle);
00055 //returns the angle between the vectors (x,y) and (xs,ys)
00056 float compute_angle_between_vectors(float x, float y,float xs,float ys);
00057 float x_robot_in_orthonormal_x(float x, float y);
00058 float y_robot_in_orthonormal_y(float x, float y);
00059 float robot_center_x_in_orthonormal_x();
00060 float robot_center_y_in_orthonormal_y();
00061 float robot_sonar_front_x_in_orthonormal_x();
00062 float robot_sonar_front_y_in_orthonormal_y();
00063 float robot_sonar_right_x_in_orthonormal_x();
00064 float robot_sonar_right_y_in_orthonormal_y();
00065 float robot_sonar_left_x_in_orthonormal_x();
00066 float robot_sonar_left_y_in_orthonormal_y();
00067 float estimated_width_indice_in_orthonormal_x(int i);
00068 float estimated_height_indice_in_orthonormal_y(int j);
00069 //update foceX and forceY if necessary
00070 void update_force(int widthIndice, int heightIndice, float range, float* forceX, float* forceY, float xRobotOrtho, float yRobotOrtho );
00071 //compute the X and Y force
00072 void compute_forceX_and_forceY(float* forceX, float* forceY);
00073 //robotX and robotY are from Odometria, calculate line_a, line_b and line_c
00074 void calculate_line(float forceX, float forceY, float robotX, float robotY,float *line_a, float *line_b, float *line_c);
00075 //return 1 if positiv, -1 if negativ
00076 float sign1(float value);
00077 //return 1 if positiv, 0 if negativ
00078 int sign2(float value);
00079 //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)
00080 void set_target_to(float x, float y);
00081 void try_to_reach_target();
00082 void test_map_sonar();
00083 
00084 //those target are in comparaison to the robot (for exemple a robot in 50,50 with a taget of 0,0 would not need to move)
00085 float targetX;//this is in the robot space top left
00086 float targetY;//this is in the robot space top left
00087 //Ortho but for the map (i.e x and Y are > 0)
00088 float targetXOrhto;
00089 float targetYOrhto;
00090 float targetXOrhtoNotMap;
00091 float targetYOrhtoNotMap;
00092 
00093 const float pi=3.14159;
00094 
00095 //spec of the sonar
00096 //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
00097 const float RANGE_SONAR=50;//cm
00098 const float RANGE_SONAR_MIN=10;//Rmin cm
00099 const float INCERTITUDE_SONAR=10;//cm
00100 const float ANGLE_SONAR=pi/3;//Omega rad
00101 
00102 //those distance and angle are approximation in need of measurements, in the orthonormal space
00103 const float ANGLE_FRONT_TO_LEFT=10*pi/36;//50 degrees
00104 const float DISTANCE_SONAR_LEFT_X=-4;
00105 const float DISTANCE_SONAR_LEFT_Y=4;
00106 
00107 const float ANGLE_FRONT_TO_RIGHT=-10*pi/36;//-50 degrees
00108 const float DISTANCE_SONAR_RIGHT_X=4;
00109 const float DISTANCE_SONAR_RIGHT_Y=4;
00110 
00111 const float ANGLE_FRONT_TO_FRONT=0;
00112 const float DISTANCE_SONAR_FRONT_X=0;
00113 const float DISTANCE_SONAR_FRONT_Y=5;
00114 
00115 //TODO adjust the size of the map for computation time (25*25?)
00116 const float WIDTH_ARENA=200;//cm
00117 const float HEIGHT_ARENA=200;//cm
00118 
00119 //const int SIZE_MAP=25;
00120 const int NB_CELL_WIDTH=20;
00121 const int NB_CELL_HEIGHT=20;
00122 
00123 //used to create the map 250 represent the 250cm of the square where the robot is tested
00124 //float sizeCell=250/(float)SIZE_MAP;
00125 float sizeCellWidth=WIDTH_ARENA/(float)NB_CELL_WIDTH;
00126 float sizeCellHeight=HEIGHT_ARENA/(float)NB_CELL_HEIGHT;
00127 
00128 float map[NB_CELL_WIDTH][NB_CELL_HEIGHT];//contains the log values for each cell
00129 float initialLogValues[NB_CELL_WIDTH][NB_CELL_HEIGHT];
00130 
00131 //Diameter of a wheel and distance between the 2
00132 const float RADIUS_WHEELS=3.25;
00133 const float DISTANCE_WHEELS=7.2;
00134 
00135 //position and orientation of the robot when put on the map (ODOMETRY doesn't know those) it's in the robot space
00136 //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
00137 const float DEFAULT_X=20;
00138 const float DEFAULT_Y=WIDTH_ARENA/2;
00139 //const float DEFAULT_X=20;//lower right
00140 //const float DEFAULT_Y=20;//lower right
00141 const float DEFAULT_THETA=0;
00142 
00143 const int MAX_SPEED=50;//TODO TWEAK THE SPEED SO IT DOES NOT FUCK UP
00144 
00145 const float KRHO=12, KA=30, KB=-13, KV=200, KH=200; //Kappa values
00146 
00147 //CONSTANT FORCE FIELD
00148 const float FORCE_CONSTANT_REPULSION=10000;//TODO tweak it
00149 const float FORCE_CONSTANT_ATTRACTION=1;//TODO tweak it
00150 const float RANGE_FORCE=30;//TODO tweak it
00151 
00152 float alpha; //angle error
00153 float rho; //distance from target
00154 float beta;
00155 float linear, angular, angular_left, angular_right;
00156 float dt=0.5;
00157 float temp;
00158 float d2;
00159 Timer t;
00160 
00161 int main(){
00162     initialise_parameters();   
00163     procedure_Lab_3();                      //uses force fields to reach target with set_terget
00164     //procedure_Lab_2();                    //picks random targets and makes a map (SUCCESS - builds a more or less accurate map without colliding with obstacles)
00165     
00166     //theta=0;
00167     //X=0;
00168     //Y=0;
00169     
00170     //go_to_point(16.8, 78.6);              //(x,y) in the global coordinates x cm on the x direction, y cm in the y direction form the 0,0 of the table 
00171                                             //(SUCCESS - goes to the specified point)
00172     
00173     //go_to_line_lab_1(10, -10, 20);        //a,b,c of a line: ax+by+c=0, again on the global coordinates of the table (SUCCESS - goes along the line)
00174     
00175     //go_to_point_with_angle(46.8, 78.6, 0);//(x,y,theta) in the global coordinates (SUCCESS - goes to the point, the angle is almost right as well)
00176     
00177     //test_procedure_Lab_2();               //starts from the middle of the arena, goes to a point with set_terget
00178 }
00179 
00180 void procedure_Lab_3(){
00181     //try to reach the target is ortho space  
00182     set_target_to(0,80);//
00183     print_final_map_with_robot_position_and_target();
00184     try_to_reach_target();
00185     //set_target_to(0,20);//lower right
00186     //print_final_map_with_robot_position_and_target();
00187     //try_to_reach_target();
00188     //set_target_to(-20,-20);//up left
00189     //print_final_map_with_robot_position_and_target();
00190     //try_to_reach_target();
00191     //print the map forever
00192     while(1){
00193          print_final_map_with_robot_position_and_target();
00194     }
00195 }
00196 
00197 void test_map_sonar(){
00198     float leftMm;
00199     float frontMm;
00200     float rightMm;
00201     X=20;
00202     Y=WIDTH_ARENA/2;
00203     theta=0;
00204     while(1){
00205         leftMm = get_distance_left_sensor();
00206         frontMm = get_distance_front_sensor();
00207         rightMm = get_distance_right_sensor();
00208         pc.printf("%f, %f, %f",leftMm,frontMm,rightMm);
00209         //update the probabilities values 
00210         update_sonar_values(leftMm, frontMm, rightMm);
00211         print_final_map();
00212     }
00213 }
00214 
00215 void test_procedure_Lab_2(){
00216     X=HEIGHT_ARENA/2;
00217     Y=WIDTH_ARENA/2;
00218     set_target_to(-100,50);
00219     print_final_map_with_robot_position_and_target();
00220     go_to_point_with_angle(targetX, targetY, pi/2);
00221     print_final_map_with_robot_position_and_target();
00222     
00223 }
00224 void procedure_Lab_2(){
00225     for(int i=0;i<15;i++){
00226         randomize_and_map();
00227         print_final_map_with_robot_position();
00228         wait(2);
00229     }
00230     while(1){
00231         print_final_map_with_robot_position();
00232         wait(10);
00233     }
00234 }
00235 
00236 
00237 void try_to_reach_target(){
00238     //atan2 gives the angle beetween pi and -pi
00239     float angleToTarget=atan2(targetYOrhtoNotMap,targetXOrhtoNotMap);
00240     turn_to_target(angleToTarget);
00241     bool reached=false;
00242     int print=0;
00243     while (!reached) {
00244         vff(&reached);
00245         //test_got_to_line(&reached);
00246         if(print==10){
00247             leftMotor(1,0);
00248             rightMotor(1,0);
00249             /*
00250             pc.printf("\r\n theta=%f", theta);
00251             pc.printf("\r\n IN ORTHO:");
00252             pc.printf("\r\n X Robot=%f", robot_center_x_in_orthonormal_x());
00253             pc.printf("\r\n Y Robot=%f", robot_center_y_in_orthonormal_y());
00254             pc.printf("\r\n X Target=%f", targetXOrhto);
00255             pc.printf("\r\n Y Target=%f", targetYOrhto);
00256             */
00257             print_final_map_with_robot_position_and_target();
00258             print=0;
00259         }else
00260             print+=1;
00261     }
00262     //Stop at the end
00263     leftMotor(1,0);
00264     rightMotor(1,0);
00265     pc.printf("\r\n target reached");
00266     wait(3);//
00267 }
00268 
00269 //target in ortho space
00270 void set_target_to(float x, float y){
00271     targetX=y;
00272     targetY=-x;
00273     targetXOrhto=x_robot_in_orthonormal_x(targetX,targetY);
00274     targetYOrhto=y_robot_in_orthonormal_y(targetX,targetY);
00275     targetXOrhtoNotMap=x;
00276     targetYOrhtoNotMap=y;
00277 }
00278 
00279 void initialise_parameters(){
00280     i2c1.frequency(100000);
00281     initRobot(); //Initializing the robot
00282     pc.baud(9600); // baud for the pc communication
00283 
00284     measure_always_on();//TODO check if needed
00285     wait(0.5);
00286     //fill the map with the initial log values
00287     fill_initial_log_values();
00288 
00289     theta=DEFAULT_THETA;
00290     X=DEFAULT_X;
00291     Y=DEFAULT_Y;
00292 }
00293 
00294 //fill initialLogValues with the values we already know (here the bordurs)
00295 void fill_initial_log_values(){
00296     //Fill map, we know the border are occupied
00297     for (int i = 0; i<NB_CELL_WIDTH; i++) {
00298         for (int j = 0; j<NB_CELL_HEIGHT; j++) {
00299             if(j==0 || j==NB_CELL_HEIGHT-1 || i==0 || i==NB_CELL_WIDTH-1)
00300                 initialLogValues[i][j] = proba_to_log(1);
00301             else
00302                 initialLogValues[i][j] = proba_to_log(0.5);
00303         }
00304     }
00305 }
00306 
00307 //generate a position randomly and makes the robot go there while updating the map
00308 void randomize_and_map() {
00309     //TODO check that it's aurelien's work
00310     float movementOnX=rand()%(int)(WIDTH_ARENA/2);
00311     float movementOnY=rand()%(int)(HEIGHT_ARENA/2);
00312     
00313     float signOfX=rand()%2;
00314     if(signOfX < 1)
00315         signOfX=-1;
00316     float signOfY=rand()%2;
00317     if(signOfY  < 1)
00318         signOfY=-1;
00319         
00320     float x = movementOnX*signOfX;
00321     float y = movementOnY*signOfY;
00322     float target_angle = 2*((float)(rand()%31416)-15708)/10000.0;
00323     set_target_to(x,y);
00324     go_to_point_with_angle(targetX, targetY, target_angle);
00325 }
00326 
00327 
00328 void do_half_flip(){
00329     Odometria();
00330     float theta_plus_h_pi=theta+pi/2;//theta is between -pi and pi
00331     if(theta_plus_h_pi > pi)
00332         theta_plus_h_pi=-(2*pi-theta_plus_h_pi);
00333     leftMotor(0,100);
00334     rightMotor(1,100);
00335     while(abs(theta_plus_h_pi-theta)>0.05){
00336         Odometria();
00337        // pc.printf("\n\r diff=%f", abs(theta_plus_pi-theta));
00338     }
00339     leftMotor(1,0);
00340     rightMotor(1,0);    
00341 }
00342 
00343 //ODOMETRIA MUST HAVE BEEN CALLED
00344 //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]
00345 float compute_probability_t(float x, float y,float xs,float ys, float angleFromSonarPosition, float distanceObstacleDetected){
00346 
00347     float distancePointToSonar=sqrt(pow(x-xs,2)+pow(y-ys,2));
00348     if( distancePointToSonar < RANGE_SONAR){
00349         float anglePointToSonar=compute_angle_between_vectors(x,y,xs,ys);//angle beetween the point and the sonar beam
00350         float alphaBeforeAdjustment=anglePointToSonar-theta-angleFromSonarPosition;
00351         anglePointToSonar=rad_angle_check(alphaBeforeAdjustment);//TODO I feel you don't need to do that but I m not sure
00352         
00353         if(alphaBeforeAdjustment>pi)
00354             alphaBeforeAdjustment=alphaBeforeAdjustment-2*pi;
00355         if(alphaBeforeAdjustment<-pi)
00356             alphaBeforeAdjustment=alphaBeforeAdjustment+2*pi;
00357             
00358         //float anglePointToSonar2=atan2(y-ys,x-xs)-theta;
00359         
00360         //check if the distance between the cell and the robot is within the circle of range RADIUS_WHEELS
00361         //check if absolute difference between the angles is no more than Omega/2
00362         if(anglePointToSonar <= ANGLE_SONAR/2 || anglePointToSonar >= rad_angle_check(-ANGLE_SONAR/2)){
00363             if( distancePointToSonar < (distanceObstacleDetected - INCERTITUDE_SONAR)){
00364             //point before obstacle, probably empty
00365             /*****************************************************************************/
00366                 float Ea=1.f-pow((2*alphaBeforeAdjustment)/ANGLE_SONAR,2);
00367                 float Er;
00368                 if(distancePointToSonar < RANGE_SONAR_MIN){
00369                     //point before minimum sonar range
00370                     Er=0.f;
00371                 }else{
00372                     //point after minimum sonar range
00373                     Er=1.f-pow((distancePointToSonar-RANGE_SONAR_MIN)/(distanceObstacleDetected-INCERTITUDE_SONAR-RANGE_SONAR_MIN),2);
00374                 }
00375              /*****************************************************************************/
00376                 //if((1.f-Er*Ea)/2.f >1 || (1.f-Er*Ea)/2.f < 0)
00377                 //    pc.printf("\n\r return value=%f,Er=%f,Ea=%f,alphaBeforeAdjustment=%f",(1.f-Er*Ea)/2.f,Er,Ea,alphaBeforeAdjustment);
00378                 return (1.f-Er*Ea)/2.f;
00379             }else{
00380                 //probably occupied
00381             /*****************************************************************************/
00382                 float Oa=1.f-pow((2*alphaBeforeAdjustment)/ANGLE_SONAR,2);
00383                 float Or;
00384                 if( distancePointToSonar <= (distanceObstacleDetected + INCERTITUDE_SONAR)){
00385                     //point between distanceObstacleDetected +- INCERTITUDE_SONAR
00386                     Or=1-pow((distancePointToSonar-distanceObstacleDetected)/(INCERTITUDE_SONAR),2);
00387                 }else{
00388                     //point after in range of the sonar but after the zone detected
00389                     Or=0;
00390                 }
00391             /*****************************************************************************/
00392                 //if((1+Or*Oa)/2 >1 || (1+Or*Oa)/2 < 0)
00393                 //    pc.printf("\n\r return value=%f,Er=%f,Ea=%f,alphaBeforeAdjustment=%f",(1+Or*Oa)/2,Or,Oa,alphaBeforeAdjustment);
00394                 return (1+Or*Oa)/2;
00395             }
00396         }   
00397     }
00398     //not checked by the sonar
00399     return 0.5;
00400 }
00401 
00402 void print_final_map() {
00403     float currProba;
00404     pc.printf("\n\r");
00405     for (int y = NB_CELL_HEIGHT -1; y>-1; y--) {
00406         for (int x= 0; x<NB_CELL_WIDTH; x++) {
00407                 currProba=log_to_proba(map[x][y]);
00408             if ( currProba < 0.5) {
00409                 pc.printf("   ");
00410             } else {
00411                 if(currProba==0.5)
00412                     pc.printf(" . ");
00413                 else
00414                     pc.printf(" X ");
00415             }
00416         }
00417         pc.printf("\n\r");
00418     }
00419 }
00420 
00421 void print_final_map_with_robot_position() {
00422     float currProba;
00423     Odometria();
00424     float Xrobot=robot_center_x_in_orthonormal_x();
00425     float Yrobot=robot_center_y_in_orthonormal_y();
00426     
00427     float heightIndiceInOrthonormal;
00428     float widthIndiceInOrthonormal;
00429     
00430     float widthMalus=-(3*sizeCellWidth/2);
00431     float widthBonus=sizeCellWidth/2;
00432     
00433     float heightMalus=-(3*sizeCellHeight/2);
00434     float heightBonus=sizeCellHeight/2;
00435 
00436     pc.printf("\n\r");
00437     for (int y = NB_CELL_HEIGHT -1; y>-1; y--) {
00438         for (int x= 0; x<NB_CELL_WIDTH; x++) {
00439             heightIndiceInOrthonormal=estimated_height_indice_in_orthonormal_y(y);
00440             widthIndiceInOrthonormal=estimated_width_indice_in_orthonormal_x(x);
00441             if(Yrobot >= (heightIndiceInOrthonormal+heightMalus) && Yrobot <= (heightIndiceInOrthonormal+heightBonus) && Xrobot >= (widthIndiceInOrthonormal+widthMalus) && Xrobot <= (widthIndiceInOrthonormal+widthBonus))                    
00442                 pc.printf(" R ");
00443             else{
00444                 currProba=log_to_proba(map[x][y]);
00445                 if ( currProba < 0.5)
00446                     pc.printf("   ");
00447                 else{
00448                     if(currProba==0.5)
00449                         pc.printf(" . ");
00450                     else
00451                         pc.printf(" X ");
00452                 } 
00453             }
00454         }
00455         pc.printf("\n\r");
00456     }
00457 }
00458 
00459 void print_final_map_with_robot_position_and_target() {
00460     float currProba;
00461     Odometria();
00462     float Xrobot=robot_center_x_in_orthonormal_x();
00463     float Yrobot=robot_center_y_in_orthonormal_y();
00464     
00465     float heightIndiceInOrthonormal;
00466     float widthIndiceInOrthonormal;
00467     
00468     float widthMalus=-(3*sizeCellWidth/2);
00469     float widthBonus=sizeCellWidth/2;
00470     
00471     float heightMalus=-(3*sizeCellHeight/2);
00472     float heightBonus=sizeCellHeight/2;
00473 
00474     pc.printf("\n\r");
00475     for (int y = NB_CELL_HEIGHT -1; y>-1; y--) {
00476         for (int x= 0; x<NB_CELL_WIDTH; x++) {
00477             heightIndiceInOrthonormal=estimated_height_indice_in_orthonormal_y(y);
00478             widthIndiceInOrthonormal=estimated_width_indice_in_orthonormal_x(x);
00479             if(Yrobot >= (heightIndiceInOrthonormal+heightMalus) && Yrobot <= (heightIndiceInOrthonormal+heightBonus) && Xrobot >= (widthIndiceInOrthonormal+widthMalus) && Xrobot <= (widthIndiceInOrthonormal+widthBonus))
00480                 pc.printf(" R ");
00481             else{
00482                 if(targetYOrhto >= (heightIndiceInOrthonormal+heightMalus) && targetYOrhto <= (heightIndiceInOrthonormal+heightBonus) && targetXOrhto >= (widthIndiceInOrthonormal+widthMalus) && targetXOrhto <= (widthIndiceInOrthonormal+widthBonus))                    
00483                     pc.printf(" T ");
00484                 else{
00485                     currProba=log_to_proba(map[x][y]);
00486                     if ( currProba < 0.5)
00487                         pc.printf("   ");
00488                     else{
00489                         if(currProba==0.5)
00490                             pc.printf(" . ");
00491                         else
00492                             pc.printf(" X ");
00493                     } 
00494                 }
00495             }
00496         }
00497         pc.printf("\n\r");
00498     }
00499 }
00500 
00501 //MATHS heavy functions
00502 /**********************************************************************/
00503 //Distance computation function
00504 float dist(float robot_x, float robot_y, float target_x, float target_y){
00505     //pc.printf("%f, %f, %f, %f",robot_x,robot_y,target_x,target_y);
00506     return sqrt(pow(target_y-robot_y,2) + pow(target_x-robot_x,2));
00507 }
00508 
00509 //returns the probability [0,1] that the cell is occupied from the log valAue lt
00510 float log_to_proba(float lt){
00511     return 1-1/(1+exp(lt));
00512 }
00513 
00514 //returns the log value that the cell is occupied from the probability value [0,1]
00515 float proba_to_log(float p){
00516     return log(p/(1-p));
00517 }
00518 
00519 //returns the new log value
00520 float compute_log_estimation_lt(float previousLogValue,float currentProbability,float originalLogvalue ){
00521     return previousLogValue+proba_to_log(currentProbability)-originalLogvalue;
00522 }
00523 
00524 //makes the angle inAngle between 0 and 2pi
00525 float rad_angle_check(float inAngle){
00526     //cout<<"before :"<<inAngle;
00527     if(inAngle > 0){
00528         while(inAngle > (2*pi))
00529             inAngle-=2*pi;
00530     }else{
00531         while(inAngle < 0)
00532             inAngle+=2*pi;
00533     }
00534     //cout<<" after :"<<inAngle<<endl;
00535     return inAngle;
00536 }
00537 
00538 //returns the angle between the vectors (x,y) and (xs,ys)
00539 float compute_angle_between_vectors(float x, float y,float xs,float ys){
00540     //alpha angle between ->x and ->SA
00541     //vector S to A ->SA
00542     float vSAx=x-xs;
00543     float vSAy=y-ys;
00544     //norme SA
00545     float normeSA=sqrt(pow(vSAx,2)+pow(vSAy,2));
00546     //vector ->x (1,0)
00547     float cosAlpha=1*vSAy/*+0*vSAx*//normeSA;;
00548     //vector ->y (0,1)
00549     float sinAlpha=/*0*vSAy+*/1*vSAx/normeSA;//+0*vSAx;
00550     if (sinAlpha < 0)
00551         return -acos(cosAlpha);
00552     else
00553         return acos(cosAlpha);
00554 }
00555 
00556 //return 1 if positiv, -1 if negativ
00557 float sign1(float value){
00558     if(value>=0) 
00559         return 1;
00560     else 
00561         return -1;
00562 }
00563 
00564 //return 1 if positiv, 0 if negativ
00565 int sign2(float value){
00566     if(value>=0) 
00567         return 1;
00568     else 
00569         return 0;
00570 }
00571 
00572 /*
00573 Robot space:      orthonormal space:
00574       ^                 ^
00575       |x                |y
00576    <- R                 O ->
00577     y                     x
00578 */
00579 //Odometria must bu up to date
00580 float x_robot_in_orthonormal_x(float x, float y){
00581     return robot_center_x_in_orthonormal_x()-y;
00582 }
00583 
00584 //Odometria must bu up to date
00585 float y_robot_in_orthonormal_y(float x, float y){
00586     return robot_center_y_in_orthonormal_y()+x;
00587 }
00588 
00589 float robot_center_x_in_orthonormal_x(){
00590     return NB_CELL_WIDTH*sizeCellWidth-Y;
00591 }
00592 
00593 float robot_center_y_in_orthonormal_y(){
00594     return X;
00595 }
00596 
00597 float robot_sonar_front_x_in_orthonormal_x(){
00598     return robot_center_x_in_orthonormal_x()+DISTANCE_SONAR_FRONT_X;
00599 }
00600 float robot_sonar_front_y_in_orthonormal_y(){
00601     return robot_center_y_in_orthonormal_y()+DISTANCE_SONAR_FRONT_Y;
00602 }
00603 
00604 float robot_sonar_right_x_in_orthonormal_x(){
00605     return robot_center_x_in_orthonormal_x()+DISTANCE_SONAR_RIGHT_X;
00606 }
00607 float robot_sonar_right_y_in_orthonormal_y(){
00608     return robot_center_y_in_orthonormal_y()+DISTANCE_SONAR_RIGHT_Y;
00609 }
00610 
00611 float robot_sonar_left_x_in_orthonormal_x(){
00612     return robot_center_x_in_orthonormal_x()+DISTANCE_SONAR_LEFT_X;
00613 }
00614 float robot_sonar_left_y_in_orthonormal_y(){
00615     return robot_center_y_in_orthonormal_y()+DISTANCE_SONAR_LEFT_Y;
00616 }
00617 
00618 float estimated_width_indice_in_orthonormal_x(int i){
00619     return sizeCellWidth/2+i*sizeCellWidth;
00620 }
00621 float estimated_height_indice_in_orthonormal_y(int j){
00622     return sizeCellHeight/2+j*sizeCellHeight;
00623 }
00624 
00625 void update_force(int widthIndice, int heightIndice, float range, float* forceX, float* forceY, float xRobotOrtho, float yRobotOrtho ){
00626     //get the coordonate of the map and the robot in the ortonormal space
00627     float xCenterCell=estimated_width_indice_in_orthonormal_x(widthIndice);
00628     float yCenterCell=estimated_height_indice_in_orthonormal_y(heightIndice);
00629     //compute the distance beetween the cell and the robot
00630     float distanceCellToRobot=sqrt(pow(xCenterCell-xRobotOrtho,2)+pow(yCenterCell-yRobotOrtho,2));
00631     //check if the cell is in range
00632     if(distanceCellToRobot <= range) {
00633         /*float anglePointToRobot=compute_angle_between_vectors(xCenterCell,yCenterCell,xRobotOrtho,yRobotOrtho);//angle beetween the point and the sonar
00634         float alphaBeforeAdjustment=anglePointToRobot-theta;
00635         anglePointToRobot=rad_angle_check(alphaBeforeAdjustment);
00636         if(anglePointToRobot <= pi/2 || anglePointToRobot >= rad_angle_check(-pi/2)){
00637         */
00638             float probaCell=log_to_proba(map[widthIndice][heightIndice]);
00639             float xForceComputed=FORCE_CONSTANT_REPULSION*probaCell*(xCenterCell-xRobotOrtho)/pow(distanceCellToRobot,3);
00640             float yForceComputed=FORCE_CONSTANT_REPULSION*probaCell*(yCenterCell-yRobotOrtho)/pow(distanceCellToRobot,3);
00641             *forceX+=xForceComputed;
00642             *forceY+=yForceComputed;
00643         //}
00644     }
00645 }
00646 
00647 void test_got_to_line(bool* reached){
00648     float line_a=1;
00649     float line_b=2;
00650     float line_c=-140;
00651     //we update the odometrie
00652     Odometria();
00653     float angularRight=0;
00654     float angularLeft=0;
00655 
00656     go_to_line(&angularLeft,&angularRight,line_a,line_b,line_c);
00657     //pc.printf("\r\n line: %f x + %f y + %f =0", line_a, line_b, line_c);
00658 
00659     leftMotor(sign2(angularLeft),abs(angularLeft));
00660     rightMotor(sign2(angularRight),abs(angularRight));
00661     
00662     pc.printf("\r\n dist=%f", dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrhto,targetYOrhto));
00663 
00664     //wait(0.1);
00665     Odometria();
00666     if(dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrhto,targetYOrhto)<10)
00667         *reached=true;
00668 }
00669 void vff(bool* reached){
00670     float line_a;
00671     float line_b;
00672     float line_c;
00673     //Updating X,Y and theta with the odometry values
00674     float forceX=0;
00675     float forceY=0;
00676     //we update the odometrie
00677     Odometria();
00678     //we check the sensors
00679     float leftMm = get_distance_left_sensor();
00680     float frontMm = get_distance_front_sensor();
00681     float rightMm = get_distance_right_sensor();
00682     float angularRight=0;
00683     float angularLeft=0;
00684     //update the probabilities values 
00685     update_sonar_values(leftMm, frontMm, rightMm);
00686     //we compute the force on X and Y
00687     compute_forceX_and_forceY(&forceX, &forceY);
00688     //we compute a new ine
00689     calculate_line(forceX, forceY, X, Y,&line_a,&line_b,&line_c);
00690     go_to_line(&angularLeft,&angularRight,line_a,line_b,line_c);
00691 
00692     //Updating motor velocities
00693     
00694     leftMotor(sign2(angularLeft),abs(angularLeft));
00695     rightMotor(sign2(angularRight),abs(angularRight));
00696 
00697     //wait(0.1);
00698     Odometria();
00699     if(dist(robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y(),targetXOrhto,targetYOrhto)<10)
00700         *reached=true;
00701 }
00702 
00703 //robotX and robotY are from Odometria, calculate line_a, line_b and line_c
00704 void calculate_line(float forceX, float forceY, float robotX, float robotY,float *line_a, float *line_b, float *line_c){
00705     /*
00706     in the teachers maths it is 
00707     
00708     *line_a=forceY;
00709     *line_b=-forceX;
00710     
00711     because a*x+b*y+c=0
00712     a impact the vertical and b the horizontal
00713     and he has to put them like this because
00714     Robot space:      orthonormal space:
00715       ^                 ^
00716       |x                |y
00717    <- R                 O ->
00718     y                     x
00719     but since our forceX, forceY are already computed in the orthonormal space I m not sure we need to 
00720     */
00721     *line_a=forceX;
00722     *line_b=forceY;
00723     //TODO check that
00724     //because the line computed always pass by the robot center we dont need lince_c
00725     //float xRobotOrtho=robot_center_x_in_orthonormal_x();
00726     //float yRobotOrtho=robot_center_y_in_orthonormal_y();
00727     //*line_c=forceX*yRobotOrtho+forceY*xRobotOrtho;    
00728     *line_c=0;
00729 }
00730 
00731 /*angleToTarget is obtained through atan2 so it s:
00732 < 0 if the angle is bettween pi and 2pi on a trigo circle
00733 > 0 if it is between 0 and pi
00734 */
00735 void turn_to_target(float angleToTarget){
00736     Odometria();
00737     float theta_plus_h_pi=theta+pi/2;//theta is between -pi and pi
00738     if(theta_plus_h_pi > pi)
00739         theta_plus_h_pi=-(2*pi-theta_plus_h_pi);
00740      if(angleToTarget>0){   
00741         leftMotor(0,1);
00742         rightMotor(1,1);
00743     }else{
00744         leftMotor(1,1);
00745         rightMotor(0,1);
00746     }
00747     while(abs(angleToTarget-theta_plus_h_pi)>0.05){
00748         Odometria();
00749         theta_plus_h_pi=theta+pi/2;//theta is between -pi and pi
00750          if(theta_plus_h_pi > pi)
00751             theta_plus_h_pi=-(2*pi-theta_plus_h_pi);
00752         //pc.printf("\n\r diff=%f", abs(angleToTarget-theta_plus_h_pi));
00753     }
00754     leftMotor(1,0);
00755     rightMotor(1,0);    
00756 }
00757 
00758 //currently line_c is not used
00759 void go_to_line(float* angularLeft,float* angularRight,float line_a, float line_b, float line_c){
00760     float lineAngle;
00761     float angleError;
00762     float linear;
00763     float angular; 
00764     
00765     bool direction=true;
00766     
00767     float angleToTarget=atan2(targetYOrhtoNotMap,targetXOrhtoNotMap);
00768     bool inFront=true;
00769     if(angleToTarget < 0)//the target is in front
00770         inFront=false;
00771 
00772     if(theta > 0){
00773         //the robot is oriented to the left
00774         if(theta > pi/2){
00775             //the robot is oriented lower left
00776             if(inFront)
00777                 direction=false;//robot and target not oriented the same way
00778         }else{
00779             //the robot is oriented upper left
00780             if(!inFront)
00781                 direction=false;//robot and target not oriented the same way
00782         }
00783     }else{
00784         //the robot is oriented to the right
00785         if(theta < -pi/2){
00786             //the robot is oriented lower right
00787             if(inFront)
00788                 direction=false;//robot and target not oriented the same way
00789         }else{ 
00790             //the robot is oriented upper right
00791             if(!inFront)
00792                 direction=false;//robot and target not oriented the same way
00793         }
00794     }
00795     //pc.printf("\r\n Target is in front");
00796     
00797      if(line_b!=0){
00798         if(!direction)
00799             lineAngle=atan(-line_a/line_b);
00800         else
00801             lineAngle=atan(line_a/-line_b);
00802     }
00803     else{
00804         lineAngle=1.5708;
00805     }
00806     
00807     //Computing angle error
00808     angleError = lineAngle-theta;
00809     angleError = atan(sin(angleError)/cos(angleError));
00810 
00811     //Calculating velocities
00812     linear=KV*(3.1416);
00813     angular=KH*angleError;
00814 
00815     *angularLeft=(linear-0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00816     *angularRight=(linear+0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00817     
00818     float aL=*angularLeft;
00819     float aR=*angularRight;
00820     //Normalize speed for motors
00821     if(abs(*angularLeft)>abs(*angularRight)) {  
00822         *angularRight=MAX_SPEED*abs(aR/aL)*sign1(aR);
00823         *angularLeft=MAX_SPEED*sign1(aL);
00824     }
00825     else {
00826         *angularLeft=MAX_SPEED*abs(aL/aR)*sign1(aL);
00827         *angularRight=MAX_SPEED*sign1(aR);
00828     }
00829     pc.printf("\r\n X=%f; Y=%f", robot_center_x_in_orthonormal_x(),robot_center_y_in_orthonormal_y());
00830 }
00831 
00832 //compute the force on X and Y
00833 void compute_forceX_and_forceY(float* forceX, float* forceY){
00834      //we put the position of the robot in an orthonormal space
00835      float xRobotOrtho=robot_center_x_in_orthonormal_x();
00836      float yRobotOrtho=robot_center_y_in_orthonormal_y();
00837 
00838      float forceRepulsionComputedX=0;
00839      float forceRepulsionComputedY=0;
00840      //for each cell of the map we compute a force of repulsion
00841      for(int i=0;i<NB_CELL_WIDTH;i++){
00842         for(int j=0;j<NB_CELL_HEIGHT;j++){
00843             update_force(i,j,RANGE_FORCE,&forceRepulsionComputedX,&forceRepulsionComputedY,xRobotOrtho,yRobotOrtho);
00844         }
00845     }
00846     //update with attraction force
00847     *forceX=+forceRepulsionComputedX;
00848     *forceY=+forceRepulsionComputedY;
00849     float distanceTargetRobot=sqrt(pow(targetXOrhto-xRobotOrtho,2)+pow(targetYOrhto-yRobotOrtho,2));
00850     if(distanceTargetRobot != 0){
00851         *forceX-=FORCE_CONSTANT_ATTRACTION*(targetXOrhto-xRobotOrtho)/distanceTargetRobot;
00852         *forceY-=FORCE_CONSTANT_ATTRACTION*(targetYOrhto-yRobotOrtho)/distanceTargetRobot;
00853     }
00854     float amplitude=sqrt(pow(*forceX,2)+pow(*forceY,2));
00855     if(amplitude!=0){//avoid division by 0 if forceX and forceY  == 0
00856         *forceX=*forceX/amplitude;
00857         *forceY=*forceY/amplitude;
00858     }
00859 }
00860 
00861 //x and y passed are TargetNotMap
00862 float get_error_angles(float x, float y,float theta){
00863     float angleBeetweenRobotAndTarget=atan2(y,x);
00864     if(y > 0){
00865         if(angleBeetweenRobotAndTarget < pi/2)//up right
00866             angleBeetweenRobotAndTarget=-pi/2+angleBeetweenRobotAndTarget;
00867         else//up right
00868             angleBeetweenRobotAndTarget=angleBeetweenRobotAndTarget-pi/2;
00869     }else{
00870         if(angleBeetweenRobotAndTarget > -pi/2)//lower right
00871             angleBeetweenRobotAndTarget=angleBeetweenRobotAndTarget-pi/2;
00872         else//lower left
00873             angleBeetweenRobotAndTarget=2*pi+angleBeetweenRobotAndTarget-pi/2;
00874     }
00875     return angleBeetweenRobotAndTarget-theta;
00876 }
00877 
00878 void compute_angles_and_distance(float target_x, float target_y, float target_angle){
00879     alpha = atan2((target_y-Y),(target_x-X))-theta;
00880     alpha = atan(sin(alpha)/cos(alpha));
00881     rho = dist(X, Y, target_x, target_y);
00882     d2 = rho;
00883     beta = -alpha-theta+target_angle;        
00884     
00885     //Computing angle error and distance towards the target value
00886     rho += dt*(-KRHO*cos(alpha)*rho);
00887     temp = alpha;
00888     alpha += dt*(KRHO*sin(alpha)-KA*alpha-KB*beta);
00889     beta += dt*(-KRHO*sin(temp));
00890    //pc.printf("\n\r d2=%f", d2);
00891     //pc.printf("\n\r dt=%f", dt);
00892 }
00893 
00894 void compute_linear_angular_velocities(){
00895     //Computing linear and angular velocities
00896     if(alpha>=-1.5708 && alpha<=1.5708){
00897         linear=KRHO*rho;
00898         angular=KA*alpha+KB*beta;
00899     }
00900     else{
00901         linear=-KRHO*rho;
00902         angular=-KA*alpha-KB*beta;
00903     }
00904     angular_left=(linear-0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00905     angular_right=(linear+0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
00906     
00907     //Normalize speed for motors
00908     if(angular_left>angular_right) {
00909         angular_right=MAX_SPEED*angular_right/angular_left;
00910         angular_left=MAX_SPEED;
00911     } else {
00912         angular_left=MAX_SPEED*angular_left/angular_right;
00913         angular_right=MAX_SPEED;
00914     }
00915 }
00916 
00917 //go the the given position while updating the map
00918 void go_to_point_with_angle(float target_x, float target_y, float target_angle) {
00919     Odometria();
00920     alpha = atan2((target_y-Y),(target_x-X))-theta;
00921     alpha = atan(sin(alpha)/cos(alpha));
00922     rho = dist(X, Y, target_x, target_y);
00923     beta = -alpha-theta+target_angle;
00924     //beta = atan(sin(beta)/cos(beta));
00925     bool keep_going=true;
00926     float leftMm;
00927     float frontMm; 
00928     float rightMm;
00929     do {
00930         //Timer stuff
00931         dt = t.read();
00932         t.reset();
00933         t.start();
00934         
00935         //Updating X,Y and theta with the odometry values
00936         Odometria();
00937         leftMm = get_distance_left_sensor();
00938         frontMm = get_distance_front_sensor();
00939         rightMm = get_distance_right_sensor();
00940 
00941         //pc.printf("\n\r leftMm=%f", leftMm);
00942         //pc.printf("\n\r frontMm=%f", frontMm);
00943         //pc.printf("\n\r rightMm=%f", rightMm);
00944     
00945         //if in dangerzone 
00946         if((frontMm < 150 && frontMm > 0)|| (leftMm <150 && leftMm > 0) || (rightMm <150 && rightMm > 0) ){
00947             leftMotor(1,0);
00948             rightMotor(1,0);
00949             update_sonar_values(leftMm, frontMm, rightMm);
00950             //TODO Giorgos maybe you can also test the do_half_flip() function
00951             Odometria();
00952             //do a flip TODO
00953             keep_going=false;
00954             do_half_flip();   
00955         }else{
00956             //if not in danger zone continue as usual
00957             update_sonar_values(leftMm, frontMm, rightMm);
00958             compute_angles_and_distance(target_x, target_y, target_angle); //Compute the angles and the distance from target
00959             compute_linear_angular_velocities(); //Using the angles and distance, compute the velocities needed (linear & angular)
00960     
00961             //pc.printf("\n\r X=%f", X);
00962             //pc.printf("\n\r Y=%f", Y);
00963     
00964             //pc.printf("\n\r a_r=%f", angular_right);
00965             //pc.printf("\n\r a_l=%f", angular_left);
00966     
00967             //Updating motor velocities
00968             leftMotor(1,angular_left);
00969             rightMotor(1,angular_right);
00970     
00971             wait(0.2);
00972             //Timer stuff
00973             t.stop();
00974             pc.printf("\n\r dist to target= %f",d2);
00975         }
00976     } while(d2>1 && (abs(target_angle-theta)>0.01) && keep_going);
00977 
00978     //Stop at the end
00979     leftMotor(1,0);
00980     rightMotor(1,0);
00981 }
00982 
00983 //Updates sonar values
00984 void update_sonar_values(float leftMm, float frontMm, float rightMm){
00985     if(leftMm==0)
00986         pc.printf("\n\r leftMm==0");
00987     if(frontMm==0)
00988         pc.printf("\n\r frontMm==0");
00989     if(rightMm==0)
00990         pc.printf("\n\r rightMm==0");
00991     float currProba;
00992     float i_in_orthonormal;
00993     float j_in_orthonormal;
00994     for(int i=0;i<NB_CELL_WIDTH;i++){
00995         for(int j=0;j<NB_CELL_HEIGHT;j++){
00996                 //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)
00997             //check that again
00998             //compute for front sonar
00999             i_in_orthonormal=estimated_width_indice_in_orthonormal_x(i);
01000             j_in_orthonormal=estimated_height_indice_in_orthonormal_y(j);
01001 
01002             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);
01003             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
01004             //compute for right sonar
01005             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);
01006             map[i][j]=map[i][j]+proba_to_log(currProba)+initialLogValues[i][j];
01007              //compute for left sonar
01008             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);
01009             map[i][j]=map[i][j]+proba_to_log(currProba)+initialLogValues[i][j];
01010         }
01011     }
01012 }
01013 
01014 
01015 //Go to a given X,Y position, regardless of the final angle
01016 void go_to_point(float target_x, float target_y){
01017     float angle_error; //angle error
01018     float d; //distance from target
01019     float k_linear=10, k_angular=200;
01020 
01021     do {        
01022         //Updating X,Y and theta with the odometry values
01023         Odometria();
01024 
01025         //Computing angle error and distance towards the target value
01026         angle_error = atan2((target_y-Y),(target_x-X))-theta;
01027         angle_error = atan(sin(angle_error)/cos(angle_error));
01028         d=dist(X, Y, target_x, target_y);
01029 
01030         //Computing linear and angular velocities
01031         linear=k_linear*d;
01032         angular=k_angular*angle_error;
01033         angular_left=(linear-0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
01034         angular_right=(linear+0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
01035 
01036         
01037         //Normalize speed for motors
01038         if(angular_left>angular_right) {
01039             angular_right=MAX_SPEED*angular_right/angular_left;
01040             angular_left=MAX_SPEED;
01041         } else {
01042             angular_left=MAX_SPEED*angular_left/angular_right;
01043             angular_right=MAX_SPEED;
01044         }
01045 
01046         pc.printf("\n\r X=%f", X);
01047         pc.printf("\n\r Y=%f", Y);
01048 
01049         //Updating motor velocities
01050         leftMotor(1,angular_left);
01051         rightMotor(1,angular_right);
01052 
01053         wait(0.5);
01054     } while(d>1);
01055 
01056     //Stop at the end
01057     leftMotor(1,0);
01058     rightMotor(1,0);
01059 }
01060 
01061 //go to line and follow it, from lab 1
01062 void go_to_line_lab_1(float line_a, float line_b, float line_c){
01063 
01064     float angle_error; //angle error
01065     float d; //distance from line
01066     float kd=5, kh=200, kv=200;
01067     float linear, angular, angular_left, angular_right;
01068     float line_angle;
01069      
01070     //Check if b=0, if yes line_angle=90
01071     if(line_b!=0){
01072         line_angle=atan(-line_a/line_b);
01073     }
01074     else{
01075         line_angle=1.5708;
01076     }
01077 
01078     do {
01079         pc.printf("\n\n\r entered while");
01080 
01081         //Updating X,Y and theta with the odometry values
01082         Odometria();
01083 
01084         //Computing angle error and distance from the target line
01085         angle_error = line_angle-theta;
01086         angle_error = atan(sin(angle_error)/cos(angle_error));
01087         d=distFromLine(X, Y, line_a, line_b, line_c);
01088         pc.printf("\n\r d=%f", d);
01089 
01090         //Calculating velocities
01091         linear=kv*(3.1416-angle_error);
01092         angular=-kd*d+kh*angle_error;
01093         angular_left=(linear-0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
01094         angular_right=(linear+0.5*DISTANCE_WHEELS*angular)/RADIUS_WHEELS;
01095 
01096         //Normalize MAX_SPEED for motors
01097         if(angular_left>angular_right) {
01098             angular_right=MAX_SPEED*angular_right/angular_left;
01099             angular_left=MAX_SPEED;
01100         }
01101         else {
01102             angular_left=MAX_SPEED*angular_left/angular_right;
01103             angular_right=MAX_SPEED;
01104         }
01105         
01106         //Updating motor velocities
01107         if(angular_left>0){
01108             leftMotor(1,angular_left);
01109         }
01110         else{
01111             leftMotor(0,-angular_left);
01112         }
01113         
01114         if(angular_right>0){
01115             rightMotor(1,angular_right);
01116         }
01117         else{
01118             rightMotor(0,-angular_right);
01119         }
01120 
01121         wait(0.5);
01122     } while(1);       
01123 }
01124 
01125 float distFromLine(float robot_x, float robot_y, float line_a, float line_b, float line_c){
01126     return abs((line_a*robot_x+line_b*robot_y+line_c)/sqrt(line_a*line_a+line_b*line_b));
01127 }