Introduction: FinduCar: a Smart Car Key Guiding People to Where the Car Is Parked

About: I love my life very much. I am passionate about making handicrafts. I hope to use them to explain my love for life and my hope for the future.

In order to solve the problems above, this project proposes to develop a smart car key which could direct people to where they parked the car. And my plan is integrating a GPS into the car key. There is no need to use the smartphone app to track the car, all the guidance will just show on the car key.

Step 1: Paper Sketch

When people press the button to lock the car, the location information could be recorded in the microcontroller automatically. Then, when people start to navigate to the car, the different LED is lighted up to direct to the position of the car and blinking frequency shows the distance to the car. They can easily follow the blinking LED and quickly find the car.

Step 2: Hardware List

These are the components used in this project. Some are from the particle kits(breadboard, button, headers), others are purchased from Adafruit official website( Adafruit Feather M0, Adafruit Ultimate GPS module , Lpoly Battery and Coin Cell Battery) and Amazon( NeoPixel Ring - 12 RGB LED).

Step 3: Circuit Design

Neopixel_LED is connected to the PIN 6 of Feather M0

Button_Unlock is connected to the PIN 12 of Feather M0

Button_Lock is connected to the PIN 13 of Feather M0

Step 4: Hardware Connection

Solder the headers with Adafruit M0 Feather, Adafruit Ultimate GPS Featherwing. Stack the two boards together. The GPS FeatherWing plugs right into your Feather M0 board without any more wires.

Step 5: Software Design

Test Components

  • Read a FIX
void setup() {
  Serial.println("GPS echo test");
  Serial.begin(9600);
  Serial1.begin(9600);      // default NMEA GPS baud
}
void loop() {
  if (Serial.available()) {
    char c = Serial.read();
    Serial1.write(c);
  }
  if (Serial1.available()) {
    char c = Serial1.read();
    Serial.write(c);
  }
}
  • Blink LED Ring

See Adafruit NeoPixel Examples.

GPS Calculation Functions

  • Calculate the Azimuth
// Calculate the Azimuth
double azimuth(double lat_a, double lon_a, double lat_b, double lon_b) {
    double d = 0;
    lat_a = lat_a*PI/180;
    lon_a = lon_a*PI/180;
    lat_b = lat_b*PI/180;
    lon_b = lon_b*PI/180;

    d = sin(lat_a)*sin(lat_b)+cos(lat_a)*cos(lat_b)*cos(lon_b-lon_a);
    d = sqrt(1-d*d);
    d = cos(lat_b)*sin(lon_b-lon_a)/d;
    d = asin(d)*180/PI;    return d;
}
  • Calculate the time on the LED clock, which is also the direction of the vehicle
// Calculate the time on LED clock
int led_time(double angle){
    int flag = 0;
    if (angle < 0){
      flag = 1;
    }
    angle = abs(angle);
    double angle_remainder = fmod(angle, 30);
    int angle_time = (int)angle/30;
    if (angle_remainder >= 15) {
      angle_time = angle_time + 1;
    }
    if (flag == 1){
      angle_time = 12 - angle_time;
    }
    return angle_time;
}
  • Calculate the distance between the person and his vehicle
// Calculate the Distance<br>
double distance(double lat_a, double lon_a, double lat_b, double lon_b) {
    double EARTH_RADIUS = 6378137.0;      double radLat1 = (lat_a * PI / 180.0);
    double radLat2 = (lat_b * PI / 180.0);
    double a = radLat1 - radLat2;
    double b = (lon_a - lon_b) * PI / 180.0;     double s = 2 * asin(sqrt(pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2)));
    s = s * EARTH_RADIUS / 10000000;
    return s;
}

LED Display Functions

  • Light up LEDs in a circle showing that it starts to navigate
// LED ring lighting one by one shows that the navigation begins
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}
  • Get the LED frequency on the basis of the distance
// Get LED Frequency
int frequency(double distance){
  int f = (int)distance * 20;
  return f;
}
  • Blink the certain LED indicating the direction of the car
//Display on LED
          strip.clear();
          strip.show();
          delay(frequency(car_person_distance)); 
//          delay(500);          
          strip.setPixelColor(angle_time, strip.Color(0, 0, 255));
          strip.show();
          delay(frequency(car_person_distance)); 
//          delay(500);
//Disable LED
          if (button_flag == 1 && car_person_distance < 5.0){
            button_flag = 0;
            led_flag = 1;
            strip.clear();
            strip.show();         
          }

Main

#include Adafruit_GPS.h<br>#include Adafruit_NeoPixel.h
#include HardwareSerial.h
#include Button.h
#include math.h
#define Neopixel_LED_PIN 6
#define Neopixel_LED_NUM 12
#define Button_Lock_PIN 13
#define Button_Unlock_PIN 12
#define GPSSerial Serial1
<p>#define GPSECHO false</p>
Adafruit_GPS GPS(&GPSSerial);<br>Adafruit_NeoPixel strip = Adafruit_NeoPixel(Neopixel_LED_NUM, Neopixel_LED_PIN, NEO_GRB + NEO_KHZ800);
Button button_lock(Button_Lock_PIN);
Button button_unlock(Button_Unlock_PIN);
int button_flag = 0;
int led_flag = 1;
uint32_t timer = millis(); double car_lat, car_lon; double car_person_distance;
double move_direction;
double car_azimuth;
double car_person_angle;
int angle_time;
void setup() {
  Serial.begin(115200);
//  Serial1.begin(9600);
  GPS.begin(9600);      // default NMEA GPS baud
  strip.begin();  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate  // Request updates on antenna status, comment out to keep quiet
//  GPS.sendCommand(PGCMD_ANTENNA);  delay(1000);}
void loop() {//  if (Serial.available()) {
//    char c = Serial.read();
//    Serial1.write(c);
//  }
//  if (Serial1.available()) {
    char c = GPS.read();    if (GPSECHO)
      if (c) Serial.print(c);    // if a sentence is received, we can check the checksum, parse it...
    if (GPS.newNMEAreceived()) {
      // a tricky thing here is if we print the NMEA sentence, or data
      // we end up not listening and catching other sentences!
      // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
      Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
      if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
        return; // we can fail to parse a sentence in which case we should just wait for another
    }
    
    // if millis() or timer wraps around, we'll just reset it
    if (timer > millis()) timer = millis();
    if (millis() - timer > 2000) {
      timer = millis(); // reset the timer
      Serial.print("\nTime: ");
      Serial.print(GPS.hour, DEC); Serial.print(':');
      Serial.print(GPS.minute, DEC); Serial.print(':');
      Serial.print(GPS.seconds, DEC); Serial.print('.');
      Serial.println(GPS.milliseconds);
      Serial.print("Date: ");
      Serial.print(GPS.day, DEC); Serial.print('/');
      Serial.print(GPS.month, DEC); Serial.print("/20");
      Serial.println(GPS.year, DEC);
      Serial.print("Fix: "); Serial.print((int)GPS.fix);
      Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
      if (GPS.fix) {
        Serial.print("Location: ");
        Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
        Serial.print(", "); 
        Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
        Serial.print("Location (in degrees, works with Google Maps): ");
        Serial.print(GPS.latitudeDegrees, 4);
        Serial.print(", "); 
        Serial.println(GPS.longitudeDegrees, 4);
      
        Serial.print("Speed (knots): "); Serial.println(GPS.speed);
        Serial.print("Angle: "); Serial.println(GPS.angle);
        Serial.print("Altitude: "); Serial.println(GPS.altitude);
        Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
  
        // Save the GPS of the vehicle      
        if (button_lock.read()) {
          car_lat = GPS.latitudeDegrees;
          car_lon = GPS.longitudeDegrees;
          //for debug
          Serial.print("carLatitude: "); Serial.println(car_lat);
          Serial.print("carLongitude: "); Serial.println(car_lon);
        }  
        
        // Start to find the car
        if (button_flag == 0){
          button_flag = button_unlock.read();        
        } 
        
        if(button_flag == 1 && led_flag == 1){
          colorWipe(strip.Color(0, 255, 0), 500);
          
          led_flag = 0;
        }     
  
        if (button_flag == 1) {    
          car_person_distance = distance(GPS.latitudeDegrees, GPS.longitudeDegrees, car_lat, car_lon); //Calculate the distance
          //car_person_distance = distance(100.0005, 100.0005, 100.0, 100.0);
          //for debug
          Serial.println(car_person_distance);
          move_direction = GPS.angle;//Record the moving direction(angle)
          //move_direction = 100.0;
          // Record the Azimuth(angle)     
          car_azimuth = azimuth(GPS.latitudeDegrees, GPS.longitudeDegrees, car_lat, car_lon);
          //car_azimuth = azimuth(100.0005, 100.0005, 100.0, 100.0);
          // Calculate the time on LED clock
          car_person_angle = car_azimuth - move_direction;
          angle_time = led_time(car_person_angle);
  
          //Display on LED
          strip.clear();
          strip.show();
//          delay(frequency(car_person_distance));
          delay(500);          
          strip.setPixelColor(angle_time, strip.Color(0, 0, 255));
          strip.show();
//          delay(frequency(car_person_distance));
          delay(500);  
  
          //Disable LED
          if (button_flag == 1 && car_person_distance < 5.0){
            button_flag = 0;
            led_flag = 1;
            strip.clear();
            strip.show();         
          }
        }      
      }
//    }
  }
}

Step 6: Debug on Breadboard

Step 7: Hardware Assembly

Step 8: Electronics Housing Design in Adobe Illustrator

Step 9: Cardboard Prototype

This step is used to confirm the size of the housing and every piece of the model, making sure the box size, and the button position, and LED position fit the assembled electronic components.

Step 10: Birch Plywood Prototype

This was the initial prototype. A square hole for plugging into a charger was added to one of the pieces finally.

Step 11: Final Assembly Prototype