Remote vehicle ignition - Paying for some codeing help.

Hi there.
I'm currently a newbie to C++ and the Arduino, however i have a strong electronics background.

I've been working on a remote vehicle ignition for the past week now, and have had a PCB printed and everything physically has been implemented and pieced together minus the cell/gsm shield/

Basically, i have an arduino UNO R3, and two relays with transisters. one relay closes the contact for the vehicle to be "ON" and the second relay is to close the contact for the car's ignition.
Then i have an input that only goes HIGH when the vehicles alternator is running, thus, the car has started. When this pin is LOW, it means the car is not running.

What i've been told i need is a state machine, and as i'm new to C++, i have no idea how to piece this together.
I've done all the basic arduino tutorials, and can do very basic code. But nothing like a state machine.

What i need is this:

The arduino gets a serial command > fires the "ON" relay > Waits 5 seconds for the fuel pump to prime> then checks to see alternatorPin's state, if the state is LOW, the ignition relay is fired until the alternatorPin goes HIGH, once the alternatorPin goes HIGH, the ignition relay shuts off.

Then the code waits 10 minutes, after ten minutes the code restarts, waiting for another serial input.

I've put it like this:
State0: onPin = off, ignitionPin = off, alternatorPin = LOW.
Upon recival of serial command, go to state 1.

State1: onPin = on, ignitionPin = off, alternatorPin = LOW.
after 5 seconds go to state 2.

State2: onPin = on, ignitionPin = on, alternatorPin = LOW.
once alternatorPin becomes HIGH, go to state 3, if alternator pin is alrady HIGH, go to state0 (in case if someone floods the serial)

State3: onPin = on, ignitionPin = off, alternatorPin = HIGH.
once 10 minutes has elapsed go to state 0

This seems fairly simple, and i'm definetly willing to pay money in whichever way suits you, and your name would be included in the code.

Regards, Matt.

and your name would be included in the code

I suggest you spell out your expectations for ownership / publishing. In the U.S., if you, the person paying the bill, does not explicitly state that the effort is "work for hire" then the copyright remains in the hands of the person who developed the program.

This will get you part way there:

/*
The arduino gets a serial command > fires the "ON" relay > Waits 5 seconds for the fuel pump to prime> then checks to see alternatorPin's state, 
if the state is LOW, the ignition relay is fired until the alternatorPin goes HIGH, once the alternatorPin goes HIGH, the ignition relay shuts off.
 
 Then the code waits 10 minutes, after ten minutes the code restarts, waiting for another serial input.
 
 State0: onPin = off, ignitionPin = off, alternatorPin = LOW. 
 Upon recival of serial command, go to state 1.
 
 State1: onPin = on, ignitionPin = off, alternatorPin = LOW.
 after 5 seconds go to state 2.
 
 State2: onPin = on, ignitionPin = on, alternatorPin = LOW.
 once alternatorPin becomes HIGH, go to state 3, if alternator pin is alrady HIGH, go to state0 (in case if someone floods the serial)
 
 State3: onPin = on, ignitionPin = off, alternatorPin = HIGH.
 once 10 minutes has elapsed go to state 0
 */
 
// system states 
#define STOPPED   0
#define STARTING  1
#define CRANKING  2
#define RUNNING   3

#define FUEL_PUMP_PRIME_TIME  5000
#define RUNNING_TIMEOUT 600000UL

const int ignitionPin = 12;
const int onPin = 11;
const int ledPin = 13;
const int alternatorPin = 4;

int state = STOPPED;        // master variable for the state machine
unsigned long StartingTime; // When did we power up the engine? Need this to time the fuel pump priming
unsigned long RunningTime;  // When did the engine start? Need this for the ten minute timeout

void setup() 
{
pinMode(onPin, OUTPUT);
pinMode(ignitionPin, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(alternatorPin,INPUT);
Stop(); // Make sure everything is set correctly
Serial.begin(9600);
}

void loop() 
{
switch(state)
  {
  case STOPPED:
    HandleStoppedState();
    break;
  case STARTING:
    HandleStartingState();
    break;
  case CRANKING: // Crank until the engine starts - shouldn't there be a timeout of some sort?
    HandleCrankingState();
   break;  
  case RUNNING:
    if(millis()-RunningTime > RUNNING_TIMEOUT)
      {
      Serial.println("Running Timeout");  
      Stop();  
      }
    break;  
  default:
    Serial.print("Unknown State: ");
    Serial.println(state);
    Stop(); // Should never get here
    break;  
  }
}

void Stop()
{
Serial.println("Stop");  
digitalWrite(ignitionPin,LOW);
digitalWrite(onPin,LOW);
state=STOPPED;
}

void HandleStartingState()
{
if(millis()-StartingTime > FUEL_PUMP_PRIME_TIME)
  {
  if(digitalRead(alternatorPin)==HIGH)
    {
    Serial.println("Abort cranking");  
    Stop(); // Don't crank the engine - it's already running, something is wrong, let's just stop
    }
  else
    {  
    Serial.println("Start cranking");  
    digitalWrite(ignitionPin,HIGH);
    digitalWrite(onPin,HIGH);
    state=CRANKING;
    }  
  }
}

void HandleStoppedState()
{
if (Serial.available() > 0) 
  {
  Serial.read(); // I wonder if this should be flush
  Serial.println("Power up");  
  StartingTime=millis();
  digitalWrite(ignitionPin,LOW);
  digitalWrite(onPin,HIGH);
  state=STARTING;
  }      
}

void HandleCrankingState()
{
if(digitalRead(alternatorPin)==HIGH) 
  {    
  Serial.println("Start Running");  
  digitalWrite(ignitionPin,LOW);
  digitalWrite(onPin,HIGH);
  RunningTime=millis();
  state=RUNNING;
  }
}

Compiled, not tested. You'll need to tweak it a bit - comment out the debugging stuff when you've tested it for example. I also thought that it ought to clear out the serial port when it reads it so it won't immediately start again after a timeout if there was extra stuff sent to the aurduino the first time (CRLF perhaps).

I'm not clear from the spec what to do if you receive a start order and the engine is already running. I chose to assume something's wrong and just stop.

Note that in every state transition I have set the ignition and on outputs to that which is appropriate for the new state. You can easily see that many of these are unnecessary (once the system is on, only the ignition varies until you stop it).

Code is not particularly good - those globals irk me, but I didn't want to start throwing in references to confuse you.

Also, how do you handle whether the car is in gear - I assume that's external to the arduino piece?

Good luck - I believe you owe me a beer :wink:

Oh wow, thank you so much for putting in the effort, this is truly amazing :slight_smile:
You've forgotton to put your name in the code, so i''ll put a link to your arduino forum profile and forum name :slight_smile:
I'm still new to states and such, so it confuses me a little, but i get the grasp of the code, i shall test tomorrow :slight_smile:

With this:

case CRANKING: // Crank until the engine starts - shouldn't there be a timeout of some sort?
         HandleCrankingState();
         break;

Does this mean that it will stop cranking when the alternatorpin goes high?
Because, when the car's running, the alternatorpin will go high, meaning the car can stop cranking. I chose this method over just a timeout because some mornings when it's cold, the car takes a little extra to start.

Regards, Matt.
And i think i owe you more than a beer :slight_smile:
Chuck me your address in a PM and i'll mail you some australianbeer, i.e Victoria Bitter or Carlton Draught. :slight_smile:

Also, with

I'm not clear from the spec what to do if you receive a start order and the engine is already running. I chose to assume something's wrong and just stop.

That's fine :slight_smile:
Oh, and the car's an automatic too, so no need to worry about that issue.

Sorry, after reading and testing the code, it works perfectly.
And regards to the starter motor timeout, yes, i need to add a timeout if it won't start, as in the rare occurence the car refuses to start, i don't want it burning out the starter motor.

This is awesome, thank you so much!
I've just ordered the sparkfun GSM shield, when it arrives, i shall attempt to get it to work with this.

Regards, Matt.

aussie-v8 can you please tell me how you get the alternator pin working. What wire do i connect from alternator to arduino and how. please help me.

OK, I've worked in the automotive world, and there are a LOT of things you aren't considering.

Is this being powered from the car? What type of DC-DC controller do you have on the input of this device to power the uC and other circuitry? Have you considered load dump/BCI tolerance for this circuit? If you end up with a 42V transient at the power input, will it survive? Read about BCI... Implement redundant failsafes so that your vehicle does NOT try to start if a BCI or other transient event makes your microcontroller suddenly think that it's time to start the car. You may want to enclose this entire thing in a shielded box. Implement input filtering on the power input. Put a series diode on the input and a big cap on the PCB side so you can hopefully ride through cold crank and not have your uC lose it's mind when the vehicle starts cranking in a worst-case situation and input voltage drops below 5V. Etc, etc, etc...
Also... Look at the schematic for your vehicle. Where do the wires go that you are using to control the vehicle. How much current flows through them. How high does the voltage ring during cold crank on the pin you're using to sense alternator voltage. Is it high enough to damage the ADC you've connected it to? Are you using a buffer? What is the Abs(max) voltage of any pins that interface to the outside world vs. what the voltage could possibly be.

shudders to think what could happen