czwartek, 24 kwietnia 2014

eCompas FRDM-KL46Z + openGL

Hej!
Jako, że nasza płytka posiada magnetometr MAG3110 postanowiłem to wykorzystać i
powstał taki mały nie skomplikowany pseudo kompas w openGL. Narysowałem
trzy linie imitujące igłę kompasu mające wskazywać kierunki i na formatce wyświetlam sobie litery
N - północ oraz S - południe sygnalizujące położenie magnetometru względem biegunów
ziemskich.

Północ:
Południe:




using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SharpGL;
using System.Globalization;

namespace SharpGLWinformsApplication1
{

    public partial class SharpGLForm : Form
    {

        public SharpGLForm()
        {

            InitializeComponent();
            serialPort1.Open();
        }
        string receive;
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                receive = serialPort1.ReadTo("\r\n");
                this.Invoke(new EventHandler(displayText));
            }
            catch
            {
                
            }
        }
       
        private string[] parse = new string[3];
        private void displayText(object sender, EventArgs e)
        {
            parse = receive.Split(',');
            textBox1.Text = receive;

        }



        private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e)
        {
            OpenGL gl = openGLControl.OpenGL;           
            gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);            
            gl.LoadIdentity();

            
            if (receive != null)
            {
                gl.Rotate(1.0f, (float)Convert.ToInt32(float.Parse(receive, CultureInfo.InvariantCulture)), 0.0f);

                if ((float)Convert.ToInt32(float.Parse(receive, CultureInfo.InvariantCulture)) >= -5 && (float)Convert.ToInt32(float.Parse(receive, CultureInfo.InvariantCulture)) <= 5)
                {

                    label1.Text = "S";
                }
                else label1.Text = "";


                if ((float)Convert.ToInt32(float.Parse(receive, CultureInfo.InvariantCulture)) <= -175 || (float)Convert.ToInt32(float.Parse(receive, CultureInfo.InvariantCulture)) >= 175)
                {
                    label1.Text = "N";
                }
               

            }
            

            gl.Begin(OpenGL.GL_LINES);
            gl.Color(255.0f, 0.0f, 0.0f);
            gl.Vertex(0.0f, 0.0f, 0.0f);
            gl.Color(0.0f, .0f, 255.0f);
            gl.Vertex(1.0f, 1.0f, 1.0f);

            gl.Color(0.0f, 255.0f, 0.0f);
            gl.Vertex(1.0f, 1.0f, 1.0f);
            gl.Color(0.0f, 1.0f, 0.0f);
            gl.Vertex(0.0f, 1.0f, 0.0f);


            gl.Vertex(0.0f, 1.0f, 0.0f);
            gl.Color(0.0f, 200.0f, 100.0f);
            gl.Vertex(0.0f, 0.0f, 0.0f);                        
            gl.End();

            rotation += (float)numericUpDown1.Value;
        }



 
        private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
        {
            
            OpenGL gl = openGLControl.OpenGL;

            
            gl.ClearColor(0, 0, 0, 0);
        }

 
        private void openGLControl_Resized(object sender, EventArgs e)
        {
            OpenGL gl = openGLControl.OpenGL;            
            gl.MatrixMode(OpenGL.GL_PROJECTION);            
            gl.LoadIdentity();            
            gl.Perspective(40.0f, (double)Width / (double)Height, 0.01, 100.0);
            gl.LookAt(0, 3, 1, 0, 0, 0, 0, 0, 1);            
            gl.MatrixMode(OpenGL.GL_MODELVIEW);
        }

        private float rotation = 0.0f;

        private void SharpGLForm_Load(object sender, EventArgs e)
        {

        }


        private void SharpGLForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            serialPort1.Dispose();
            Application.Exit();
        }
        
    }
}
Obsługa magnetometru:
#include "mbed.h"
#include "MMA8451Q.h"
#include "MAG3110.h"
#include "SLCD.h"
#include "TSISensor.h"
#include 


#include "USBHostMSD.h" //Lab3-MSd

define LED_ON  0 //outON, pwmON
#define LED_OFF 1 //outOFF,pwmOFF
DigitalOut gLED(LED_GREEN); //PTD5

#define rLEDperiod 150      //[ms]
PwmOut rLED(LED_RED);       //PTE29

#define PRESS_ON  0
#define PRESS_OFF 1
DigitalIn  sw1(PTC3);  //if(sw1) Release else Press
DigitalIn  sw3(PTC12); //while(sw3); wait for Press

#define MMA8451_I2C_ADDRESS (0x1d<<1 data-blogger-escaped--="" data-blogger-escaped-acc="" data-blogger-escaped-agnetometer="" data-blogger-escaped-analog-light="" data-blogger-escaped-analogin="" data-blogger-escaped-apacitive="" data-blogger-escaped-define="" data-blogger-escaped-input="" data-blogger-escaped-light="" data-blogger-escaped-mag3110="" data-blogger-escaped-mag="" data-blogger-escaped-mma8451_i2c_address="" data-blogger-escaped-mma8451q="" data-blogger-escaped-out="" data-blogger-escaped-pensda="" data-blogger-escaped-pf="" data-blogger-escaped-printf="" data-blogger-escaped-pte24="" data-blogger-escaped-segmentlcd="" data-blogger-escaped-serial="" data-blogger-escaped-slcd="" data-blogger-escaped-slider="" data-blogger-escaped-terminal="" data-blogger-escaped-touch="" data-blogger-escaped-tsisensor="" data-blogger-escaped-usb_osda="" data-blogger-escaped-usbrx=""> osda (lab1,2,3)

struct KL46_SENSOR_DATA {
    int   sw1State;
    int   sw3State;
    float   accValX;
    float   accValY;
    float   accValZ;
    
    float   slider;
    float   light;
    int     magValX;
    int     magValY;
    int     magValZ;
    
    float   magHeading;
} sensorData;
#define sD sensorData

void SLCD_blinking_msg_wait(char *slcd_msg1, char *slcd_msg2);

int MagCalibrationXY(void); //mag calib
int main(void)
{
    int mag_calib = 0;
    
    FILE* fp;

    //---- MAIN/Inits -----------------------------------------//
    
    sw1.mode(PullUp);
    sw3.mode(PullUp);
    
    gLED = LED_ON; //Green LED ON to indicate running/writing
    rLED = LED_OFF; //Red LED OFF
    rLED.period(rLEDperiod); //Red LED (rLED) tsi/accZ/mag
    
    //---- MAIN/Inits (Wait4SW1) -> Start! --------------------//   
    
    //wait for Press SW1 - e.g. for HID/CDC/MSD Windows install.
    //SLCD_blinking_msg_wait("   o","Helo"); //Helo (no usb);
    SLCD_blinking_msg_wait("   o","MSd ");//Lab1=Hid;2=cdc;3=Msd
    
    //---- MAIN/Inits Interface -------------------------------//
    
    usb_osda.baud(115200);
    usb_osda.printf("\n___________________________________\r\n");
    usb_osda.printf("\nFRDM-KL46Z_Lab\r\n \r\n I am a CDC serial port @OpenSDA/mUSB. Baud=115200 \r\n");
    
 
    while (!mag_calib) {
        pf.printf(" Press and release SW1 to calibrate eCompass.\r\n");
        SLCD_blinking_msg_wait("   o","CAL ");
        
        // Calibrate Magnetometer to eCompass
        pf.printf(" ... r o t a t e  the FRDM board in 3d/360° until [donE].\r\n");
        
        mag_calib = MagCalibrationXY(); //to wait untill calib or cancel!!! 
        
        if (mag_calib) {
            if (mag_calib == -1)
            {
                pf.printf(" [SKiP]! Calibration skipped!  ... See Accelerometer Z-axe.\r\n");
                SLCD_blinking_msg_wait("   o","SKiP"); //->acc
            } else {
                pf.printf(" [donE]! Calibration completed! ... Press and release SW1 to try eCompass.\r\n");  
                SLCD_blinking_msg_wait("   o","donE"); //->mag
            }
            break; //while (!mag_calib)
        } else {
            slcd.printf("erro");
            pf.printf("r\n Error Calib !!! try again !!!\r\n\r\n");
        } //repet calib
    }
    
    
    
    gLED = LED_OFF; //Inits are done

    
    while (1) {
        //disable all SLCD DPs
        slcd.DP(0, false); slcd.DP(1, false); slcd.DP(2, false);

        
        sD.sw1State = sw1; sD.sw3State = sw3;
        sD.accValX = acc.getAccX(); //accX[-1..1]->mouse (Lab1)
        sD.accValY = acc.getAccY(); //accY[-1..1]->mouse (Lab1)
        sD.accValZ = acc.getAccZ(); //accZ[-1..1]->rLED
        
        sD.slider = slider.readPercentage() * 100;
        sD.light = light;
        sD.magValX = mag.readVal(MAG_OUT_X_MSB);
        sD.magValY = mag.readVal(MAG_OUT_Y_MSB);
        sD.magValZ = mag.readVal(MAG_OUT_Z_MSB);
        
        sD.magHeading = mag.getHeading(); 
 
        pf.printf("%3f",sD.magHeading);
        
        pf.printf("\r\n");
        
       
        slcd.CharPosition=0; 
        slcd.printf("% 3.0f", sD.magHeading);
        
        wait(0.05); //wait 50ms
    }
}





//_____________________________________________________________//
//======== FUNC() =============================================//
//¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯//

//Lab2add
void SLCD_blinking_msg_wait(char *slcd_msg1, char *slcd_msg2)
{
    char wait4sw1=0; //~500ms blinking

    //wait for Press SW1 - to start mag calibration
    while(sw1 == PRESS_ON); //wait for release
    while(sw1 == PRESS_OFF) { //wait for press
        if (++wait4sw1 < 150) //300ms
            slcd.printf(slcd_msg1);
        else //200ms
            slcd.printf(slcd_msg2);
        wait(0.002);
    }
    while(sw1 == PRESS_ON); //wait for release
}

//Lab3add
int MagCalibrationXY(void)
{
    int newX, tempXmax, tempXmin; int newY, tempYmax, tempYmin;
    int newZ, tempZmax, tempZmin;
    int delta_avg=0, delta_avg_min=0, delta_avg_max=0, delta_calib_limit=800;
    
    tempXmax = tempXmin = mag.readVal(MAG_OUT_X_MSB); //init X
    tempYmax = tempYmin = mag.readVal(MAG_OUT_Y_MSB); //init Y
    tempZmax = tempZmin = mag.readVal(MAG_OUT_Z_MSB); //init Z
    
    // Update min and max values until calPin asserted again
    while(sw1) {//wait for Press == manual calib stop
        newX = mag.readVal(MAG_OUT_X_MSB);
        newY = mag.readVal(MAG_OUT_Y_MSB);
        newZ = mag.readVal(MAG_OUT_Z_MSB);
        
        if (newX > tempXmax) tempXmax=newX;
        if (newX < tempXmin) tempXmin=newX; newX=tempXmax - tempXmin;
        if (newY > tempYmax) tempYmax=newY;
        if (newY < tempYmin) tempYmin=newY; newY=tempYmax - tempYmin;
        if (newZ > tempZmax) tempZmax=newZ;
        if (newZ < tempZmin) tempZmin=newZ; newZ=tempZmax - tempZmin;       
        
        delta_avg = (newX + newY + newZ);
        
        //delta is too high? -> error, try new calib!!!
        if (delta_avg > 5 * delta_calib_limit) {delta_avg=0; break;}
        
        //div3 with error +0.8 pct
        delta_avg = (21*(newX + newY + newZ))>>6;

        //calib ok for delat ~800-1200 (~80-120uT)
        if (delta_avg > delta_calib_limit){
            delta_avg_min = delta_avg - (delta_avg>>2);
            delta_avg_max = delta_avg + (delta_avg>>1);
            if (delta_avg_min < newX && delta_avg_max > newX
            &&  delta_avg_min < newY && delta_avg_max > newY
            &&  delta_avg_min < newZ && delta_avg_max > newZ) break;
        }
        
        //show calib progress 0->100%
        slcd.printf("C%3.0f", (float)delta_avg/delta_calib_limit*100);
    }
    
    if (sw1 == PRESS_ON || delta_avg ) {
        mag.setCalibration( tempXmin, tempXmax, tempYmin, tempYmax );
        if (sw1 == PRESS_ON) return -1; //==-1 ..user skip
        return delta_avg; //>0 .. done, ok calib
    }
    return 0; //==0 .. error, no calib
}
Tutaj jeszcze filmik pokazujący działanie eKompasu w praktyce:

 Przyjemnej zabawy :)

Brak komentarzy:

Prześlij komentarz