Dependencies:   BufferedSerial

Revision:
4:6ebe8982de0e
Parent:
3:0a718d139ed1
Child:
5:5653e559a67b
--- a/main.cpp	Wed Apr 24 16:00:07 2019 +0000
+++ b/main.cpp	Mon May 06 17:15:52 2019 +0000
@@ -1,15 +1,44 @@
-// Coded by Luís Afonso 11-04-2019
+    // Coded by Luís Afonso 11-04-2019
 #include "mbed.h"
 #include "BufferedSerial.h"
 #include "rplidar.h"
 #include "Robot.h"
 #include "Communication.h"
+#include "math.h"
+#include "ActiveCell.h"
+#include "HistogramCell.h"
+#define M_PI 3.14159265358979323846f
 
-Serial pc(SERIAL_TX, SERIAL_RX);
 RPLidar lidar;
 BufferedSerial se_lidar(PA_9, PA_10);
 PwmOut rplidar_motor(D3);
 
+//EXERCICIO 1
+//Luis Cruz N2011164454
+//Jacek Sobecki N2018319609
+Serial pc(SERIAL_TX, SERIAL_RX, 115200);
+DigitalIn button(PC_13);
+void poseEst(float p[], float radius, float enc_res, float b);
+void SpeedLim(float w[]);
+void initializeArrays();
+void calcSectors(float theta);
+void sumForces();
+void updateActive(float xR, float yR,float theta);
+//int ReadSensors();
+//const int m = 200, n = 200, activeSize = 11;
+//histogram size | aSize active region size
+const int hSize = 80, aSize = 11;
+ActiveCell activeReg[aSize][aSize];
+HistogramCell histogram[hSize][hSize];
+//Repulsive force sums
+float p[3], p_obj[3], p_final[3], fX, fY;
+const float Fca=6;/*5*/
+
+//VFH
+const int L=2;
+float secVal[36];
+float smooth[36];
+
 int main()
 {
     float odomX, odomY, odomTheta;
@@ -24,15 +53,463 @@
     lidar.setAngle(0,360);
 
     pc.printf("Program started.\n");
-        
+    
     lidar.startThreadScan();
     
-    while(1) {
+    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    button.mode(PullUp);
+    getCountsAndReset();
+    setSpeeds(0, 0);
+    initializeArrays();
+    while(button==1);
+    rplidar_motor.write(0.7f);
+    //w[0] = Omega     | w[1] = Left  | w[2] = Right
+    //p[0] = X         | p[1] = Y     | p[2] = Theta
+    //p_obj[0] = X     | p_obj[1] = Y | p_obj[2] = Theta
+    //b = Distance between wheels, enc_res = Encoder Resolution, v = Calculated speed
+    //k_v = Speed gain, k_s = Curvature gain, wratio = Angular speed ratio control command
+    //Cells dim: 5x5cm |
+    float  w[3], v, theta, theta_error, err, integral = 0.0, k_i = 0.01/*0.02*/;
+    const float radius = 3.5, b = 13.3, enc_res = 1440, k_v = 8/*7*/, 
+    k_s = 12/*10*/, sample_time = 0.05, d_stalker = 5, k_f = 12.5; /*12.5*/ //VFF
+    float theta_final;
+// ===============================================================================
+// =================================== COORDS ====================================
+// =============================================================================== 
+    //Target coordinates
+    p_final[0] = 100, p_final[1] = 20, p_final[2] = 0;
+    //p_obj[0] = 20, p_obj[1] = 20, p_obj[2] = 0;
+    //Initial coordinates:
+    p[0] = 20, p[1] = 20, p[2] = 0;
+// ===============================================================================
+// =================================== EXECUTION =================================
+// ===============================================================================
+    while(1){
         // poll for measurements. Returns -1 if no new measurements are available. returns 0 if found one.
         if(lidar.pollSensorData(&data) == 0)
         {
-            pc.printf("%f\t%f\t%d\t%c\n", data.distance, data.angle, data.quality, data.startBit); // Prints one lidar measurement.
+                pc.printf("dist:%f  angle:%f   %d   %c\n", data.distance, data.angle, data.quality, data.startBit); // Prints one lidar measurement.
+        }
+        
+        
+        getCountsAndReset();
+        //pc.printf("Speeds: Left=%lf   Right=%lf\n", w[1], w[2]);
+        //pc.printf("OBJECTIVE X: %lf  OBJECTIVE Y: %lf\n", p_obj[0], p_obj[1]);
+        //pc.printf("Position: X=%lf   Y=%lf   Theta=%lf\n\n", p[0], p[1], p[2]);
+        //pc.printf("Force (X): X=%lf   Force(Y)=%lf\n", fX, fY);
+        
+        
+        //------------Process lidar readings
+        //theta of the robot in degrees
+        float thetaR_deg = 0;
+        //float thetaR_deg = (p[2]*180.0f)/M_PI;
+        if(thetaR_deg <0) thetaR_deg=360+thetaR_deg;
+        //real angle of the reading
+        if(data.angle<360 && data.angle>0) data.angle=360-data.angle;
+        float readAngle = data.angle - 180 + thetaR_deg;
+        if(readAngle>=360) readAngle=fmod(readAngle,360);
+        
+        pc.printf("Robots_deg: %f  data_deg: %f  readAngle: %f\n",thetaR_deg,data.angle,readAngle);
+        
+        //update cells according to a reading
+        if(data.distance!=0 && data.distance<200){
+        for(int i=0;i<11;i++){
+            for (int j = 0; j < 11; j++) {
+                if(readAngle<=activeReg[i][j].sectorK*10+5 && readAngle>=activeReg[i][j].sectorK*10-5){
+                    if(data.distance<=((double)activeReg[i][j].distance+2.5)*10 && data.distance>=((double)activeReg[i][j].distance-2.5)*10) {
+                        //cell is occupied
+                        activeReg[i][j].cellVal = 3;
+                    } else if (data.distance>((double)activeReg[i][j].distance-2.5)*10){
+                            //cell is unoccupied
+                            activeReg[i][j].cellVal = 1;
+                    }
+                }
+            }
+        }
+        }
+        
+        for (int j = 10; j >= 0; j--) {
+        for (int i = 0; i < 11; i++) {
+            cout << "[" << activeReg[i][j].cellVal << "]";
+        }
+        cout << endl;
+    }
+        
+  
+        //Path calculation
+        poseEst(p, radius, enc_res, b); //Pose estimation
+        theta_final = atan2(p_final[1]-p[1],p_final[0]-p[0]);
+        theta_final = atan2(sin(theta_final),cos(theta_final));
+        //updateActive(p[0], p[1], theta_final);
+        p_obj[0] = p[0]+k_f*fX; // add parameter to relate chosen direction (VFH) to the point nearby of the robot
+        p_obj[1] = p[1]+k_f*fY;
+        //Control Law
+        err = sqrt(pow((p_obj[0]-p[0]),2)+pow((p_obj[1]-p[1]),2)) - d_stalker; //distance to the point
+        theta = atan2(p_obj[1]-p[1],p_obj[0]-p[0]);
+        //pc.printf("theta MAIN: = %lf\n\n", theta);
+        theta = atan2(sin(theta),cos(theta));
+        
+
+        
+        p[2] = atan2(sin(p[2]),cos(p[2]));
+        theta_error = theta-p[2];
+        theta_error = atan2(sin(theta_error),cos(theta_error));
+        //pc.printf("theta_error = %lf | p[2]= %lf\n\n", theta_error, p[2]);
+        w[0] = k_s*(theta_error); //direction gain
+        integral += err;
+        v = k_v*err+k_i*integral; //Speed calculation
+        w[1] = (v-(b/2)*w[0])/radius;
+        w[2] = (v+(b/2)*w[0])/radius;
+        
+        SpeedLim(w);
+        //if((fabs(p[0]-p_final[0])+fabs(p[1]-p_final[1])) < 70) k_i = -0.005;
+        if((fabs(p[0]-p_final[0])+fabs(p[1]-p_final[1])) < 5){
+            setSpeeds(0,0);
+        }
+        else{
+            //setSpeeds(w[1], w[2]);
+            }
+        wait(sample_time); 
+    }
+}
+// ===============================================================================
+// =================================== FUNCTIONS =================================
+// ===============================================================================
+//Pose Estimation function
+void poseEst(float p[], float radius, float enc_res, float b){
+    float deltaDl, deltaDr, deltaD, deltaT;
+    deltaDl = ((float)countsLeft)*(2.0f*M_PI*radius/enc_res);
+    deltaDr = ((float)countsRight)*(2.0f*M_PI*radius/enc_res);
+    deltaD = (deltaDr + deltaDl)/2.0f;
+    deltaT = (deltaDr - deltaDl)/b;
+    if(fabs(deltaT) == 0){
+        p[0] = p[0] + deltaD*cos(p[2]) + deltaT/2;
+        p[1] = p[1] + deltaD*sin(p[2]) + deltaT/2;
+        return;
+    }
+    p[0] = p[0] + deltaD*(sin(deltaT/2.0f)/(deltaT/2.0f))*cos(p[2]+deltaT/2.0f);
+    p[1] = p[1] + deltaD*(sin(deltaT/2.0f)/(deltaT/2.0f))*sin(p[2]+deltaT/2.0f);
+    p[2] = p[2] + deltaT;
+}
+//Speed limiter function
+void SpeedLim(float w[]){
+    float wratio;
+    wratio = fabs(w[2]/w[1]);
+    if(w[2] > 150 || w[1] > 150){
+        if(wratio < 1){
+            w[1] = 150;
+            w[2] = w[1]*wratio;
+        }
+        else if(wratio > 1){
+            w[2] = 150;
+            w[1] = w[2]/wratio;
+        }
+        else{
+            w[2] = 150;
+            w[1] = 150;
+        }
+    }
+    if(w[2] < 50 || w[1] < 50){
+        if(wratio < 1){
+            w[1] = 50;
+            w[2] = w[1]*wratio;
+        }
+        else if(wratio > 1){
+            w[2] = 50;
+            w[1] = w[2]/wratio;
+        }
+        else{
+            w[2] = 50;
+            w[1] = 50;
+        }
+    }
+}
+
+void initializeArrays() {
+    for (int i = 0; i < hSize; i++) {
+        for (int j = 0; j < hSize; j++) {
+            histogram[i][j].calculate(i, j);
+            //if(((i >= 8 && i <= 12) && (j == 0 || j == 8)) || ((i == 8 || i == 12) && (j >= 0 && j <= 8))) histogram[i][j].cellVal=3;
+            //if(((i >= 0 && i <= 3) && (j == 8 || j == 12)) || ((i == 0 || i == 3) && (j >= 8 && j <= 12))) histogram[i][j].cellVal=3;
+            //if(((i >= 14 && i <= 20) && (j == 8 || j == 9)) || ((i == 14 || i == 20) && (j >= 8 && j <= 9))) histogram[i][j].cellVal=3;
+        }
+    }
+    for (int i = 0; i < aSize; i++) {
+        for (int j = 0; j < aSize; j++) {
+            activeReg[i][j].calDist(i, j);
+        }
+    }
+}
+
+//every time robot changes position we need to call this function to update active region and calculate forces
+//xR, yR - robots position in coordinates system
+void updateActive(float xR, float yR,float theta) {
+    int idXr = 0;
+    int idYr = 0;
+    for (int i = 0; i < hSize; i++) {
+        for (int j = 0; j < hSize; j++) {
+            if (xR > histogram[i][j].x - 2.5 && xR < histogram[i][j].x + 2.5 && yR > histogram[i][j].y - 2.5 &&
+                yR < histogram[i][j].y + 2.5) {
+                idXr = i;
+                idYr = j;
+                break;
+            }
+        }
+    }
+    int m = idXr - aSize / 2;
+    for (int k = 0; k < aSize; k++) {
+        int n = idYr - aSize / 2;
+        for (int l = 0; l < aSize; l++) {
+            if (m >= 0 && n >= 0 && m < hSize && n < hSize) {
+                histogram[m][n].cellVal=activeReg[k][l].cellVal;
+            }
+            n++;
+        }
+        m++;
+    }
+    for (int i = 0; i < aSize; ++i) {
+        for (int j = 0; j < aSize; ++j) {
+            activeReg[i][j].calForce();
+        }
+    }
+    activeReg[5][5].amplitude=0;
+    activeReg[5][5].amplitude=0;
+    
+    for (int j = 10; j >= 0; j--) {
+        for (int i = 0; i < 11; i++) {
+            cout << "[" << activeReg[i][j].cellVal << "]";
+        }
+        cout << endl;
+    }
+
+    calcSectors(theta);
+}
+void calcSectors(float theta){
+    for (int k = 0; k < 36; ++k) {
+        secVal[k]=0;
+        for (int i = 0; i < aSize; ++i) {
+            for (int j = 0; j < aSize; ++j) {
+                if(activeReg[i][j].sectorK==k)
+                    secVal[k]+=activeReg[i][j].amplitude;
+            }
         }
-       wait(0.01); 
+    }
+
+    smooth[0]=(secVal[34]+2*secVal[35]+2*secVal[0]+2*secVal[1]+secVal[2])/5;
+    smooth[1]=(secVal[35]+2*secVal[0]+2*secVal[1]+2*secVal[2]+secVal[3])/5;
+    smooth[34]=(secVal[32]+2*secVal[33]+2*secVal[34]+2*secVal[35]+secVal[0])/5;
+    smooth[35]=(secVal[33]+2*secVal[34]+2*secVal[35]+2*secVal[0]+secVal[1])/5;
+    for (int i = 2; i < 34; ++i) {
+        smooth[i]=(secVal[i-L]+2*secVal[i-L+1]+2*secVal[i]+2*secVal[i+L-1]+secVal[i+L])/5;
+    }
+    
+    const int thresh=200;//100
+    int temp[36];
+    int counter = 0, aux = 0;
+    int valley[36];
+    for(int i=0;i<36;++i){
+        //pc.printf("|%lf", smooth[i]);
+        if(smooth[i]<thresh){
+            temp[i]=1;
+            //valley[aux][aux] = 
+            counter++;
+        }
+        else{
+            valley[aux] = counter;
+            counter = 0;
+            aux++;
+            temp[i]=0;
+            //pc.printf("#%d", i);
+        }
+        
+    }
+    float best=999;
+    float theta_deg;
+    theta_deg =(theta*180.0f)/M_PI;
+    //pc.printf("theta (degrees): = %lf\n\n", theta_deg);
+   int destSec = theta_deg / 10;
+   if(destSec<0) destSec=36+destSec;
+   //cout<<"destination sector: "<<destSec<<endl;
+   
+   int L=destSec;
+    int R=destSec;
+    while(temp[L]==0){
+        L--;
+        if(L<0) L=35;
+    }
+    while(temp[R]==0){
+        R++;
+        if(R>35) R=0;
     }
-}
\ No newline at end of file
+   
+    float dirSet, dirC,dirL,dirR;
+    if(temp[destSec]==1){
+        int k=destSec-1;
+        if(k<0) k=35;
+        int size=1;
+        while(temp[k]==1){
+            size++;
+            k--;
+            if(k<0) k=35;
+            if(k==destSec) break;
+            if(size>=5) break;
+        }
+        int right=k+1;
+        if(right<0) right=35;
+        k=destSec+1;
+        if(k>35) k=0;
+        while(temp[k]==1){
+            size++;
+            k++;
+            if(k>35) k=0;
+            if(k==destSec) break;
+            if(size>=5) break;
+        }
+        int left=k-1;
+        if(left>35) left=0;
+        if(size>=5) {
+        //wide
+            dirC=destSec*10;
+            //cout << "wide"<<endl;
+            }
+    
+        else if(size>4 && size<5) //narrow
+        {
+            dirC=0.5*(left*10+right*10);
+            //cout<<"narrow"<<endl;
+        } else {
+            int secL = L;
+        while (temp[secL] != 1) {
+            secL++;
+            if (secL > 35) secL = 0;
+        }
+        int rightL = secL;
+        int size = 1;
+
+        int i = secL + 1;
+        if (i > 35) i = 0;
+        while (temp[i] == 1) {
+            size++;
+            i++;
+            if (i > 35) i = 0;
+            if (i == secL) break;
+            // Smax here
+            if (size >= 5) break;
+        }
+        int leftL = i - 1;
+        if (leftL < 0) leftL = 35;
+        if (size >= 5) //wide
+            dirL = rightL * 10 + 0.5 * 10 * 5;
+        else if(size>4 && size<5)  //narrow
+            dirL = 0.5 * (leftL * 10 + rightL * 10);
+        else
+            dirL=9999;
+        ///////////////////////////////////////////////////////////////////
+        int secR = R;
+        while (temp[secR] != 1) {
+            secR--;
+            if (secR < 0) secR = 35;
+        }
+
+        int leftR = secR;
+        int sizeR = 1;
+
+        int j = secR - 1;
+        if (j < 0) j = 35;
+        while (temp[j] == 1) {
+            sizeR++;
+            j--;
+            if (j < 0) j = 35;
+            if (j == secR) break;
+            if (sizeR >= 5) break;
+        }
+        int rightR = j + 1;
+        if (rightR > 35) rightR = 0;
+        if (sizeR >= 5) //wide
+            dirR = leftR * 10 + 0.5 * 10 * 5;
+        else if(sizeR>4 && sizeR<5)//narrow
+            dirR = 0.5 * (rightR * 10 + leftR * 10);
+        else
+            dirR=9999;
+
+        if(dirL>360) dirL=fabs(dirL-360);
+        if(dirR>360) dirR=fabs(dirR-360);
+        if(fabs(theta_deg-dirL)>fabs(theta_deg-dirR))
+            dirC=dirR;
+        else
+            dirC=dirL;
+        }
+        dirSet=dirC;
+        //cout<<"dirSet: 1"<<endl;
+
+        ///////////////////////////////////////////////////////////
+    } else {
+        int secL = destSec;
+        while (temp[secL] != 1) {
+            secL++;
+            if (secL > 35) secL = 0;
+        }
+        int rightL = secL;
+        int size = 1;
+
+        int i = secL + 1;
+        if (i > 35) i = 0;
+        while (temp[i] == 1) {
+            size++;
+            i++;
+            if (i > 35) i = 0;
+            if (i == secL) break;
+            // Smax here
+            if (size >= 5) break;
+        }
+        int leftL = i - 1;
+        if (leftL < 0) leftL = 35;
+        if (size >= 5) //wide
+            dirL = rightL * 10 + 0.5 * 10 * 5;
+        else if(size>4 && size<5)  //narrow
+            dirL = 0.5 * (leftL * 10 + rightL * 10);
+        else
+            dirL=9999;
+        ///////////////////////////////////////////////////////////////////
+        int secR = destSec;
+        while (temp[secR] != 1) {
+            secR--;
+            if (secR < 0) secR = 35;
+        }
+
+        int leftR = secR;
+        int sizeR = 1;
+
+        int j = secR - 1;
+        if (j < 0) j = 35;
+        while (temp[j] == 1) {
+            sizeR++;
+            j--;
+            if (j < 0) j = 35;
+            if (j == secR) break;
+            if (sizeR >= 5) break;
+        }
+        int rightR = j + 1;
+        if (rightR > 35) rightR = 0;
+        if (sizeR >= 5) //wide
+            dirR = leftR * 10 + 0.5 * 10 * 5;
+        else if(sizeR>4 && sizeR<5)//narrow
+            dirR = 0.5 * (rightR * 10 + leftR * 10);
+        else
+            dirR=9999;
+
+        if(dirL>360) dirL=fabs(dirL-360);
+        if(dirR>360) dirR=fabs(dirR-360);
+        if(fabs(theta_deg-dirL)>fabs(theta_deg-dirR))
+            dirSet=dirR;
+        else
+            dirSet=dirL;
+        //cout<<"dirSet:2 dirR: "<<dirR<<" dirL: "<<dirL<<endl;
+    }
+    //cout<<"dirSet: "<<dirSet<<endl;
+    
+    fX=cos(dirSet*M_PI/180.0f);
+    fY=sin(dirSet*M_PI/180.0f);
+    
+}