A quick and dirty vehicle entry/start sketch for Arduino

  • Community Helper

    Removal of steering lock and locking ignition barrel:

    Shear bolts removed by drilling a hole and using an 'easy-out' screw:

    This is the catch that actually locks your steering wheel:

    Here is the actual ignition switch where it lives on the back of the locking barrel. I'm keeping this for the moment, it'll be hidden away out of sight.

    Here is the switch removed from the barrel, yours may have more screws:

  • Community Helper

    Finished for now, all mounted and the NFC reader where the key used to go. I'll print a black blank cover for it and it'll look like it's supposed to be that way!

  • Is it just me or did you break the key barrel slot? Lol. I could be nuts

  • Community Helper

    nah, it's that teardrop shape to fit in the barrel plus lock button. Makes it a little more irritating to make a blank for, but never mind. It's behaved so far (I still haven't hooked up a 'run mode' sense of some kind to stop the occasional starter motor grind but it hasn't happened again yet.

  • Community Helper

    So, I'm currently modifying my circuit to include seperately triggered LEDs to show which state the starter is in and an input to read whether the handbrake is on or off - if the handbrake is on then the starter will assume it's safe to crank the engine, if not then it skips the cranking step entirely.
    Meanwhile I'll be able to see if the arduino has reset itself or not and choose whether to engage the handbrake when I stop and switch off or circumvent the starting phase by leaving it off and cycling through modes to stop.

    Sounds complicated but it makes sense to me, we'll see how it goes.

  • Community Helper

    Version 3 of the car starter code, with state indicator LEDs and handbrake sense.

    int triggerPin1 = 2;
    int triggerPin2 = 3;
    int triggerPin3 = 4;
    int indicatorPin1 = 5;
    int indicatorPin2 = 6;
    int indicatorPin3 = 7;
    int indicatorPin4 = 8;
    int handbrakePin1 = 9;
    int carRunState = 0;
    int handbrakeState = 0;
      #include <Wire.h>
      #include <PN532_I2C.h>
      #include <PN532.h>
      PN532_I2C pn532i2c(Wire);
      PN532 nfc(pn532i2c);
    void setup(void) {
      pinMode(triggerPin1, OUTPUT);
      pinMode(triggerPin2, OUTPUT);
      pinMode(triggerPin3, OUTPUT);
      pinMode(indicatorPin1, OUTPUT);
      pinMode(indicatorPin2, OUTPUT);
      pinMode(indicatorPin3, OUTPUT);
      pinMode(indicatorPin4, OUTPUT);
      pinMode(handbrakePin1, INPUT);
      Serial.println("Hello! I'm a Car!");
      uint32_t versiondata = nfc.getFirmwareVersion();
      if (! versiondata) {
        Serial.print("PN53x key scanner board not online");
        while (1); // halt
      // Got ok data, report state
      Serial.print("Reader Online, ");
      // Set the max number of retry attempts to read from a card
      // This prevents us from waiting forever for a card, which is
      // the default behaviour of the PN532.
      // configure board to read NFC tags
      Serial.println("Waiting for a valid key");
    void loop(void) {
      String ringUid;
      boolean success;
      uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
      uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
      // Wait for an ISO14443A type cards (NFC Ring, Mifare, etc.).  When one is found
      // 'uid' will be populated with the UID, and uidLength will indicate
      // if the uid is 4 bytes (Mifare Classic) or 7 bytes (NFC Ring or Mifare Ultralight)
      success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
      if (success) {
        // Display some basic information about the card
    //    Serial.print("  UID Length: "); Serial.print(uidLength, DEC); Serial.println(" bytes");
        Serial.print("  UID Value: ");
        for (uint8_t i = 0; i < uidLength; i++)
          Serial.print(uid[i], HEX);
          ringUid += String(uid[i], HEX);
        Serial.println(ringUid + "\n");
        if (ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx"){
          Serial.println("Key accepted!");
        if ((ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx") && (carRunState == 0)){
          Serial.println("PERMISSION GRANTED, SYSTEMS ON");
          digitalWrite(triggerPin3, HIGH);   // sets latching relay trigger on for ignition mode in car to allow start
          digitalWrite(indicatorPin2, HIGH); //show state, second LED
          delay(200);                  // waits briefly
          digitalWrite(triggerPin3, LOW);    // removes latching relay trigger
          carRunState = carRunState++;
        else if ((ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx") && (carRunState == 1)){
          handbrakeState = digitalRead(handbrakePin1); //check if handbrake is on or off
          if (handbrakeState = 0){//if handbrake is on then safe to crank car, if not then skip this mode entirely
            Serial.println("ENGINE CRANKING");
            digitalWrite(triggerPin1, HIGH);   // triggers output for engine starting
            digitalWrite(indicatorPin3, HIGH); //show state, third LED
            delay(2000);                  // waits for a second
            digitalWrite(triggerPin1, LOW);    // removes triggered output 
            Serial.println("ENGINE CRANKING COMPLETE");
          carRunState = carRunState++;     
        else if ((ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx" || ringUid == "xxxxxxxxxxxxxx") && (carRunState > 1)){
          Serial.println("SYSTEM OFF, SLEEP TIME");
          digitalWrite(triggerPin2, HIGH);   // Trigger latching relay to reset for vehicle OFF
          digitalWrite(indicatorPin1, HIGH); //show state, LED1 on
          digitalWrite(indicatorPin2, LOW); //LED2 off
          digitalWrite(indicatorPin3, LOW); //LED3 off
          delay(200);                  // waits briefly      
        digitalWrite(triggerPin2, LOW);    // Removes latching relay reset trigger
        carRunState = 0;
        digitalWrite(indicatorPin1, LOW); //LED1 off

  • Community Helper

    Heh, well that didn't work consistently but as it turns out the reset problem was entirely due to where I was taking my power feed from in the first place. Running a power feed straight from the main battery line stopped the issue I was having with my starter resetting itself (which turned out to be every time I was using the brakes to stop, hence why I didn't notice when it was happening - I was busy each time).
    I've commented out the handbrake sensing stuff and am just using it with the indicator lights to make sure it doesn't happen again and will test it like this for a while to see how it goes.

  • I saw an integer listed as "carRunState", or something like that. What are you using to set this? A pin or, programming string being monitored from within the sketch? So far I have worked out an input pin for the brake state, a pin for the tach state to monitor engine on/off, and an output to bring the security bypass that is already in for the remote starter that tells the obd all is good. I am still learning arduino sketch's so I have more of a flow chart in mind now. For starting:
    Sense ring-check brake state- if on > check engine state- off > accessory relay - pause for long hold then starter relay. Need to integrate tach level to appropriately gauge starter engage time. This is just of the top of my head though.

  • Nevermind that last post. Just saw the other thread...

  • Community Helper

    Carrunstate is just an arbitrary counter for which mode the arduino should be in. Handbrake state is the only input that's of any importance in that sketch - but wasn't working properly. Possibly my code is crap.