benstr πŸš€
Published © MIT

Unicorn Finder (Kid Tracker for Techie Parents)

The Arduino Uno controls a 16 Neopixel unicorn horn. This includes a GPS module broadcasting through a cellular GSM shield.

IntermediateFull instructions provided3 hours10,700
Unicorn Finder (Kid Tracker for Techie Parents)

Things used in this project

Hardware components

Hologram Global IoT SIM Card
Hologram Global IoT SIM Card
×1
Arduino UNO
Arduino UNO
×1
Arduino GSM Shield 2
×1
Adafruit Ultimate GPS Breakout
Adafruit Ultimate GPS Breakout
×1
Adafruit NeoPixel Stick
×2

Software apps and online services

Arduino IDE
Arduino IDE
Hologram Data Router
Hologram Data Router
Losant Platform
Losant Platform

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

3D Unicorn Horn

Available at http://www.thingiverse.com/thing:956359

Schematics

Unicorn Finder

Fritzing Schematic

Code

Arduino Sketch

Arduino
// ADAFRUIT NEOPIXEL GLOBALS ------------------------------------------
#include <Adafruit_NeoPixel.h>
#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(8, PIN, NEO_GRB + NEO_KHZ800);

// ADAFRUIT ULTIMATE GPS GLOBALS -------------------------------------
#include <Adafruit_GPS_Alt.h>
#include <AltSoftSerial.h>
AltSoftSerial mySerial(8, 7);
Adafruit_GPS_Alt GPS(&mySerial);
#define GPSECHO false
boolean usingInterrupt = false;
void useInterrupt(boolean);
uint32_t timer = millis();
String lastCoor = "\"coords\": [0,0]";

// ARDUINO GSM GLOBALS ------------------------------------------------
#include <GSM.h>
#define PINNUMBER ""
#define GPRS_APN "hologram"
#define GPRS_LOGIN ""
#define GPRS_PASSWORD ""
GSMClient client;
GPRS gprs;
GSM gsmAccess; // pass (true) for debugger

// HOLOGRAM CLOUD GLOBALS ---------------------------------------------
char server[] = "23.253.146.203"; // the base URL or IP
int port = 9999; // 80 for HTTP, 443 for HTTPS, 999 for TCP
const char HOLOGRAMID[] = "xxxx"; //replace with 4 digit shared id from device details on dashboard
const char HOLOGRAMKEY[] = "xxxx"; //replace with 4 digit shared key from device details on dashboard

void setup() {
  Serial.begin(115200);
  
  // ADAFRUIT NEOPIXEL SETUP ------------------------------------------  
  Serial.println(F("Initializing Adafruit NeoPixels..."));
  strip.begin();
  strip.setBrightness(100); //adjust brightness here
  strip.show(); // Initialize all pixels to 'off'

  // ADAFRUIT GPS SETUP -----------------------------------------------
  Serial.println(F("Initializing Adafruit GPS..."));
  GPS.begin(9600);
  // Setup GPS to report the data we need
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  GPS.sendCommand(PGCMD_ANTENNA);
  useInterrupt(true);
  delay(1000);
  mySerial.println(F(PMTK_Q_RELEASE));

  // ARDUINO GSM SETUP ------------------------------------------------
  Serial.println(F("Initializing Arduino GSM..."));
  boolean notConnected = true;
  while(notConnected){
    if((gsmAccess.begin(PINNUMBER)==GSM_READY) & (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD)==GPRS_READY)) {
      notConnected = false;
      Serial.println(F("Cellular Network Connected"));
    } else {
      Serial.println(F("Not Connected to Cellular Network"));
      delay(1000);
    }
  }

  Serial.print(F("Arduino UNO Free RAM: ")); Serial.println(freeRam());
  delay(1000);
}

 
void loop() {
  // ADAFRUIT NEOPIXEL LOOP ------------------------------------------ 
  Serial.println(F("Rainbow Cycling...")); 
  rainbowCycle(10);

  // ADAFRUIT GPS LOOP -----------------------------------------------
  if (GPS.newNMEAreceived()) {
    if (!GPS.parse(GPS.lastNMEA()))
      return;
  }
  
  String message;
  String newCoor = lastCoor;
  Serial.print(F("GPS Fixed: ")); Serial.println((int)GPS.fix);
  Serial.print(F("GPS Satellites: ")); Serial.println((int)GPS.satellites);
  if (GPS.fix + GPS.satellites > 1) {
    newCoor = "";
    newCoor.concat(F("\"gps\":"));
    newCoor.concat(GPS.latitude);
    newCoor.concat(F(", "));
    newCoor.concat(GPS.longitude);
    
    message.concat(F("{"));
    message.concat(newCoor);
    message.concat(F("}")); 

    Serial.print(F("Arduino UNO Free RAM: ")); Serial.println(freeRam());
  }

  // ARDUINO GSM / HOLOGRAM CLOUD LOOP -------------------------------
  Serial.print(F("Last Coordinates: ")); Serial.println(lastCoor);
  Serial.print(F("New Coordinates: ")); Serial.println(newCoor);
  if (lastCoor != newCoor) {
    char msgbuf[38];
    Serial.print(F("message: ")); Serial.println(message);
    message.toCharArray(msgbuf, 38);
    modemCloudWrite(msgbuf);
    lastCoor = newCoor;
  }

  Serial.println(F("Loop Finished"));
  Serial.println();
}


int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}


// ADAFRUIT NEOPIXEL FUNTIONS ------------------------------------------
 
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;
  for(j=0; j<256*10; j++) { // 10 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);
  }
}
 
// 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) {
  if(WheelPos < 85) {
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

// ARDUINO GSM / HOLOGRAM CLOUD FUNCTIONS -----------------------------

// Make a TCP write
bool modemCloudWrite(char * msg) {
  // if you get a connection send message then disconnect
  if (client.connect(server, port)) {
    Serial.println(F("Connected to Hologram"));
    client.beginWrite();
    client.print(F("A"));
    client.print((char*)HOLOGRAMID);
    client.print((char*)HOLOGRAMKEY);
    client.print(F(" "));
    client.print(F("S"));
    client.print(msg);
    client.println(F("\n\n"));
    client.endWrite();
  
    Serial.print(F("Message sent: "));
    Serial.println(msg);
    client.stop();
    Serial.println(F("Disconnecting Cellular"));
    Serial.println();
  }
}


// ADAFRUIT GPS FUNCTIONS -----------------------------
// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
#ifdef UDR0
  if (GPSECHO)
    if (c) UDR0 = c;  
    // writing direct to UDR0 is much much faster than Serial.print 
    // but only one character can be written at a time. 
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

Adafruit_GPS_Alt.zip

Arduino
Use this GPS library instead of the one found in the library manager.
No preview (download only).

Credits

benstr πŸš€

benstr πŸš€

5 projects β€’ 115 followers
πŸ‘‹ Managing Director of Hackster. Please reach out when you have thoughts on how to make Hackster more awesome πŸ“§ ben.s@hackster.io

Comments