dasd
Dependencies: BufferedSerial
main.cpp
- Committer:
- shut
- Date:
- 2019-06-07
- Revision:
- 7:5e59f8a011fd
- Parent:
- 6:1c84602323c8
File content as of revision 7:5e59f8a011fd:
#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 //Luis Cruz N2011164454 //Jacek Sobecki N2018319609 //VFH/VFF (LIDAR) - LW3 RPLidar lidar; BufferedSerial se_lidar(PA_9, PA_10); PwmOut rplidar_motor(D3); struct RPLidarMeasurement data; 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); void mapping(); void prob_calc(); int Bresenham(int x1, int y1, int x2, int y2, int cX[], int cY[]); void log_cell(int cX[], int cY[], int npts); //Histogram size -> hSize | Active region size -> aSize 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; int aux99 = 0; //const float Fca=6;/*5*/ //VFH const int L=2; float secVal[36]; float smooth[36]; int main(){ pc.baud(115200); init_communication(&pc); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// button.mode(PullUp); getCountsAndReset(); setSpeeds(0, 0); while(button==1); // Lidar initialization rplidar_motor.period(0.001f); lidar.begin(se_lidar); lidar.setAngle(0,360); rplidar_motor.write(0.8f); pc.printf("Program started.\n"); lidar.startThreadScan(); //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] = 250, p_final[1] = 100, p_final[2] = 0; //p_obj[0] = 20, p_obj[1] = 20, p_obj[2] = 0; //Initial coordinates: p[0] = 100, p[1] = 100, p[2] = 0; // =============================================================================== // =================================== EXECUTION ================================= // =============================================================================== initializeArrays(); 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("dist:%f angle:%f\n", data.distance, data.angle); // Prints one lidar measurement. getCountsAndReset(); //pc.printf("Speeds: Left=%lf Right=%lf\n", w[1], w[2]); // DEBUG //pc.printf("OBJECTIVE X: %lf OBJECTIVE Y: %lf\n", p_obj[0], p_obj[1]); DEBUG pc.printf("Position: X=%lf Y=%lf Theta=%lf\n\n", p[0], p[1], p[2]);// DEBUG //pc.printf("Force (X): X=%lf Force(Y)=%lf\n", fX, fY); DEBUG //Path calculation mapping(); poseEst(p, radius, enc_res, b); 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 "carrot" point theta = atan2(p_obj[1]-p[1],p_obj[0]-p[0]); //pc.printf("theta MAIN: = %lf\n\n", theta); DEBUG 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]); DEBUG 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; //Not functional, meant to decrease speed as aproaching final point if((fabs(p[0]-p_final[0])+fabs(p[1]-p_final[1])) < 5){ setSpeeds(0,0); } else if (aux99 > 5){ setSpeeds(w[1], w[2]);// Motor's output } wait(sample_time); aux99++; } } // =============================================================================== // =================================== 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] < 70 || w[1] < 70){ if(wratio < 1){ w[1] = 70; w[2] = w[1]*wratio; } else if(wratio > 1){ w[2] = 70; w[1] = w[2]/wratio; } else{ w[2] = 70; w[1] = 70; } } } void initializeArrays() { /*for (int i = 0; i < hSize; i++) { for (int j = 0; j < hSize; j++) { histogram[i][j].cellVal = 0; //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); } } } //xR, yR - robots position in coordinates system - ATM updating histogram (10/5) 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 >= (i*5.0f) && xR < (i*5.0f+5.0f) && yR >= (j*5.0f) && yR < (j*5.0f+5.0f)){ 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) { activeReg[k][l].cellVal = histogram[m][n].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; } } } 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; } 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; //tried 10, same behaviour } 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; //5 } 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); } void mapping(){ float thetaR_deg, readAngle, lDist, lAng; int xR, yR, xL, yL, cX[400], cY[400], npts, xF, yF; //------------Processing LIDAR readings------------ lDist = data.distance / 10; //mm -> cm if(lDist == 0 || lDist > 200) return; //TO DO (opt): if less than ~10cm! -> make a turn around lAng = data.angle; thetaR_deg = (p[2] * 180.0f) / M_PI; //TO DO: Add the robot's angle in world frame to the lidar's reagin angle (readAngle) if(thetaR_deg < 0) thetaR_deg = 360 + thetaR_deg; readAngle = 270 - lAng + thetaR_deg; //Align LIDAR's frame with robot's one if(readAngle > 360) readAngle -= 360; // " " " " " else if(readAngle < 0) readAngle += 360;// " " " " " //pc.printf("ReadAngle: %f | data_deg: %f | Distance: %f | pos: (%f,%f)\n", readAngle, lAng, lDist, p[0], p[1]); readAngle = (readAngle * M_PI) /180.0f; // deg -> rads xL = lDist * cos(readAngle); yL = lDist * sin(readAngle); xR = p[0]/5, yR = p[1]/5, xL = xL/5, yL = yL/5; // cm -> cell index units xF = xR + xL; //(xR - xL) -> delta distance THINK IS WRONG should be delta = yL-yR; yF = yR + yL;//(yR - yL) -> delta distance THINK IS WRONG should be delta = yL-yR; //if(xF < 0 || yF < 0 || xF > 80 || yF > 80) return; //pc.printf("xF: %d | yF: %d", xF, yF); npts = Bresenham(xR, yR, xF, yF, cX, cY); log_cell(cX, cY, npts); prob_calc(); } //Bresenham algo -> trace the Lidar's reading line into a bitmap a.k.a. cell's index int Bresenham(int x1, int y1, int x2, int y2, int cX[], int cY[]){ int aux = 0; int delta_x(x2 - x1); // if xR == x2, then it does not matter what we set here signed char const ix((delta_x > 0) - (delta_x < 0)); delta_x = std::abs(delta_x) << 1; int delta_y(y2 - y1); // if yR == y2, then it does not matter what we set here signed char const iy((delta_y > 0) - (delta_y < 0)); delta_y = std::abs(delta_y) << 1; cX[aux] = x1, cY[aux] = y1, aux++; //pc.printf("x = %d | y = %d | cx = %d | cy = %d | aux = %d \n", x1, y1, cX[aux-1], cY[aux-1], aux-1); if (delta_x >= delta_y){ // error may go below zero int error(delta_y - (delta_x >> 1)); while (x1 != x2) { // reduce error, while taking into account the corner case of error == 0 if ((error > 0) || (!error && (ix > 0))){ error -= delta_x; y1 += iy; } error += delta_y; x1 += ix; cX[aux] = x1, cY[aux] = y1, aux++; //pc.printf("x = %d | y = %d | cx = %d | cy = %d | aux = %d \n", x1, y1, cX[aux-1], cY[aux-1], aux-1); } } else{ // error may go below zero int error(delta_x - (delta_y >> 1)); while (y1 != y2){ // reduce error, while taking into account the corner case of error == 0 if ((error > 0) || (!error && (iy > 0))){ error -= delta_y; x1 += ix; } error += delta_x; y1 += iy; cX[aux] = x1, cY[aux] = y1, aux++; //pc.printf("x = %d | y = %d | cx = %d | cy = %d | aux = %d \n", x1, y1, cX[aux-1], cY[aux-1], aux-1); } } return aux; } void log_cell(int cX[], int cY[], int npts){ float l_occ = 0.65; float l_free = -0.65; for(int i = 0; i < (npts-1); i++){ if(cX[i] < 0 || cY[i] < 0) break; histogram[cX[i]][cY[i]].logodds = histogram[cX[i]][cY[i]].logodds + l_free; //l0 já inicializado com o array } histogram[cX[npts-1]][cY[npts-1]].logodds = histogram[cX[npts-1]][cY[npts-1]].logodds + l_occ; /*for (int i = -1; i < 2; i++){ for (int j = -1; j < 2; j++){ histogram[cX[npts-1]+i][cY[npts-1]+j].logodds = histogram[cX[npts-1]+i][cY[npts-1]+j].logodds + l_occ; } }*/ //Força precisa de ser calculada de log odds para probabilidades: <50% de ocupação = livre //Se o valor da repulsiva óptimo era 3, então vai oscilar entre 0 e 3 - 50 e 100% } void prob_calc(){ float aux; for (int i = 0; i < hSize; i++) { for (int j = 0; j < hSize; j++) { aux = (1.0f - (1.0f/(1.0f+exp(histogram[i][j].logodds)))); if(aux > 0.5f){ histogram[i][j].cellVal = 20*aux; //6 } } } }