Loading
Northstar Necklace

Northstar Necklace

by diskordier lucy | updated April 28, 2016

A directional necklace for the navigationally challenged | Neopixel LED strip necklace, of which only the northern-most LED is ever lit. Controlled by an integrated Adafruit Flora with compass/accelerometer sensor.

Clothing_icon
Electronics_icon

0

15/11/15

Can really got his heart set on using the necklace wearable for communicating other information, for example proximity to a specific GPS location - an idea that we also really liked but didn't have time to fully prototype. He worked on techniques for feeding desired GPS coordinates to the Lilypad.

March 20, 2016 at 6:33 PM
Created by lucy
Comments (0)

9/01/16

With Ramin we got started adapting the code for Flora and soldering up all the electronics.

March 20, 2016 at 7:40 PM
Created by lucy
Comments (0)

I was inspired by a few different sensory substitution hacks and wanted to make a simple one of my own to see if I can't actually programme my subconscious to interpret a new kind of data input:

Not least other hacks that give you live haptic compass direction:

I have a terrible sense of direction and would love to see if I can train myself to develop a gut feeling for magnetic north, like migratory birds do. However, I really wanted to make something that I would want to wear long-term and couldn't imagine being happy wearing the clunky belt or anklet. So I pumped for an LED necklace. I know the lit LED wouldn't be visible to me all the time... maybe 1 third of the time it would be out of my peripheral vision, but I figured that was information in itself.

I want to be able to wear the thing long-term to see if I can entrain myself to have a better sense of direction, either to landmarks around Berlin or, even better, to the sun... and get less lost :)

March 20, 2016 at 7:49 PM
Created by lucy
Comments (0)

15/11/15

So I pitched the idea to the good people at Science Hack Day Dublin, 14-15th November. The response was great, we made up a team of 3, put together a functioning first prototype, and WON THE BEST CONCEPT PRIZE!!

The Adafruit compass/accellerometer sensor we used delivers 6 data points - 3 dimensions for magnetic north and 3 dimensions for gravity. Processing this information into a single compass heading proved trickier than we thought... non-euclidian spherical geometry anyone? So instead, for the first prototype we just took 2 dimensions of compass data and made sure to hold the thing consistently in one plane. 

 

Team:

Parts:

  • Arduino Lilypad
  • Adafruit Compass/Accelerometer sensor
  • Adafruit Neopixels strip
  • Lithium-ion battery

Code:
written by Robert for lilypad. Needs the following libraries installed:
https://github.com/adafruit/Adafruit_Sensor
https://github.com/adafruit/Adafruit_LSM9DS0_Library
https://github.com/adafruit/Adafruit_NeoPixel

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM9DS0.h>
#include <Adafruit_NeoPixel.h>

Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0(1000);  // Use I2C, ID #1000
Adafruit_NeoPixel strip = Adafruit_NeoPixel(40, 9, NEO_GRB + NEO_KHZ800);

void configureSensor(void)
{
  // 1.) Set the accelerometer range
  lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_2G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_4G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_6G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_8G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_16G);
  
  // 2.) Set the magnetometer sensitivity
  lsm.setupMag(lsm.LSM9DS0_MAGGAIN_2GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_4GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_8GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_12GAUSS);

  // 3.) Setup the gyroscope
  lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_245DPS);
  //lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_500DPS);
  //lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_2000DPS);
}

void setup(void) 
{
//  pinMode(A5, OUTPUT);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
//  while (!Serial);  // wait for flora/leonardo
//  Serial.begin(9600);
  digitalWrite(13, LOW);
  
  if (!lsm.begin()) {
    while(1);
  }
  digitalWrite(13, HIGH);
  configureSensor();
  digitalWrite(13, LOW);
  
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  digitalWrite(13, HIGH);
}

float magX;
float magY;
float magZ;

void readAvg(const int count) {
  magX = 0.0F;
  magY = 0.0F;
  magZ = 0.0F;
  for (int i = 0; i < count; i++) {
    lsm.read();
    magX += lsm.magData.x;
    magY += lsm.magData.y;
    magZ += lsm.magData.z;
  }
  magX /= count;
  magY /= count;
  magZ /= count;
}

void loop(void) 
{  
  readAvg(3);

  float heading = atan2(magY, magX);
  float declinationAngle = 0.058F; // Dublin 3.334 * pi / 180 // http://www.magnetic-declination.com/
  heading += declinationAngle;

  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;
    
  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;

  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 
  headingDegrees -= 90.0F;
  
  int index = (((int)headingDegrees) / (360 / strip.numPixels())) % strip.numPixels();
//  Serial.print(index);
//  Serial.print("\tHead: \t"); Serial.print(headingDegrees); Serial.print("\t");
//  Serial.println();

//  Serial.print("X: "); Serial.print((int)lsm.magData.x);     Serial.print(" ");
//  Serial.print("Y: "); Serial.print((int)lsm.magData.y);         Serial.print(" ");
//  Serial.print("Z: "); Serial.println((int)lsm.magData.z);       Serial.print(" ");

  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0));
  }
  strip.setPixelColor(index, strip.Color(255, 255, 255));
  strip.show();

  delay(250);
}

 

April 8, 2016 at 11:16 AM
Created by lucy
Comments (0)

13/02/16

With some awesome help we got a new version of the code together that used all 6 data points from the compass/accellerometer sensor. Now it just needs a little tinkering and callibrating.

Here's the new code, based on https://learn.adafruit.com/lsm303-accelerometer-slash-compass-breakout/calibration ...

Uses the following libraries:
https://github.com/adafruit/Adafruit_Sensor
https://github.com/adafruit/Adafruit_LSM303
https://github.com/adafruit/Adafruit_NeoPixel

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303.h>

#include <Adafruit_NeoPixel.h>

Adafruit_LSM303 lsm;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(40, 6, NEO_GRB + NEO_KHZ800);
/*
void configureSensor(void)
{
  // 1.) Set the accelerometer range
  lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_2G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_4G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_6G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_8G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_16G);

  // 2.) Set the magnetometer sensitivity
  lsm.setupMag(lsm.LSM9DS0_MAGGAIN_2GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_4GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_8GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_12GAUSS);

  // 3.) Setup the gyroscope
  lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_245DPS);
  //lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_500DPS);
  //lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_2000DPS);
}
*/
int ledPin = 7;

void setup(void) {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  shortBlink();
  if (!lsm.begin()) {
    while (1);
  }
  Serial.println("lsm initialized");
  shortBlink();
  //configureSensor();
  shortBlink();
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  shortBlink();
}

void shortBlink() {
  for (int i = 0; i < 10; i++) {
    digitalWrite(ledPin, HIGH);
    delay(100);
    digitalWrite(ledPin, LOW);
    delay(100);
  }
}

float magX;
float magY;
float magZ;

void readAvg(const int count) {
  magX = 0.0F;
  magY = 0.0F;
  magZ = 0.0F;
  for (int i = 0; i < count; i++) {
    lsm.read();
    magX += lsm.magData.x;
    magY += lsm.magData.y;
    magZ += lsm.magData.z;
  }
  magX /= count;
  magY /= count;
  magZ /= count;
}

void loop(void)
{
  readAvg(3);

  float heading = atan2(magY, magX);
  float declinationAngle = 0.058F; // Dublin 3.334 * pi / 180 // http://www.magnetic-declination.com/
  heading += declinationAngle;

  // Correct for when signs are reversed.
  if (heading < 0)
    heading += 2 * PI;

  // Check for wrap due to addition of declination.
  if (heading > 2 * PI)
    heading -= 2 * PI;

  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180 / M_PI;
  headingDegrees -= 90.0F;

  int index = (((int)headingDegrees) / (360 / strip.numPixels())) % strip.numPixels();
  //  Serial.print(index);
  //  Serial.print("\tHead: \t"); Serial.print(headingDegrees); Serial.print("\t");
  //  Serial.println();

  //  Serial.print("X: "); Serial.print((int)lsm.magData.x);     Serial.print(" ");
  //  Serial.print("Y: "); Serial.print((int)lsm.magData.y);         Serial.print(" ");
  //  Serial.print("Z: "); Serial.println((int)lsm.magData.z);       Serial.print(" ");

  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0));
  }
  strip.setPixelColor(index, strip.Color(255, 255, 255));
  strip.show();

  delay(250);
}

April 8, 2016 at 1:22 PM
Created by lucy
Comments (0)