3D Compass

Engineer

Erynn G

Area of Interest

Electrical Engineering Programming

School

Columbia Grammar Preparatory School

Grade

Incoming Freshman

Second Milestone

For my last milestone, I secured the Arduino Mega as well as the sensor to the mount by using nylon screws. See Figure 1 for a picture of the attached board and Figure 2 for the nylon screws. A challenge I faced was with the Neopixel ring and soldering. The ring short circuited and the ground and power line became connected rendering it useless. Look to Figure 3 for a diagram of a Neopixels wiring. Because of this experience I learned more about arduinos and how to be more careful with my soldering.

For my second milestone, I got the sensor to work by fixing the programing and wiring. See Figure 1 for a picture of the sensor. The Neopixels now light up in correlation with the magnetometer. See Figure 2 for the Neopixels. I struggled with the wiring and programming because I am using a different Arduino than the original buildplan called for. In order to complete this milestone, I researched how to adapt to the Arduino Mega. See Figure 3 for the sensor’s schematic. The program that the Arduino is running is modified for the LSM303 library. Look to Figure 4 for the specific editided lines. Because of this experience I learned to make sure that all of my parts match the build plan and if they don’t find out how to make them still perform in the same way.

void loop() {

Serial.println(“hi”);
// Read the sensor
sensors_event_t event;
mag.getEvent(&event);

// Calculate the heading and inclination from the data and convert to degrees
heading = 180/M_PI * calcHeading(event.magnetic.x,event.magnetic.y,event.magnetic.z);
inclination = 180/M_PI * calcInclination(event.magnetic.x,event.magnetic.y,event.magnetic.z);

// Every #STREAMDECIMATE reads, display data
if (count%STREAMDECIMATE == 0){
Serial.print(event.magnetic.x); Serial.print(“,”);
Serial.print(event.magnetic.y); Serial.print(“,”);
Serial.print(event.magnetic.z); Serial.print(“,”);
Serial.print(heading); Serial.print(“,”);
Serial.println(inclination);
count = 0; //prevent overflow of int
}

// Plot the Azimuth
plotAzimuth(360 – heading);

// Plot the Inclination
plotInclination(inclination,360-heading);

count += 1;
}

void plotAzimuth(int angle){
int red;
int blue;
int pixDeg;

for(int i=0;i<NUMAZ;i++){

// Calculate angle that pixel is at and make sure it is
// in 0-360
pixDeg = AZANGLE + i*15;

if (pixDeg > 360){
pixDeg -= 360;
}

// Color based on difference of given angle and pixel angle
int diff = abs(pixDeg – angle);

// If the difference is over 180, we’ll loop back to lower values of
// difference since this is a ring
if (diff>180){
diff = abs(360 – diff);
}

// Do red coloring, increase the value for a larger red area, decrease
// for less red. If negative, set to zero
red = 60 – diff;
if (red<0){
red = 0;
}

// Do difference 180 from heading for south (blue) coloring and make
// sure it is in range
diff = abs(pixDeg – angle – 180);

if (diff>180){
diff = abs(360 – diff);
}

// Do blue coloring, increase the value for a larger blue area, decrease
// for less blue. If negative, set to zero
blue = 170 -diff;
if (blue<0){
blue = 0;
}

// Set pixel color brightnesses
red = red*BRIGHTNESS;
blue = blue*BRIGHTNESS/5;

// Make sure neither is over 255
if (red > 255){
red = 255;
}

if (blue > 255){
blue = 255;
}
//Actually set the color on the NeoPixel ring
strip.setPixelColor(i,red,0,blue);
}
//Refresh the NeoPixel displays
strip.show();
}

void plotInclination(float angle, float heading){
int red;
int blue;
int pixDeg;

// Check if negative, and if so put at correct positive angle
if (angle < 0){
angle += 360;
}

// Do azimuth switching if necessary
if (heading > 180){
angle = 180 – angle ;
}

// Make sure we are under 360
while (angle > 360){
angle -= 360;
}

// Make sure we are over zero
if (angle < 0){
angle += 360;
}

for(int i=0;i<NUMINC;i++){
pixDeg = INCANGLE – i*22.5;

if (pixDeg < 0){
pixDeg += 360;
}

// Color based on difference of given angle and pixel angle
int diff = abs(pixDeg – angle);

// If the difference is over 180, we’ll loop back to lower values of
// difference since this is a ring
if (diff>180){
diff = abs(360 – diff);
}

// Do red coloring, increase the value for a larger red area, decrease
// for less red. If negative, set to zero
red = 60 – diff;
if (red<0){
red = 0;
}

// Do difference 180 from heading for south (blue) coloring and make
// sure it is in range
diff = abs(pixDeg – angle – 180);

if (diff>180){
diff = abs(360 – diff);
}

// Do blue coloring, increase the value for a larger blue area, decrease
// for less blue. If negative, set to zero
blue = 170 -diff;
if (blue<0){
blue = 0;
}

// Set pixel color brightness
red = red*BRIGHTNESS;
blue = blue*BRIGHTNESS/5;

// Make sure neither is over 255
if (red > 255){
red = 255;
}

if (blue > 255){
blue = 255;
}
//Actually set the color on the NeoPixel ring
strip.setPixelColor(i+NUMAZ,red,0,blue);
}
//Refresh the NeoPixel displays
strip.show();
}

float calcInclination(float x, float y, float z)
{
/* Given x,y,z componets of a field, return the
inclination angle w.r.t horizontal in radians. */
return atan2(z,sqrt(x*x + y*y));
}

float calcHeading(float x, float y, float z)
{
/* Given x,y,z componets of a field, return the
heading angle w.r.t “north”. This assumes that
x is “east”, y is “north”, and z is “up”.*/
float theta;
theta = atan2(y, x);
theta -= DECLINATION;
theta -= 0.5 * PI;

if (theta < 0){
theta += 2*PI;
}

if (theta > 2*PI){
theta -= 2*PI;
}

return theta;
}

For my first milestone, I got the Neopixels to light up by using a breadboard and an Arduino Mega. See figure 3 for a close up of the lit up Neopixels. The circuit works because the Arduino supplies power, ground, and signal creating a successful circuit. See figure 5 for imagery of the Arduino. I struggled  with my cable management and the breadboard allowed me to visually see how each connection from the Arduino was distributed to both Neopixel rings. See figure 4 for an image of the wired breadboard. In order to complete this milestone, I used the Adafruit Neopixel uber guide which provided me with a helpful schematic. See figure 2 for the full diagram of my circuit. The program that the Arduino is running is from the Adafruit Neopixel library. See figure 6 for specific lines of code that determine the LED colors on a RGB scale. The function used is called colorwipe() and it takes three numbers ranging from 0-255 which correlates to how much red, green, or blue is displayed in a pixel. Through this experience I learned about the importance of breaking down the fundamentals before trying to complete a larger task.

Code for testing Neopixels

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);

 

byte neopix_gamma[] = {

    0,  0, 0,  0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0, 0,  0,

    0,  0, 0,  0, 0, 0,  0, 0, 0, 0,  0, 0, 1, 1, 1,  1,

    1,  1, 1,  1, 1, 1,  1, 1, 1, 2,  2, 2, 2, 2, 2,  2,

    2,  3, 3,  3, 3, 3,  3, 3, 4, 4,  4, 4, 4, 5, 5,  5,

    5,  6, 6,  6, 6, 7,  7, 7, 7, 8,  8, 8, 9, 9, 9, 10,

   10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,

   17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,

   25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,

   37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,

   51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,

   69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,

   90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,

  115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,

  144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,

  177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,

  215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };

 

void setup() {

  // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket

  #if defined (__AVR_ATtiny85__)

    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);

  #endif

  // End of trinket special code

  strip.setBrightness(BRIGHTNESS);

  strip.begin();

  strip.show(); // Initialize all pixels to ‘off’

}

 

void loop() {

  // Some example procedures showing how to display to the pixels:

  colorWipe(strip.Color(255, 0, 0), 50); // Red

  colorWipe(strip.Color(0, 255, 0), 50); // Green

  colorWipe(strip.Color(0, 0, 255), 50); // Blue

  colorWipe(strip.Color(0, 0, 0, 255), 50); // White

 

  whiteOverRainbow(20,75,5);  

 

  pulseWhite(5); 

 

  // fullWhite();

  // delay(2000);

 

  rainbowFade2White(3,3,1);

 

}

 

// Fill the dots one after the other with a color

void colorWipe(uint32_t c, uint8_t wait) {

  for(uint16_t i=0; i<strip.numPixels(); i++) {

    strip.setPixelColor(i, c);

    strip.show();

    delay(wait);

  }

}

 

void pulseWhite(uint8_t wait) {

  for(int j = 0; j < 256 ; j++){

      for(uint16_t i=0; i<strip.numPixels(); i++) {

          strip.setPixelColor(i, strip.Color(0,0,0, neopix_gamma[j] ) );

        }

        delay(wait);

        strip.show();

      }

 

  for(int j = 255; j >= 0 ; j–){

      for(uint16_t i=0; i<strip.numPixels(); i++) {

          strip.setPixelColor(i, strip.Color(0,0,0, neopix_gamma[j] ) );

        }

        delay(wait);

        strip.show();

      }

}

 

void rainbowFade2White(uint8_t wait, int rainbowLoops, int whiteLoops) {

  float fadeMax = 100.0;

  int fadeVal = 0;

  uint32_t wheelVal;

  int redVal, greenVal, blueVal;

 

  for(int k = 0 ; k < rainbowLoops ; k ++){

    

    for(int j=0; j<256; j++) { // 5 cycles of all colors on wheel

 

      for(int i=0; i< strip.numPixels(); i++) {

 

        wheelVal = Wheel(((i * 256 / strip.numPixels()) + j) & 255);

 

        redVal = red(wheelVal) * float(fadeVal/fadeMax);

        greenVal = green(wheelVal) * float(fadeVal/fadeMax);

        blueVal = blue(wheelVal) * float(fadeVal/fadeMax);

 

        strip.setPixelColor( i, strip.Color( redVal, greenVal, blueVal ) );

 

      }

 

      //First loop, fade in!

      if(k == 0 && fadeVal < fadeMax-1) {

          fadeVal++;

      }

 

      //Last loop, fade out!

      else if(k == rainbowLoops – 1 && j > 255 – fadeMax ){

          fadeVal–;

      }

 

        strip.show();

        delay(wait);

    }

  

  }

 

  delay(500);

 

  for(int k = 0 ; k < whiteLoops ; k ++){

 

    for(int j = 0; j < 256 ; j++){

 

        for(uint16_t i=0; i < strip.numPixels(); i++) {

            strip.setPixelColor(i, strip.Color(0,0,0, neopix_gamma[j] ) );

          }

          strip.show();

        }

 

        delay(2000);

    for(int j = 255; j >= 0 ; j–){

 

        for(uint16_t i=0; i < strip.numPixels(); i++) {

            strip.setPixelColor(i, strip.Color(0,0,0, neopix_gamma[j] ) );

          }

          strip.show();

        }

  }

 

  delay(500);

 

}

 

void whiteOverRainbow(uint8_t wait, uint8_t whiteSpeed, uint8_t whiteLength ) {

  

  if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() – 1;

 

  int head = whiteLength – 1;

  int tail = 0;

 

  int loops = 3;

  int loopNum = 0;

 

  static unsigned long lastTime = 0;

 

  while(true){

    for(int j=0; j<256; j++) {

      for(uint16_t i=0; i<strip.numPixels(); i++) {

        if((i >= tail && i <= head) || (tail > head && i >= tail) || (tail > head && i <= head) ){

          strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );

        }

        else{

          strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));

        }

        

      }

 

      if(millis() – lastTime > whiteSpeed) {

        head++;

        tail++;

        if(head == strip.numPixels()){

          loopNum++;

        }

        lastTime = millis();

      }

 

      if(loopNum == loops) return;

    

      head%=strip.numPixels();

      tail%=strip.numPixels();

        strip.show();

        delay(wait);

    }

  }

  

}

void fullWhite() {

  

    for(uint16_t i=0; i<strip.numPixels(); i++) {

        strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );

    }

      strip.show();

}

 

// Slightly different, this makes the rainbow equally distributed throughout

void rainbowCycle(uint8_t wait) {

  uint16_t i, j;

 

  for(j=0; j<256 * 5; j++) { // 5 cycles of all colors on wheel

    for(i=0; i< strip.numPixels(); i++) {

      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));

    }

    strip.show();

    delay(wait);

  }

}

 

void rainbow(uint8_t wait) {

  uint16_t i, j;

 

  for(j=0; j<256; j++) {

    for(i=0; i<strip.numPixels(); i++) {

      strip.setPixelColor(i, Wheel((i+j) & 255));

    }

    strip.show();

    delay(wait);

  }

}

 

// Input a value 0 to 255 to get a color value.

// The colours are a transition r – g – b – back to r.

uint32_t Wheel(byte WheelPos) {

  WheelPos = 255 – WheelPos;

  if(WheelPos < 85) {

    return strip.Color(255 – WheelPos * 3, 0, WheelPos * 3,0);

  }

  if(WheelPos < 170) {

    WheelPos -= 85;

    return strip.Color(0, WheelPos * 3, 255 – WheelPos * 3,0);

  }

  WheelPos -= 170;

  return strip.Color(WheelPos * 3, 255 – WheelPos * 3, 0,0);

}

 

uint8_t red(uint32_t c) {

  return (c >> 16);

}

uint8_t green(uint32_t c) {

  return (c >> 8);

}

uint8_t blue(uint32_t c) {

  return (c);

}

Start typing and press Enter to search

Bluestamp Engineering