Gadget, Strike and Dip

Strike and Dip Part II

This post was originally published on September 16, 2017 at https://sparklechicken.net/channel/jakessbc

 

Building on what I mashed together a couple of days ago, I’ve got an updated version of the Little Dipper. And I just named it. Like just now, as I was typing that. Good grief, I’m an idiot. Anyways, I’ve added a virtual bubble level, the Vubble Level, to the mix to help isolate the pitch from the roll. It is three LEDs, two red with a green one in the middle. Yes, I named this, too.

Software wise, I cleaned up the code a bit and found a lovely function in the 9DOF library, fusionGetOrientation(), that integrates the positional data with the magnetometer reading to give a true north reading regardless of the orientation of the IMU.

Since I live in Illinois and am several hundred kilometers from the nearest rock outcropping, I had to run my tests on my windshield and my wife’s. W00t! My pitch readings are about 2° off from the transit compass. This is within the current design parameters since it reads 2° of dip while sitting on a flat surface due to a less than perpendicular solder job on the headers and the fact that this is just breadboarded. Directional readings were likewise within 2° of the transit compass, but since I was measuring a curved surface this was within my margins of error.

This build requires:

Arduino Uno
ST7735 1.4″ TFT
9-DOF IMU L3GD20 + LSM303
3 x 260𝛺 Resistors
2 x Red LEDs
1 x Green LED

 

#include <Wire.h>

#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_9DOF.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#define TFT_CS     10
#define TFT_RST    9  // you can also connect this to the Arduino reset
                      // in which case, set this #define pin to 0!
#define TFT_DC     8
#define TFT_SCLK 13   // set these to be whatever pins you like!
#define TFT_MOSI 11   // set these to be whatever pins you like!

/* Assign a unique ID to the sensors */
Adafruit_9DOF                dof   = Adafruit_9DOF();
Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(30301);
Adafruit_LSM303_Mag_Unified   mag   = Adafruit_LSM303_Mag_Unified(30302);
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

/* Update this with the correct SLP for accurate altitude measurements */
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
float p = 3.1415926;
float adjHeading = 0;
/*set pins for Vubble Level */
int left = 7;
int level = 6;
int right = 5;

/**************************************************************************/
/*!
    @brief  Initialises all the sensors used by this example
*/
/**************************************************************************/
void initSensors()
{
  if(!accel.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println(F("Ooops, no LSM303 detected ... Check your wiring!"));
    while(1);
  }
  if(!mag.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
    while(1);
  }
}

/**************************************************************************/
/*!

*/
/**************************************************************************/
void setup(void)
{
  Serial.begin(115200);
  Serial.println(F("Adafruit 9 DOF Pitch/Roll/Heading Example")); Serial.println("");
  tft.initR(INITR_BLACKTAB);
  /* Initialise the sensors */
  initSensors();
  uint16_t time = millis();
  tft.fillScreen(ST7735_BLACK);
  time = millis() - time;
  /*Initialize the Vubble Level */
  pinMode(left, OUTPUT);
  pinMode(level, OUTPUT);
  pinMode(right, OUTPUT);
}

/**************************************************************************/
/*!
    @brief  Constantly check the roll/pitch/heading/altitude/temperature
*/
/**************************************************************************/
void loop(void)
{
  sensors_event_t accel_event;
  sensors_event_t mag_event;
  sensors_vec_t   orientation;

  /* Calculate pitch and roll from the raw accelerometer data 
     and calculate heading from magnetometer*/
  accel.getEvent(&accel_event);
  mag.getEvent(&mag_event);
  if (dof.fusionGetOrientation(&accel_event, &mag_event, &orientation))
  {
    if (orientation.heading < 0)
    {
      adjHeading = 360 + orientation.heading;
    }
    else
    {
      adjHeading = orientation.heading;
    }
    /* 'orientation' should have valid .roll field 
       pitch will be represented by Vubble Level*/
    adjHeading = abs(360-adjHeading);
    tft.fillScreen(ST7735_BLACK);
    tft.setCursor(0, 30);
    tft.setTextColor(ST7735_YELLOW);
    tft.setTextSize(2);
    tft.println("Dip: ");
    tft.println(abs(orientation.roll));
    tft.println(" ");
    tft.setTextColor(ST7735_YELLOW);
    tft.setTextSize(2);
    tft.println("Strike: ");
    tft.println(adjHeading);
    tft.println(" ");
    delay(10);
  }
  
 /*This series of if statements run the Vubble Level
  * There is probably a vastly better way to do this
  * using elif, but need to look up syntax first.
  */
  if (orientation.pitch < -3)
  {
    digitalWrite(left,HIGH);
    analogWrite(level,0);
    analogWrite(right,0);
  }
  if (orientation.pitch > 3)
  {
    analogWrite(left,0);
    analogWrite(level,0);
    analogWrite(right,255);
  }
  if (orientation.pitch >= -3 && orientation.pitch <= 3)
  {
    analogWrite(left,0);
    analogWrite(level,255);
    analogWrite(right,0);
  }

  tft.println("");
  delay(100);
}

void testdrawtext(char *text, uint16_t color) {
  tft.setCursor(0, 0);
  tft.setTextColor(color);
  tft.setTextWrap(true);
  tft.print(text);
}