Vehicle speed sensor

Hi,

I'm new to Arduino and a novice at programming so I'm looking for some guidance and help to achieve what should be a relatively simple task.

My car has a vehicle speed signal (VSS) which pulses 8000 time a mile, its a square wave 5V pulse. So to convert that into mph I would count the pulses in a second and use

miles per hour = pulse count/(8000/3600)

I think that is right but correct me if I'm wrong.

So what I want to achieve with this Arduino project is to monitor the miles per hour on the VSS wire.

When the VSS input hits 40mph I want an output signal to send pulses equivalent to 100mph and to maintain that output at a constant 100mph until the VSS drops to 5mph.

Can somebody help with this, happy to buy someone a beer if they can help.

TIA

miles per hour = pulse count/(8000/3600)

Perhaps if you count pulses for an hour but otherwise no.

average velocity = distance / time

and pulses only give you distance. You need to measure the time part.

At 64mph you should get ... hold on... 142.222 pulses/second, a pulse every 7 milliseconds but time them with micros() not millis().

If you plan on displaying speed as digits, don't update the display faster than eyes can follow, 4 or 5 updates a second is plenty. You will be able to calculate average speed that many times a second with cycles to spare.

PS -- silly me, I should explain Arduino timing!

Arduino keeps a clock ticking every microsecond.
The Arduino millis() function counts milliseconds but skips 6 values out of every 256, it's good if you're not timing small numbers of milliseconds or you don't care about + or - 1 when determining time intervals which for most uses is just fine.
The Arduino micros() function counts microseconds to the nearest 4, you don't need closer.
Both functions return 32-bit unsigned long values. Less bits can be used but don't for now.

Somewhere in your code something happens and the sketch saves the micros() value.
Later on you can see how long it's been since that time mark was saved...

unsigned long startMicros, elapsedMicros;
...............
startMicros = micros(); // event detected, save the time
.................
elapsedMicros = micros() - startMicros; // later on, remember that micros() always returns "now"

Since the time values are all unsigned integers, the subtraction will ALWAYS be right up to the limit that the time values can count. Unsigned long micros can count a bit over 70 minutes, you're safe.

Rollover happens, the subtraction still works the same. If your clock counted to 1 to 12 and was round, subtracting is the same as moving the hand backwards. 2 - 4 would = 10, right?
The limit of that clock is that it can only time up to 11 apart, 12 apart would get 0.

Hi,

Im not looking to display anything I just want to give a false VSS above 40 mph, Ive done a bit of research and come up with this. would this work?

void setup() {
  // put your setup code here, to run once:
  const int hardwareCounterPin = 5;
  const int samplePeriod = 1000; 
  unsigned int count;
  unsigned int vssout;
}

void loop() {
  
  bitSet(TCCR1B, CS12); 
  bitSet(TCCR1B, CS11); 
  delay(samplePeriod); 
  TCCR1B = 0; 
  count = TCNT1; 
  TCNT1 = 0;     
  if (count > 88) int vssout = 222;
  if (count  <11) int vssout = 0;
  analogWrite(pin, vssout);


}

Your delay() is for 1 second. That analogWrite() only updates every second.

You could actually update that on every pulse received without resorting to setting counter bits.
I'm not joking, 7ms is a long time to Arduino.

A false VSS above 40? Trying to avoid speeding tickets?

LOL, no its not speeding tickets. Its to fool my speed dependant spoiler into raising at 40mph instead of 95mph.

Do you think that code I wrote above will work?

I dont need it to refresh very quickly but if you can show me how to make the code more responsive or efficient I would really appreciate it

Oh, cool!

40 miles/hour * 8000 pulses/mile =
320000 pulses/hour * 1 hour/3600000 ms =
0.088888889 pulses/ms =
1 pulse every 11.25 ms/pulse = 11250 us/pulse --- micros per pulse at 40 mph.

I threw in some hysteresis to keep the spoiler from flapping when speed is close to 40mph.
It goes up at 40+ but does not lower until 36-.

This compiles and likely void loop will run around 80-100 times per millisecond.

// Spoiler control with hysteresis sketch, free to use, by GFS 5/26/18

unsigned long startPulse;
unsigned long fortyMPH = 11250; 
unsigned long thirtysixMPH = 12500; // micros timing
byte pulseState;
byte prevState;
byte pulsePin = 5;
byte analogPin = A0;
byte spoilerUp = 222;
byte spoilerDown = 0;

void setup()
{
  pinMode( analogPin, OUTPUT ); // probably not necessary for analog write
}

void loop()
{
  pulseState = digitalRead( pulsePin ); // will read the same pulse many times
  
  if (( prevState == 0 ) && ( pulseState > 0 )) // pulse start detected
  {
    if ( micros() - startPulse <= fortyMPH )  // faster speed, less time
    {
      analogWrite( analogPin, spoilerUp );
    }
    else if ( micros() - startPulse >= thirtysixMPH ) // hysteresis
    {                                                 // keep the spoiler 
      analogWrite( analogPin, spoilerDown );          // from flapping!
    }
    startPulse = micros();
  }

  prevState = pulseState;
}

BTW, can the spoiler be positioned between fully up or down? At slower speeds you might want a higher angle, airfoil lift at AOA (if not stalled) increases by the square of speed as does drag.
Heck, do you want a lot of spoiler when driving straight or only on curves?

Im working on an odometer project and am going through similar headaches trying to understand the maths!
Another option if it works for you is to use a GPS for your speed... you could set up a controller with LCD to change the spoiler raise speed at the push of a button in your cockpit...

Suggest using the pulseIn() function to find the input interval and hence speed, and the tone() function to output your simulated 100mph.

Allan

pulseIn() blocks and these pulses are a few to many ms wide.
Even at over 60MPH a single pulse cycle (start of one to start of the next) is wide enough to get velocity with every pulse without resorting to direct hardware manipulation.

With a red-green led you could indicate the spoiler PWM signal as green, red, amber or off/no power on the same led.
Yes there are RGB leds but the bulbs of those need a diffuser to look like colored dots where the RG leds do not and cost way less.

OK so I uploaded the sketch to my arduino nano and it didnt work.

I got out my multimeter and measured the VSS going into PIN D5 at 40mph and its actually 60hz. So my information about 8000 pulses per mile must be incorrect.

Any way I carried on driving but didnt get any output from Pin A0 at any speed.

:confused:

Since your VSS outputs 5v square wave pulses, why not use interrupts?
There is a very simple piece of Hall Effect Arduino code here:
https://maker.pro/files/ArduinoHallEffect.ino

dexterbug:
OK so I uploaded the sketch to my arduino nano and it didnt work.

I got out my multimeter and measured the VSS going into PIN D5 at 40mph and its actually 60hz. So my information about 8000 pulses per mile must be incorrect.

Any way I carried on driving but didnt get any output from Pin A0 at any speed.

:confused:

Time to adjust the fortyMPH value?

It would be easier to debug if the Nano could display some runtime info.

Even blinking a led could help, like making 1 blink every 800 pulses (should be 1/10th mile) or so. See how far it's off and calibrate the values.

Perhaps also in setup(), add a line: pinMode( pulsePin, INPUT );
IIRC it shouldn't be needed, all pins are INPUT and LOW at start by default.

Has anyone checked my math?

This is getting more confusing, I originally thought it was going to be a simple project with just a few lines of code but its going way over my head.

I dont really need much accuracy, just at 60hz input I want any output thats over 100mph.

I looked at the hall sensor file but I wouldn't know how to adapt that to my project.

I appreciate your help guys and if I can get this working I will happily contribute to someones beer fund.

You won't vary the frequency of your output with analogWrite - that only changes the mark/space ratio of a fixed frequency.

Use tone().

I've built revcounters using pulseIn() to get the period of a waveform - it works fine.

// now obtain pulse width - note measure high and low
// parts to deal with asymmetry

    pulselow  = pulseIn( pulsepin, LOW);   // measure pulsewidth
    pulsehigh = pulseIn( pulsepin, HIGH);  // measure pulsewidth    
    pulselen = pulselow + pulsehigh;       // pulse duration in uS

    Frequency = 1000000/pulselen;

( added for your project...

      if (Frequency > 60) tone(toneoutput, 160);
      if (Frequency < 10) tone(toneoutput, 30);

)

The measurement is done inside the main loop () using the millis() function to run every 20mS.

see the 'Blink without delay' example in the IDE.

The blocking nature of pulseIn() doesn't affect the operation.

This isn't a difficult problem.

Allan

dexterbug:
This is getting more confusing, I originally thought it was going to be a simple project with just a few lines of code but its going way over my head.

I dont really need much accuracy, just at 60hz input I want any output thats over 100mph.

I looked at the hall sensor file but I wouldn't know how to adapt that to my project.

I appreciate your help guys and if I can get this working I will happily contribute to someones beer fund.

If you ever do write code, where every character counts, then get used to the idea of debugging, of checking and correcting.

Is 8000 pulses per mile correct? Would you like to see what really comes out?
I suggest running a test sketch that shines led13 whenever the pulse is HIGH.
You drive real slow to start and see if the led goes on and off and how far you go from one pulse to the next.

From here, I don't know if your pulse is being fed to pin 5 and..... whether or not the thing that makes the pulse has its ground connected to the Nano ground. That is debugging wiring.

// Spoiler control test sketch, free to use, by GFS 5/27/18

byte pulsePin = 5;
byte ledPin = 13;

void setup()
{
  pinMode( ledPin, OUTPUT ); 
  pinMode( pulsePin, INPUT );
}

void loop()
{
  digitalWrite( ledPin, digitalRead( pulsePin ));
}