Example of reading and magnetometer sensor (HMC5883L)

Dependencies:   MODSERIAL mbed-rtos mbed

Fork of ReadingMag_HMC5883L by José Claudio

main.cpp

Committer:
Maor_T
Date:
2016-05-24
Revision:
1:aea254b39529
Parent:
0:6bc5f85ca6fa

File content as of revision 1:aea254b39529:

#include "mbed.h"
#include "HMC5883L.h"
#include <math.h>
#include "rtos.h"
#include <string>
#define SDA_ARM      p28 //p9
#define SCL_ARM      p27 //p10
#define SDA_BODY      p9 //p28
#define SCL_BODY      p10 //p27
#define PI       3.14159265
#define SERVO_PIN p21
#define MaxDegreeDeviation 2 // how many degrees to ignore near north / target
#define ARM_MOUNT_ANGLE -70
#define BODY_MOUNT_ANGLE 0 //was -50
#define CCW_MIN_SPEED 1540  //1550 
#define CCW_MAX_SPEED 1800

#define CW_MIN_SPEED 1460  // 1450 
#define CW_MAX_SPEED 1200

//#define DEBUG_ARM_LOCK_TIMER
//#define DEBUG_SERVO_PWM
//#define DEBUG_GRAPH

Serial pc(USBTX,USBRX);
int TargetAngle = 0;
float BODY_MOUNT_RAD_FIX =   BODY_MOUNT_ANGLE / 180.0 * PI;
float Arm_RAD_FIX = (ARM_MOUNT_ANGLE/180.0*PI) - (TargetAngle/180.0 * PI);
float declinationAngle = 0.069; // fix by position (radian) - netanya is 0.069 (3.6 deg)
PwmOut Servo(SERVO_PIN);
bool moveFlag = false;

Serial BT(p13, p14);
float degreeToNorthArm = 0,degreeToNorthBody=0;
int bodyLastDegree = 0;
float z,x,y;;
HMC5883L hmc_arm(SDA_ARM, SCL_ARM);
HMC5883L hmc_body(SDA_BODY, SCL_BODY);

DigitalOut led2(LED2);

Ticker BTtimer;
Ticker Arm_timer;
Timer ArmlockTimer;
Timer globalTimer;

//char globalChar = ' ';
string globalString =" ";

//prototypes:
void BTsendDegrees(float degree);
void BTsendInterval();
void Arm_Ticker();
void Read_Magnetic_arm();
void Read_Magnetic_body();
float GetDegreeToNorth(int sensor);



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 RotateClockWise(int moveSpeed)
{
    led2 = 1;
    moveFlag = true;
    int moveSpeedCalc = map(180-moveSpeed,MaxDegreeDeviation,180,CW_MAX_SPEED,CW_MIN_SPEED);
    Servo.pulsewidth_us(moveSpeedCalc);
   // Servo.pulsewidth(CW_MAX_SPEED);
   // wait_ms(SERVO_WAIT_TRIGGERS);
    //Servo.pulsewidth_us(1500);
    
    #ifdef DEBUG_SERVO_PWM
    printf("CW  Servo Heading Speed : %d\tActualPwm: %.6f\n",moveSpeed,moveSpeedCalc);
    #endif
    
    #ifdef DEBUG_ARM_LOCK_TIMER
    ArmlockTimer.start();
    #endif
    
    #ifdef DEBUG_GRAPH
    printf("%d,%d,%d\n",globalTimer.read_ms(),moveSpeed,moveSpeedCalc);
    #endif
}


void RotateCounterClockWise(int moveSpeed)
{
    led2 = 1;
    moveFlag = true;
    int moveSpeedCalc = map(abs(moveSpeed),MaxDegreeDeviation,180,CCW_MIN_SPEED,CCW_MAX_SPEED);
    Servo.pulsewidth_us(moveSpeedCalc);
   // Servo.pulsewidth(CCW_MAX_SPEED);
   // wait_ms(SERVO_WAIT_TRIGGERS);
    //Servo.pulsewidth_us(1500);
    #ifdef DEBUG_SERVO_PWM
    printf("CCW Servo Heading Speed : %d\tActualPwm: %.6f\n",moveSpeed,moveSpeedCalc);
    #endif
    #ifdef DEBUG_ARM_LOCK_TIMER
    ArmlockTimer.start();
    #endif
    #ifdef DEBUG_GRAPH
    printf("%d,%d,%d\n",globalTimer.read_ms(),moveSpeed,moveSpeedCalc);
    #endif
}

void StopServo()
{
    led2 = 0;
    //myServo.writeMicroseconds(1500);
    Servo.pulsewidth(0.0015); // pulse width 1500ms - servo stop
    #ifdef DEBUG_ARM_LOCK_TIMER
    if(moveFlag)
    {
        ArmlockTimer.stop();     
     //   printf("Arm locking time : %d ms\n",ArmlockTimer.read_ms());  // - Print the incoming command
        ArmlockTimer.reset();
        moveFlag = false;       
    }
    #endif  
}


void DataReceived_ISR(){
     char globalChar = LPC_UART1->RBR;
     globalString += globalChar; 
}

int 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 atoi(cmdValue.c_str());
}

void BTCommands (string cmd)
{
   
   //printf("Input = %s\n",globalString);  // - Print the incoming command
    
   if (cmd.find("Target")!= string::npos)
   {
       TargetAngle = getCommandValue(cmd);
       Arm_RAD_FIX = Arm_RAD_FIX = (ARM_MOUNT_ANGLE/180.0*PI) - (TargetAngle/180.0 * PI);
     //  printf("New Target Angle set to: %d\n",TargetAngle);
   }
      
}

void thread1(void const *args) //arm thread
{
    while(true) {
        degreeToNorthArm = GetDegreeToNorth(2); // 2 is arm sensor

        if(degreeToNorthArm > MaxDegreeDeviation)
            RotateClockWise(degreeToNorthArm);                   
        else if(degreeToNorthArm < -MaxDegreeDeviation)
            RotateCounterClockWise(degreeToNorthArm);
                      
        else  
          StopServo();  
                         
        Thread::wait(10);
    }
}

void thread2(void const *args) //body thread
{
    while(true) { 
    degreeToNorthBody = GetDegreeToNorth(1);
    if(abs(bodyLastDegree - degreeToNorthBody) > 2)
    {     
       // printf("degrees: %f\n ",degreeToNorthBody);
        BTsendDegrees(degreeToNorthBody);
        bodyLastDegree = degreeToNorthBody;
        Thread::wait(800);     
    }
    else  
        Thread::wait(800);
    }
}



void thread3(void const *args)
{
    while(true) { 
        if(globalString.length() > 0 )
        {
            BTCommands(globalString);
            globalString = "";
        }
        
        Thread::wait(100);
    }
}

void BTsendDegrees(float degree)
{
      BT.printf("#%f~",degree);
}

void BTsendInterval()
{
    degreeToNorthBody = GetDegreeToNorth(1);
    BTsendDegrees(degreeToNorthBody);
   // Arm_timer.attach(Arm_Ticker, 0.0001); // activate arm sensor read frequency
}

void Read_Magnetic_arm()
{
    x = hmc_arm.getMx();
    y = hmc_arm.getMy();
    z = hmc_arm.getMz();
}

void Read_Magnetic_body()
{
    x = hmc_body.getMx();
    y = hmc_body.getMy();
    z = hmc_body.getMz();
}

float GetDegreeToNorth(int sensor)
{
    float heading;
     
       
    switch(sensor)
    {
        case 1: // body
            Read_Magnetic_body();
            
            heading = atan2(y,x); // find the angle
            printf("heading after atan2: %f\n",heading);
            heading = (heading * 180 / PI); //convert to degree
            printf("heading after atan2 (degrees): %f\n",heading);
            
            //heading += declinationAngle + (BODY_MOUNT_RAD_FIX);
            //printf("heading after fixes: %f\n",heading);
           
           if (heading >0 )
             heading -= 90; // sensor rotated by 90 degrees  
           else if (heading < 0)
                heading+=90;  
                
             //fix for arm sensor mount angle
            if(heading > 180) heading -= 180;
            else if(heading < 0) heading += 180; 
             
            //---------- map degrees from -180->180 to 0->360 (only positive degrees) ---------- //
           // if(heading < 0 && heading >= -180) 
          //          heading += 360;
            //-----------------------------------------------------------------------------------//
               
           
            
            ////fix for arm sensor mount angle
//            if(heading > 360) heading -= 360;
//            if(heading < 0) heading += 360; 
            
            
            //heading = (heading * 180 / PI); //convert to degree
             printf("heading final: %f\n\n",heading);
          //  printf("heading: %f\n", heading);  // debug    
             
            break;
                    
        case 2: // arm
            Read_Magnetic_arm();
            heading = atan2(y,x); // find the angle
            heading += declinationAngle + Arm_RAD_FIX ;   
            if(heading < 0) heading += 2*PI;
            if(heading > 2*PI) heading -= 2*PI;
            heading = (heading * 180 / PI); //convert to degree               
//            heading += ARM_MOUNT_ANGLE - TargetAngle;
            if(heading < 180 ) heading = - heading;
            else // 180 <= heading <= 360
                heading = 360 - heading;
            break;      
    }
    
    
    return heading;
}

int main()
{
   
    BT.baud(115200);
    Servo.period(0.020); // set PWM period time to 20ms period or 50hz frequency
  // hmc_arm.Write(0x02,0x00); // set magnetic sensor on arm to continuous mode
  //  pc.attach(&DataReceived_Pc_ISR,Serial::RxIrq); //maor
    BT.attach(&DataReceived_ISR,Serial::RxIrq); //maor
    wait(1);
    //globalTimer.start();
    pc.printf("ready");
    //Thread t1(thread1); //start thread1 ARM
    //t1.set_priority(osPriorityHigh);
    
    Thread t2(thread2); //start thread2 BT SEND
    t2.set_priority(osPriorityNormal);
    
    //Thread t3(thread3); //start thread3 BT RECIEVE
    //t3.set_priority(osPriorityNormal);
    
    Servo.pulsewidth_us(2000);
    wait(2);
    Servo.pulsewidth_us(1500);
    wait(2);
    Servo.pulsewidth_us(1000);
    wait(2);
    Servo.pulsewidth_us(1500);
    
    while(1) {       // main is the next thread 
//    if(pc.readable())
//    {
//        int x;
//        pc.scanf("%d",&x); 
//        printf("got:%d\n",x);
//       Servo.pulsewidth_us(x);    
//    }
//        
    }
}