Made by Maor and Shai

Dependencies:   DriveCommand HCSR04 Queue mbed-rtos mbed

Fork of Nucleo_UltrasonicHelloWorld by EJ Teb

main.cpp

Committer:
Maor_T
Date:
2016-07-04
Revision:
2:9a4938a0475b
Parent:
1:4a5586eb1765

File content as of revision 2:9a4938a0475b:

#include "mbed.h"
#include "hcsr04.h"
#include "rtos.h"
#include <string>

#include "DriveCommand.h"
#include "queue.h"

#define ULTRASONIC_TRIG_PIN p8
#define ULTRASONIC_ECHO_PIN p9
#define MOTOR_A_PIN1        p23
#define MOTOR_A_PIN2        p24
#define MOTOR_B_PIN1        p21 
#define MOTOR_B_PIN2        p22
#define BLUETOOTH_RX        p27
#define BLUETOOTH_TX        p28
#define SERVO_PWM_PIN       p25

#define BT_CHECK_DELAY_MS 50

#define ULTRASONIC_CHECK_DELAY_MS 50
#define ULTRASONIC_EMERGENCY_DELAY_MS 20
#define AUTODRIVE_CHECK_DELAY_MS 100



//------DEBUG OPTIONS ----------
//#define DEBUG_BT_COMMANDS
#define DEBUG_ULTRASONICE

//------------------------------

PwmOut motorA1(MOTOR_A_PIN2); //left motor
PwmOut motorA2(MOTOR_A_PIN1); //left motor
PwmOut motorB1(MOTOR_B_PIN1); //right motor
PwmOut motorB2(MOTOR_B_PIN2); //right motor

PwmOut servo(SERVO_PWM_PIN);
Serial bt(BLUETOOTH_TX,BLUETOOTH_RX);
Serial pc(USBTX,USBRX);

HCSR04  usensor(p8,p9);
float lastDistance = 0; // save the last ultrasonic val
bool moveForward_flag = false; // determined when vehicle moving forward - using to stop and avoid obascales
bool turnRight_Flag = false;
bool turnLeft_Flag = false;
bool obstacleAlert = false;
float vehicleSpeed = 1;
int rotateRightMillis  = 650;
int rotateLeftMillis = 650;
float turnSpeed = 0.3;
int obstacleDistance = 30;

Timeout stopper;
Queue autoDriverQueue(sizeof(DriveCommand),10);


//string globalString =" ";
char lastCommandChar ='x';
char incomingMsg[1024];
int incomingMsg_iter = 0;
bool succesReadFlag = false;
bool autoDriveFlag = false;
bool autoDriveRun = false;
int autoDriveCounter = 0;
bool autoDrivePartOk = true; // check if every part of auto drive is whitout obstacles

//Prototype
void Drive_Stop();
void AutoDrive_Stop();
void ExecuteNextCommand();
void Rotate_Left();
void MotorRight_Run(float speedPercent,bool forwardDir);
void MotorLeft_Run(float speedPercent,bool forwardDir);
void Drive_Force_Stop();
int Get_Min_Distance();
void Servo_Look_Left();
void Servo_Look_Right();
void Servo_Look_Center();


void FlagController(char dir)
{
    switch(dir)
    {
        case 'f':
        moveForward_flag = true; 
        turnRight_Flag = false;
        turnLeft_Flag = false;
        break;
        case 'l':
        moveForward_flag = false; 
        turnRight_Flag = false;
        turnLeft_Flag = true;
        break; 
        case 'r':
        moveForward_flag = false; 
        turnRight_Flag = true;
        turnLeft_Flag = false;
        break;    
        case 'b':
        moveForward_flag = false; 
        turnRight_Flag = false;
        turnLeft_Flag = false;
        break;     
    }
}

void StopAfter(float sec)
{
   //  printf("StopAfter Got %f\n",sec);
     stopper.attach(&AutoDrive_Stop,sec);  
}

float GetDistance()
{
    float sum = 0;
    
    for(int i=i ; i< 7 ; i++)
    {
         sum += usensor.get_dist_cm();      
    }
    
    sum /= 7.0;   
    return sum;    
    }



void Reset_IncomingMsg()
{
    for(int i=0 ; i<1024 ; i++)
        incomingMsg[i] = '*'; 
    incomingMsg_iter  =0;    
}

string Get_last_Msg()
{
    int i=0;
    string temp = "";
    while(incomingMsg[i] != '~' && incomingMsg[i] != '*')
    {
        temp+=incomingMsg[i++];         
    }
       
       if(incomingMsg[i] == '~')
       {
            succesReadFlag = true;  
            Reset_IncomingMsg();  
        }
            
       else
       {
           succesReadFlag = false;       
        }                         
        return temp;
}

float map(float x, float in_min, float in_max, float out_min, float out_max)
{
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}


 void dist(int distance)
{
    //put code here to happen when the distance is changed
    printf("Distance changed to %dmm\r\n", distance);
}


void MotorLeft_Run(float speedPercent,bool forwardDir)
{
    if(forwardDir)
    {
      motorA1.write(0);
      motorA2.write(speedPercent);      
    }
    else
    {
      motorA1.write(speedPercent);
      motorA2.write(0);          
    } 
}

void MotorLeft_Stop()
{
    motorA1.write(0);
    motorA2.write(0); 
}

void MotorRight_Run(float speedPercent,bool forwardDir)
{
    if(forwardDir)
    {
      motorB1.write(0);
      motorB2.write(speedPercent);      
    }
    else
    {
      motorB1.write(speedPercent);
      motorB2.write(0);          
    } 
}

void MotorRight_Stop()
{
    motorB1.write(0);
    motorB2.write(0); 
}

void Drive_Forward(float speedPercent)
{
    FlagController('f');
    MotorLeft_Run(speedPercent,true);
    MotorRight_Run(speedPercent,true) ;  
}

void Drive_Left(float leftPercent)
{
    FlagController('f');
    MotorRight_Run(leftPercent,true);
    MotorLeft_Run(1-leftPercent,true) ; // left motor reversed
}

void Reverse_Left(float leftPercent)
{
    MotorRight_Run(leftPercent,false);
    MotorLeft_Run(1-leftPercent,false) ; // left motor reversed
}

void Turn_Left(float leftPercent)
{
    FlagController('l');
    Servo_Look_Left();
    wait_ms(100);
    MotorRight_Run(leftPercent,true);
    MotorLeft_Run(leftPercent,false) ; // left motor reversed
}

void Drive_Right(float rightPercent)
{
      MotorLeft_Run(rightPercent,true) ;
      MotorRight_Run(1-rightPercent,true); // right motor reversed
}

void Reverse_Right(float rightPercent)
{
      MotorLeft_Run(rightPercent,false) ;
      MotorRight_Run(1-rightPercent,false); // right motor reversed
}

void Turn_Right(float rightPercent)
{
      FlagController('r');
      Servo_Look_Right();
      wait_ms(200);
      MotorLeft_Run(rightPercent,true) ;
      MotorRight_Run(rightPercent,false); // right motor reversed
}

void Drive_Backwards(float speedPercent)
{
    FlagController('b');
    MotorLeft_Run(speedPercent,false);
    MotorRight_Run(speedPercent,false) ; 
    moveForward_flag = false; 
}


void Drive_Stop()
{
    FlagController('s');
    MotorLeft_Stop();
    MotorRight_Stop();
    moveForward_flag = false;
    autoDriveRun = false;
}
void Drive_Force_Stop()
{
    MotorRight_Run(turnSpeed,false);
    MotorLeft_Run(turnSpeed,false) ;
    wait_ms(500);
    MotorLeft_Stop();
    MotorRight_Stop();
    moveForward_flag = false;
    autoDriveRun = false;
    
}


void AutoDrive_Stop()
{
//    if(autoDriveFlag) // stop only if autoDrive mode is running
//    {
        MotorLeft_Stop();
        MotorRight_Stop();
        moveForward_flag = false;        
//    }
    autoDriveRun = false;  
}


void Rotate_Left()
{
    MotorRight_Run(turnSpeed,true);
    MotorLeft_Run(turnSpeed,false) ; // left motor reversed
    wait_ms(rotateLeftMillis);
    Drive_Stop(); 
}

void Rotate_Right()
{
    MotorRight_Run(turnSpeed,false);
    MotorLeft_Run(turnSpeed,true) ; // left motor reversed
    wait_ms(rotateRightMillis);
    Drive_Stop(); 
}


void ServoMove(int pos)
{
    if(pos < 0 || pos >180)
        return;
    float outVal = map(pos,0,180,1000,2000);
    servo.pulsewidth_us(outVal);   
}


int Get_Min_Distance()
{
    int min;
    
    Servo_Look_Left();
    wait_ms(250);
    usensor.start();
    int left = usensor.get_dist_cm();
        min=left;
        
    if(min <  obstacleDistance )
    {
        autoDrivePartOk = false;
        return min;   
     }
       
    Servo_Look_Right();
    wait_ms(250);
    usensor.start();
    int right = usensor.get_dist_cm();
        if(right<min)
        min=right;
        
      if(min <  obstacleDistance ) 
      {
          autoDrivePartOk = false;
          return min;  
          
      }

    Servo_Look_Center();
    wait_ms(250);
    usensor.start();
    int center = usensor.get_dist_cm();
        if(center<min)
        min=center;
   
     if(min <  obstacleDistance )
     {
        autoDrivePartOk = false;
        return min;   
      }  
      //  printf("Min Distance %d\n",min);
    
    return min;  
} 

  

void Servo_Look_Left()
{
    servo.pulsewidth_us(2000);   
}

void Servo_Look_Right()
{
    servo.pulsewidth_us(1000);   
}

void Servo_Look_Center()
{
    servo.pulsewidth_us(1500);   
}

void DataReceived_ISR(){
   //  char globalChar = LPC_UART2->RBR;
   //  lastCommandChar = LPC_UART2->RBR;
     incomingMsg[incomingMsg_iter++] = LPC_UART2->RBR ;
     
    // globalString += globalChar; 
}

void DataReceived_PCISR(){
   //  char globalChar = LPC_UART2->RBR;
   //  lastCommandChar = LPC_UART2->RBR;
     incomingMsg[incomingMsg_iter++] = LPC_UART0->RBR ;
     
    // globalString += globalChar; 
}


void Servo_NoNo(int count)
{
    for(int i=0 ; i< count ; i++) {
        Servo_Look_Left();
        wait(0.2);
        Servo_Look_Right();
        wait(0.2);
    } 
   Servo_Look_Center();
}

float getCommandValue(string cmd){
    string cmdValue;   
    std::size_t sharpPosition = cmd.find("#");  
    cmdValue = cmd.substr(sharpPosition+1);
 //   printf("cmdvalue %s\n",cmdValue); // - Print the incoming command
    return atof(cmdValue.c_str());
}




void BTCommands(string cmd)
{
   #ifdef DEBUG_BT_COMMANDS
   printf("Incoming BT command : %s\n",cmd);  // - Print the incoming command
   #endif
   if (cmd.find("forward#")!= string::npos)
   {
       float time = getCommandValue(cmd);
       DriveCommand* dc;
       dc = (DriveCommand*)malloc(sizeof(DriveCommand));
       dc->SetTime(time);
       dc->SetDir('f');
       autoDriverQueue.Put(dc);
   }
   else if(cmd.find("backwards#")!= string::npos)
   {
       float time = getCommandValue(cmd);
       DriveCommand* dc;
       dc = (DriveCommand*)malloc(sizeof(DriveCommand));
       dc->SetTime(time);
       dc->SetDir('b');
       autoDriverQueue.Put(dc);
   }
    else if(cmd.find("obstacle#")!= string::npos)
   {
       obstacleDistance = getCommandValue(cmd);
      
   }  
   
   else if (cmd.find("rotleftms#")!= string::npos)
   {
       rotateLeftMillis = getCommandValue(cmd);
       Rotate_Left();  // todo remove after testing
       
   } 
    else if (cmd.find("rotrightms#")!= string::npos)
   {
       rotateRightMillis = getCommandValue(cmd);
       Rotate_Right(); // todo remove after testing
   } 
    else if (cmd.find("turnspeed#")!= string::npos)
   {
       turnSpeed = getCommandValue(cmd);
      
   }    
   else if(cmd.find("rotleft")!= string::npos)
   {    
       Rotate_Left();
   }
   else if(cmd.find("rotright")!= string::npos)
   {    
       Rotate_Right();
   }  
   else if(cmd.find("left#")!= string::npos)
   {
       float time = getCommandValue(cmd);
       DriveCommand* dc;
       dc = (DriveCommand*)malloc(sizeof(DriveCommand));
       dc->SetTime(time);
       dc->SetDir('l');
       autoDriverQueue.Put(dc);
   }  
         else if(cmd.find("right#")!= string::npos)
   {
       float time = getCommandValue(cmd);
       DriveCommand* dc;
       dc = (DriveCommand*)malloc(sizeof(DriveCommand));
       dc->SetTime(time);
       dc->SetDir('r');
       autoDriverQueue.Put(dc);
   }   
   else if (cmd.find("autodrive")!= string::npos)
   {
       autoDriveFlag = true;

   } 
   else if (cmd.find("forward")!= string::npos)
   {
      if(lastDistance < obstacleDistance)
      {
        Servo_NoNo(2);
        return;
       } 
       Drive_Forward(vehicleSpeed);
   }   
   else if (cmd.find("stop")!= string::npos)
   {
       Drive_Stop();
   } 
   else if (cmd.find("backwards")!= string::npos)
   {
       Drive_Backwards(vehicleSpeed);
   }
   else if (cmd.find("tleft")!= string::npos)
   {
       Turn_Left(vehicleSpeed);
   }
   else if (cmd.find("tright")!= string::npos)
   {
       Turn_Right(vehicleSpeed);
   }
   else if (cmd.find("dright")!= string::npos)
   {
       Drive_Right(vehicleSpeed);
   }
   else if (cmd.find("dleft")!= string::npos)
   {
       Drive_Left(vehicleSpeed);
   }
      else if (cmd.find("rleft")!= string::npos)
   {
       Reverse_Left(vehicleSpeed);
   }
      else if (cmd.find("rright")!= string::npos)
   {
       Reverse_Right(vehicleSpeed);
   }
    else if (cmd.find("speed1")!= string::npos)
   {
       vehicleSpeed = 0.25; 
       
   }
      else if (cmd.find("speed2")!= string::npos)
   {
      vehicleSpeed = 0.50; 
       
   }
       else if (cmd.find("speed3")!= string::npos)
   {
      vehicleSpeed = 0.75; 
       
   }
       else if (cmd.find("speed4")!= string::npos)
   {
      vehicleSpeed = 1; 
       
   }  
   else
   {
       Drive_Stop();
    }
    
}

void BTCommands2(char cmd)
{
   #ifdef DEBUG_BT_COMMANDS
   printf("Incoming BT command : %c\n",cmd);  // - Print the incoming command
   #endif

    switch(cmd)
    {
        case 'F' : Drive_Forward(1);    break;
        case 'B' : Drive_Backwards(1);    break;
        case 'S' : Drive_Stop();        break;
        case 'L' : Drive_Left(1);       break;
        case 'R' : Drive_Right(1);      break;  
}
}


void init()
{
    bt.baud(115200);
    bt.attach(&DataReceived_ISR,Serial::RxIrq);  
    pc.attach(&DataReceived_PCISR,Serial::RxIrq);  
    Reset_IncomingMsg();
}


void UltraSonic_Thread_Func(void const *args)
{
    while(1)
    {
      
    //  lastDistance = GetDistance();
    usensor.start(); 
    lastDistance = usensor.get_dist_cm();
      
      if(moveForward_flag)
      { 
        lastDistance = Get_Min_Distance();    
      }

      
      #ifdef DEBUG_ULTRASONICE
      pc.printf("Distance : %f\n",lastDistance );
      #endif
      
        if(lastDistance < obstacleDistance && moveForward_flag ) { // todo : minimize code here
            autoDrivePartOk = false;
            Drive_Force_Stop();
            moveForward_flag = false; 
            Servo_NoNo(1);
        }
        else if((turnRight_Flag || turnLeft_Flag) && lastDistance < obstacleDistance  ) { // todo : minimize code here
            autoDrivePartOk = false;
            Drive_Stop();
            
           // moveForward_flag = false;
        } 

        
      Thread::wait(ULTRASONIC_CHECK_DELAY_MS);     
    }  
}

void UltraSonic_Thread_Emergency(void const *args)
{
    while(1)
    {
    usensor.start(); 
    lastDistance = usensor.get_dist_cm();
    
      #ifdef DEBUG_ULTRASONICE
      pc.printf("Distance : %f\n",lastDistance );
      #endif
      
        if(lastDistance < obstacleDistance && moveForward_flag ) { // todo : minimize code here
            Drive_Force_Stop();
            moveForward_flag = false;
            Servo_NoNo(1);
        }     
      Thread::wait(ULTRASONIC_EMERGENCY_DELAY_MS);     
    }  
}



void ExecuteNextCommand()
{
    DriveCommand* dc = (DriveCommand*)malloc(sizeof(DriveCommand)) ;
  //  printf("Before get from queue\n");
    autoDriverQueue.Get(dc);
  //  printf("after get from queue\n");
    float time = dc->GetTime();
    char dir = dc->GetDir();
  //  printf("AutoDrive Runing at Dir:%c, Time:%d\n",dir,time);
    autoDriveRun = true;
    autoDrivePartOk = true;
    switch(dir)
    {
        case 'f': 
        Drive_Forward(vehicleSpeed);
        break;
        case 'b':
        Drive_Backwards(vehicleSpeed);
        break;
        case 'l':
        Turn_Left(turnSpeed);
        wait_ms(rotateLeftMillis);
        Drive_Forward(vehicleSpeed);
        break;
        case 'r':
        Turn_Right(turnSpeed);
        wait_ms(rotateRightMillis);      
        Drive_Forward(vehicleSpeed);
        break;        
    } 
    
    StopAfter(time);
    free(dc);
    
    while(autoDriveRun)
        wait_ms(50);
        
    if(autoDrivePartOk)
        bt.printf("ok%d~",autoDriveCounter);
    else
        bt.printf("fail%d~",autoDriveCounter);    
 
    autoDriveCounter++;

    
}





void AutoDrive_Thread_Func(void const *args)
{
        while(true) { 
        
        // todo add check for autoDriveFlag
         if(autoDriveFlag && autoDriverQueue.GetNumberOfItems() >0 )
         {
            // printf("Autodrive Commands  before commit\n");
            if(!autoDriveRun) //check that there is no running command right now
                ExecuteNextCommand(); 
            // printf("Autodrive Commands  after commit\n");
             
         }
         else
         {
            autoDriveFlag = false;
            autoDriveCounter =0;            
         }
            
        //printf("Checking for Autodrive Commands\n");
        Thread::wait(AUTODRIVE_CHECK_DELAY_MS);
    }
}




void BT_Thread_Func(void const *args)
{
//    while(true) { 
//        if(globalString.length() > 0 )
//        {
//            BTCommands(globalString);
//            globalString = "";
//        } 
//        Thread::wait(100);
//    }
//    
        while(true) { 
//        if(lastCommandChar != 'x' )
//        {
//            BTCommands2(lastCommandChar);
//            lastCommandChar = 'x';
//        }
        
         string cmd = Get_last_Msg();
         if(succesReadFlag)
         {
             
             BTCommands(cmd);
             succesReadFlag = false;
         }        
        
        Thread::wait(BT_CHECK_DELAY_MS);
    }
}


int main()
{
 //   mu.startUpdates();//start mesuring the distance
    
    init();
    printf("Hello\n");
    Thread btThread(BT_Thread_Func); 
    btThread.set_priority(osPriorityNormal);
    Thread ultraSonicThread(UltraSonic_Thread_Func);
    ultraSonicThread.set_priority(osPriorityNormal);
    Thread ultraSonicEmergencyThread(UltraSonic_Thread_Emergency);
    ultraSonicEmergencyThread.set_priority(osPriorityNormal); 
    Thread AutoDriveThread(AutoDrive_Thread_Func);
    AutoDriveThread.set_priority(osPriorityNormal);
    
    
    
         
   Servo_Look_Left();
   wait(2);   
   Servo_Look_Right();
   wait(2);    
   Servo_Look_Center();
   
      
 //  Drive_Forward(0.5);
   
 //  StopAfter(3.0);
    
       
  //     autoDriverQueue.Put(&DriveCommand('f',120)); 
                 
    while(1)
    {
    //   mu._checkDistance();   
        //Do something else here
   //     mu.checkDistance();     //call checkDistance() as much as possible, as this is where  //the class checks if dist needs to be called.
    }
       
}