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:
VIDEO
Przyjemnej zabawy :)
Brak komentarzy:
Prześlij komentarz