Doc Brown's Security Briefcase

by ossum in Circuits > Microcontrollers

7624 Views, 87 Favorites, 0 Comments

Doc Brown's Security Briefcase

progress_002.JPG

I like to think that Back to The Future's Doc Brown would have a security briefcase of his own design, instead of a combination lock, it would only open at 88MPH

I used the Mediatek Linkit One board and an old briefcase to make my own version.

This project is undoubtedly silly, but through it I will describe how to use the Linkit One's GPS to determine speed as well as how to display it on a seven segment display.

The locking mechanism is driven by a servo, also controlled by the Linkit One.

Parts Required

progress_001.JPG
  • Mediatek LinkIt One
  • Servo (I used a Corona DS-239MG Digital Slim Wing Servo)
  • Battery (inlcuded with Linkit One)
  • GPS antenna (inlcuded with Linkit One)
  • A case of some sort
  • 2 seven segment displays
  • A switch or button
  • 2 Shift Registers (74HC595)
  • Bits of wire
  • Protoboard/Perfboard

Power From Battery

LinkItONEUpdateFirmware2.jpg

One of my favorite parts about the Linkit One is that it is supplied with it's own battery and built-in chargin circuit.

All that is required to use the board in battery mode is to set the switch marked "PWR_SW" to the "BAT" position

When the "PWR_SW" is set to "BAT" the Linkit One will also charge via the USB port (but not via the 5V pins)

Get Speed From GPS Data

Linkit_one_antenna.jpg

Before we can do anything with the Linkit One's GPS, we need to attach the antenna to the port marked "GPS" on the back of the board.

GPS reported in the form of comma-separated strings, of which there are a whole lot of different types, each with a focus on a different set of data. All that I was interested in for this project was speed, so I used the "recommended minimum data for gps" or "RMC" string which looks something like this:

$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A 

This page has a great description of all the string types, here is an extract of the RMC string, you can see that ground speed is indicated in knots and is the 6th item in the list.

The only other piece of info that I required was the status, which is a single character "A" or "V" that indicates whether a GPS lock has been achieved.

      RMC          Recommended Minimum sentence C
     123519       Fix taken at 12:35:19 UTC
     A            Status A=active or V=Void.
     4807.038,N   Latitude 48 deg 07.038' N
     01131.000,E  Longitude 11 deg 31.000' E
     022.4        Speed over the ground in knots
     084.4        Track angle in degrees True
     230394       Date - 23rd of March 1994
     003.1,W      Magnetic Variation
     *6A          The checksum data, always begins with *

In addition, I found this blog post on parsing the data to be very helpful, it is a nice example of using the Linkit One to parse the GPS RMC string.

Driving a Servo

anim_004.gif
progress_003.png

Power Consumption

It is worth noting that you usually cannot drive a servo via a USB port, since they tend to consume more current than USB is allowed to supply (100-500mA depending on the port). Fortunately the LinkIt One has a battery, so it can easily supply the current required for a small servo.

Connections

RC servos have 3 pins, Data, Power and GND

I connected mine as follows

Servo Pin LinkIt One Pin
PWR 5V
GND GND
DATA D9

If you are in any doubt, there are Instructables all over the show on the topic, or you can head straight to the Arduino example page.

Code

The LinkIt One version of the Arduino IDE includes a piece of demo code to drive an RC servo, which is incredibly simple, I have included it below. It is a good idea to test your servo with this code before trying to get fancy.

#include <Servo.h> 
#define ard_log Serial.printf

int i;
Servo myservo;

void setup() {
    Serial.begin(115200);
    myservo.attach(9);
    myservo.write(90);

}

void loop() {
    delay(1000);

    i += 3;
    if (i == 180)
        i = 0;
    myservo.write(i);
    ard_log("write [%d]\n", i);
}

Driving the Seven Segment Displays

seven_seg_front.jpg
seven_seg_back.JPG
seven seg pins.png

A seven-segment display is just a collection of seven (or eight if it has a decimal point) LEDS, which can be used to display numbers when the correct LEDS are lit.

There are two challenges to using them which I will discuss my solutions to

  • Driving 14 LEDS without using up all of our digital output pins
  • Determining Which LEDS to light

Drive all 14 LEDS from 3 pins: Shift Registers

Intro

It would require about 14 digital output pins to drive the two seven-segment displays, which is just not practical, instead we make use of shift registers. The full operation of a shift register is beyond the scope of this Instructable, but here is a link to a good tutorial, in fact I based my code off their "Sample 2.3" code.

The connections from the Linkit one to the first shift register are as follows

latchPin 12 = latch = 12 on ard

shift reg 11 = clock = 11 on ard

shift reg 14 = data = 13 on ard

PINS 1-7, 15 Q0 " Q7 Output Pins
PIN 8 GND Ground, Vss
PIN 9 Q7" Serial Out
PIN 10 MR Master Reclear, active low
PIN 11 SH_CP Shift register clock pin
PIN 12 ST_CP Storage register clock pin (latch pin)
PIN 13 OE Output enable, active low
PIN 14 DS Serial data input
PIN 16 Vcc Positive supply voltage

Make sure that you know whether your displays are common-anode or common-cathode. Mine were common-cathode which meant that I connected each output pin (Q0-Q7) of the shift register to one of the LEDS via a resistor and then connected the common-cathode to ground.

When choosing the resistors for your display, remember that the LinkIt One uses 3.3V IO and not 5.5V like the Arduino. I chose 100 ohm resistors for 17mA current (3.3 - 1.6V = 1.7V across resistor), but should probably have aimed for the full 20mA since they ended up very dull.

Determining Which LEDS to light

I used this table to determine the segments for a given character.

First I made a column for each output pin of the shift register, then a corresponding colum, showing which pin of the 7-segment display it connects to.

Then I used the data sheet of the 7-segment display to correspond it's pin numbers to segments (the segments are labelled a-g)

You can see that I made a column for each character (0-9) and then wrote a 1 if the light must be on and 0 if it must be off (this is actually a truth table). The 'x' are 'dont care' because that pin isn't used.

Reading the column from the bottom up results in a binary number (for example the character 2 gives us X1101101) which we can convert to hex and use in our code (char 2 = 01101101 in binary = 0x6D in hex). I replaced all the X with 0, but it makes no difference.

Shift Pin Seg Pin Seg Name 0 1 2 3 4 5 6 7 8 9
Q0 2 A 1 0 1 1 0 1 1 1 1 1
Q1 3 F 1 0 0 0 1 1 1 0 1 1
Q2 5 E 1 0 1 0 0 0 1 0 1 0
Q3 9 D 1 0 1 1 0 1 1 0 1 0
Q4 13 C 1 1 0 1 1 1 1 1 1 1
Q5 14 G 0 0 1 1 1 1 1 0 1 1
Q6 15 B 1 1 1 1 1 0 0 1 1 1
Q7 NC NC X X X X X X X X X X

This is the basic code that I used to test that I had the correct bytes for the 10 different characters, it listens on the serial port for a number and outputs it to the first register, there is no error-checking if you input a character that is not 0-9.

/*
  Shift Register Example, modified to drive a seven seg display

 Hardware:
 * 74HC595 shift register
 * LEDs attached to each of the outputs of the shift register

 */
//Pin connected to ST_CP of 74HC595
int latchPin = 12;
//Pin connected to SH_CP of 74HC595
int clockPin = 11;
////Pin connected to DS of 74HC595
int dataPin = 13;

//holders for infromation you're going to pass to shifting function
byte data;
byte dataArray[10];

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  Serial.begin(9600);

  //Binary notation as comment
  dataArray[0] = 0x5F; //0b01011111
  dataArray[1] = 0x50; //0b01010000
  dataArray[2] = 0x6D; //0b01101101
  dataArray[3] = 0x79; //0b01111001
  dataArray[4] = 0x72; //0b01110010
  dataArray[5] = 0x3B; //0b00111011
  dataArray[6] = 0x3F; //0b00111111
  dataArray[7] = 0x51; //0b01010001
  dataArray[8] = 0x7F; //0b01111111
  dataArray[9] = 0x73; //0b01110011

}

void loop() {
  byte inByte = 0;

  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read() - '0';
    inByte = max(inByte, 0);
    inByte = min(inByte, 9);

    //load the light sequence you want from array
    data = dataArray[inByte];
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, data);
    //return the latch pin high to signal chip that it
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
  }
}


// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i = 0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOut�
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i = 7; i >= 0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1 << i) ) {
      pinState = 1;
    }
    else {
      pinState = 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}

Putting It All Together

IMG_9953.JPG
New-Project.png

Connections

Now that we have a speed measurement, a way of displaying it and a locking mechanism, we can turn this into a complete system

Connect up all the peripherals as described in the previous steps:

  • Battery
  • Displays
  • GPS Antenna
  • Switch
  • Servo

In order to make it easier to connect and disconnect, I attached all the peripherals to a "shield" which is really just a piece of perf-board with 2.54mm (0.1") headers soldered in, as you can see in my photo.

Code

My code is attached, it is simply all the snippets from the previous steps bundled together. I expect it to be updated over the next few days as I do more testing.

Some points are:

  • Seven Segment Characters are stored in an array of two-byte hex values called "dataArray"
  • getComma() returns the position of the Nth comma in a string
  • getDoubleNum(), GetChar() and getIntNum() extract those variables types from a string, between the start of the string and the next comma
  • parseGPRMC() uses the previously described functions to extract particular details from an RMC formatted GPS string , in particular, the speed.
  • displaySpeed() takes in an integer speed value and separates it into two digits for display on the seven-segment display

Locking Mechanism

IMG_20151120_164855.jpg
IMG_20151120_164849.jpg

The locking mechanism can be as robust or flimsy as you like, since my project was really "just for fun" I didn't bother with too much strength.

If you decide to go with a really tough lock, then you had better be sure that you get the code right, ir you could be locked out forever! It may be worth bringing the mini-usb out so that you can reprogram and recharge without opening the case.

I glued a small servo to the lower half of the case and then attached a L-shaped piece of aluminum to the top of the case. When the servo arm is rotated fully-clockwise it locks into place above the aluminium and prevents the case from opening.

Now is a good time to figure out the limits of your servo. I have attached my code which I use for testing limits, if the comments are not enough you can read more about it in Step 17 of my Zombie Robot Instructable.

Downloads