Skip to content

Instantly share code, notes, and snippets.

@rondagdag
Created December 30, 2015 20:42
Show Gist options
  • Save rondagdag/7d139d95e5b6ea2ef8e0 to your computer and use it in GitHub Desktop.
Save rondagdag/7d139d95e5b6ea2ef8e0 to your computer and use it in GitHub Desktop.
IMU to UDP for particle photon
// This #include statement was automatically added by the Particle IDE.
#include "Kalman/Kalman.h"
#include "SparkFunLSM9DS1/SparkFunLSM9DS1.h"
#include "math.h"
unsigned long lastRead= micros();
char myIpAddress[24];
//////////////////////////
// LSM9DS1 Library Init //
//////////////////////////
// Use the LSM9DS1 class to create an object. [imu] can be
// named anything, we'll refer to that throught the sketch.
LSM9DS1 imu;
///////////////////////
// Example I2C Setup //
///////////////////////
// SDO_XM and SDO_G are both pulled high, so our addresses are:
#define LSM9DS1_M 0x1E // Would be 0x1C if SDO_M is LOW
#define LSM9DS1_AG 0x6B // Would be 0x6A if SDO_AG is LOW
////////////////////////////
// Sketch Output Settings //
////////////////////////////
#define PRINT_CALCULATED
//#define PRINT_RAW
#define PRINT_SPEED 10 // 250 ms between prints
// Earth's magnetic field varies by location. Add or subtract
// a declination to get a more accurate heading. Calculate
// your's here:
// http://www.ngdc.noaa.gov/geomag-web/#declination
//#define DECLINATION -8.58 // Declination (degrees) in Boulder, CO.
#define DECLINATION -3.42 // Declination (degrees) in Fort Worth.
int i = 0;
// An UDP instance to let us send and receive packets over UDP
UDP Udp;
uint8_t server[] = { 192, 168, 43, 1}; // ip address of my phone
IPAddress IPfromBytes( server );
unsigned int localPort = 33333;
uint32_t timer;
void setup()
{
Serial.begin(115200);
Particle.variable("ipAddress", myIpAddress, STRING);
IPAddress myIp = WiFi.localIP();
sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
// start the UDP
Udp.begin(localPort);
// Before initializing the IMU, there are a few settings
// we may need to adjust. Use the settings struct to set
// the device's communication mode and addresses:
imu.settings.device.commInterface = IMU_MODE_I2C;
imu.settings.device.mAddress = LSM9DS1_M;
imu.settings.device.agAddress = LSM9DS1_AG;
// The above lines will only take effect AFTER calling
// imu.begin(), which verifies communication with the IMU
// and turns it on.
if (!imu.begin())
{
Serial.println("Failed to communicate with LSM9DS1.");
Serial.println("Double-check wiring.");
Serial.println("Default settings in this sketch will " \
"work for an out of the box LSM9DS1 " \
"Breakout, but may need to be modified " \
"if the board jumpers are.");
while (1)
;
}
timer = micros();
lastRead = micros();
}
void loop()
{
imu.readGyro();
imu.readAccel();
imu.readMag();
printAttitude(imu.ax, imu.ay, imu.az, -imu.my, -imu.mx, imu.mz, imu.gx, imu.gy, imu.gz);
//printGyro();
delay(PRINT_SPEED);
}
void printGyro()
{
// To read from the gyroscope, you must first call the
// readGyro() function. When this exits, it'll update the
// gx, gy, and gz variables with the most current data.
imu.readGyro();
// Now we can use the gx, gy, and gz variables as we please.
// Either print them as raw ADC values, or calculated in DPS.
Serial.print("G: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcGyro helper function to convert a raw ADC value to
// DPS. Give the function the value that you want to convert.
Serial.print(imu.calcGyro(imu.gx), 2);
Serial.print(", ");
Serial.print(imu.calcGyro(imu.gy), 2);
Serial.print(", ");
Serial.print(imu.calcGyro(imu.gz), 2);
Serial.println(" deg/s");
#elif defined PRINT_RAW
Serial.print(imu.gx);
Serial.print(", ");
Serial.print(imu.gy);
Serial.print(", ");
Serial.println(imu.gz);
#endif
char ReplyBuffer[] = "acknowledged";
Udp.beginPacket(IPfromBytes, localPort);
sprintf(ReplyBuffer, "%f,%f,%f", imu.calcGyro(imu.gx),imu.calcGyro(imu.gy), imu.calcGyro(imu.gz));
Udp.write(ReplyBuffer);
Udp.endPacket();
}
void printAccel()
{
// To read from the accelerometer, you must first call the
// readAccel() function. When this exits, it'll update the
// ax, ay, and az variables with the most current data.
imu.readAccel();
// Now we can use the ax, ay, and az variables as we please.
// Either print them as raw ADC values, or calculated in g's.
Serial.print("A: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcAccel helper function to convert a raw ADC value to
// g's. Give the function the value that you want to convert.
Serial.print(imu.calcAccel(imu.ax), 2);
Serial.print(", ");
Serial.print(imu.calcAccel(imu.ay), 2);
Serial.print(", ");
Serial.print(imu.calcAccel(imu.az), 2);
Serial.println(" g");
#elif defined PRINT_RAW
Serial.print(imu.ax);
Serial.print(", ");
Serial.print(imu.ay);
Serial.print(", ");
Serial.println(imu.az);
#endif
}
Kalman kalmanX; // Create the Kalman instances
Kalman kalmanY;
double gyroXangle, gyroYangle; // Angle calculate using the gyro only
double compAngleX, compAngleY; // Calculated angle using a complementary filter
double kalAngleX, kalAngleY; // Calculated angle using a Kalman filter
// Calculate pitch, roll, and heading.
// Pitch/roll calculations take from this app note:
// http://cache.freescale.com/files/sensors/doc/app_note/AN3461.pdf?fpsp=1
// Heading calculations taken from this app note:
// http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/Magnetic__Literature_Application_notes-documents/AN203_Compass_Heading_Using_Magnetometers.pdf
void printAttitude(
float ax, float ay, float az, float mx, float my, float mz, float gx, float gy, float gz)
{
float roll = atan2(ay, az);
float pitch = atan2(-ax, sqrt(ay * ay + az * az));
float heading;
if (my == 0)
heading = (mx < 0) ? 180.0 : 0;
else
heading = atan2(mx, my);
heading -= DECLINATION * M_PI / 180;
if (heading > M_PI) heading -= (2 * M_PI);
else if (heading < -M_PI) heading += (2 * M_PI);
else if (heading < 0) heading += 2 * M_PI;
double dt = (double)(micros() - timer) / 1000000; // Calculate delta time
timer = micros();
// Convert everything from radians to degrees:
heading *= 180.0 / M_PI;
pitch *= 180.0 / M_PI;
roll *= 180.0 / M_PI;
double gyroXrate = gx / 131.0; // Convert to deg/s
double gyroYrate = gy / 131.0; // Convert to deg/s
if ((pitch < -90 && kalAngleY > 90) || (pitch > 90 && kalAngleY < -90)) {
kalmanY.setAngle(pitch);
compAngleY = pitch;
kalAngleY = pitch;
gyroYangle = pitch;
} else
kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt); // Calculate the angle using a Kalman filter
if (abs(kalAngleY) > 90)
gyroXrate = -gyroXrate; // Invert rate, so it fits the restriced accelerometer reading
kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
double accelX = imu.calcAccel(ax);
double accelY = imu.calcAccel(ay);
double accelZ = imu.calcAccel(az);
char ReplyBuffer[] = "acknowledged";
Udp.beginPacket(IPfromBytes, localPort);
sprintf(ReplyBuffer, "%.2f,%.2f,%.2f,A,%.2f,%.2f,%.2f", kalAngleX,kalAngleY, heading, accelX,accelY,accelZ);
//sprintf(ReplyBuffer, "%.2f,%.2f,%.2f", kalAngleX,kalAngleY, heading);
Udp.write(ReplyBuffer);
Udp.endPacket();
Serial.println(ReplyBuffer);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment