# How to condition a VSS signal?

Hello,

First time posting to this forum. I’m working on a project to create a few digital gauges for a car. I’m using an Arduino Uno to capture the data and send it off to a python program. I’m struggling with the vehicle speed sensor (VSS). Currently I have the VSS plugged into the transmission, its an 8k ppm sensor powered by 12v the sensor generates a 5v ppm signal. I currently have it grounded to the vehicle’s chassis, the 12v lead is going to a constant 12v source under the dash and the signal wire is running to the Arduino pin 5.

The issue im having is when I start the engine and the car is in park, I get erratic readings ranging from 4-8 mph, when I start to drive the car the readings increase as expected but when I come to a stop, it still is reading erratically between 4-8 mph. I’ve tried conditioning the signal by adding a voltage divider using all sorts of resistors ranging from 100ohms up to 10k but still get the erratic readings. I’m not too seasoned when it comes to filtering signal. I’ve blown up google trying to figure this out. There are a bunch of forums on this topic but very few dealing with real cars. Something is just not clicking with me.

Could someone give me an idea on what I can try next?

This is the type of voltage divider I tried using. The signal is 5 volts instead of 12v for the signal

Here is the VSS im using

Below is my complete sketch. The speedometer portion I got from this post Matthew McMillan: Arduino - Digital speedometer

``````#include <SPI.h>
#include <Wire.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

const byte tachInterrupt = 1; // tach signal on interrupt 1 (digital pin 3)
byte engineCylinders = 8; // for tach calculation (pulses per revolution = 2 * cylinders / cycles)
byte engineCycles = 2; // for tach calculation
int refreshInterval = 500; // milliseconds between sensor updates
float speedMph = 0;
volatile int RPMpulses = 0;

static const int RXPin = 4, TXPin = 5;
static const uint32_t GPSBaud = 9600;

float declinationAngle = 0.17685997269;

//Fuel
int analogPin= 0;
int Vin= 5;
int raw = 0;
float Vout= 0;
float R1= 10;
int fuelLevel= 0;
float buffer= 0;
int currentFuelLevel = 0;

//vehicle speed sensor
const int hardwareCounterPin = 5;
const int samplePeriod = 500; //in milliseconds
const float pulsesPerMile = 8000; // this is pulses per mile for Toyota. Other cars are different.
const float convertMph = pulsesPerMile/3600;
volatile unsigned int count;
float mph;
volatile unsigned int imph;
int roundedMph;
int previousMph;
int prevCount;
volatile unsigned int currentSpeed;
volatile unsigned int filteredSpeed;
int speedo;

const long interval = 1000;
// The TinyGPS++ object
//TinyGPSPlus gps;

// The serial connection to the GPS device
//SoftwareSerial ss(RXPin, TXPin);

void setup()
{
pinMode(3, INPUT_PULLUP); // enable internal pullup for tach pin
pinMode(5, INPUT_PULLUP);
//attachInterrupt(tachInterrupt, countRPM, FALLING);
Serial.begin(9600);

//ss.begin(GPSBaud);

//compass
if (!mag.begin())
{
/* There was a problem detecting the LSM303 ... check your connections */
Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
while (1);
}

TCCR1A = 0; //Configure hardware counter
TCNT1 = 0;  // Reset hardware counter to zero
}

void loop()
{
bitSet(TCCR1B, CS12); // start counting pulses
bitSet(TCCR1B, CS11); // Clock on rising edge
delay(samplePeriod);
TCCR1B = 0; // stop counting
count = TCNT1; // Store the hardware counter in a variable
TCNT1 = 0;     // Reset hardware counter to zero
mph = (count/convertMph)*10; // Convert pulse count into mph.
imph = (unsigned int) mph; // Cast to integer. 10x allows retaining 10th of mph resolution.

int x = imph / 10;
int y = imph % 10;

// Round to whole mile per hour
if(y >= 5){
roundedMph = x + 1;
}else{
roundedMph = x;
}

//If mph is less than 1mph just show 0mph.
//Readings of 0.9mph or lower are some what erratic and can
//occasionally be triggered by electrical noise.
if(x == 0){
roundedMph = 0;
}

// Don't display mph readings that are more than 50 mph higher than the
// Accelerating 50mph in one second is rocketship fast so it is probably
// not real.
if((roundedMph - previousMph) > 50){
currentSpeed = previousMph;
}else{
currentSpeed = roundedMph;
}

previousMph = roundedMph; // Set previousMph for use in next loop.

//Serial.println(getRPM());

// Normalize to 0-360
{
}

fuelLevel = map(raw, 0, 1024, 0, 300);

{
}
else
{
currentFuelLevel = fuelLevel;
}

Serial.println(String(getRPM()) + "," + currentSpeed + "," + heading + "," + String(currentFuelLevel));

}

// counts tach pulses
void countRPM()
{
RPMpulses++;
}

// checks accumulated tach signal pulses and calculates engine speed
// returns engine speed in RPM
// Resolution: 30000 * engineCycles / refreshInterval / engineCylinders RPM (for default values = 20 RPM)
int getRPM()
{
int RPM = int(RPMpulses * (30000 / float(refreshInterval)) * engineCycles / engineCylinders / 2.0 ); // calculate RPM
RPMpulses = 0; // reset pulse count to 0
RPM = min(9999, RPM); // don't return value larger than 9999
return RPM;
}

int compass() {
sensors_event_t event;
mag.getEvent(&event);

float Pi = 3.14159;

// Calculate the angle of the vector y,x
float compassHeading = (atan2(event.magnetic.y, event.magnetic.x) * 180) / Pi;
}

int getSpeed()
{
/////////////////////////////////////////////////////////////
// This uses the hardware pulse counter on the Arduino.
// Currently it collects samples for one second.
//

}
``````

First, I'd try a "filter" capacitor across the 5K resistor. 100uf gives you an RC time constant of 1/2 second, which seems like a good starting point.

Then if you still have an "offset" you can subtract 8 (or 4 or whatever it "smooths-out" to). Then re-adjust your calculation/mapping so everything else doesn't read 8 MPH slow.

That's a fairly standard straight-line calibration technique where you adjust the zero-point by adding or subtracting, and then you adjust the slope with an amplification factor to make the maximum or mid-point accurate.

@DVDdoug, thank you for the reply! I was thinking about using a capacitor like this one

https://www.futurlec.com/Capacitors/C100U25E.shtml

Would that work? Im really sorry for not understanding, but when you say use the capacitor across the 5k resistor, how would that connect? Could you provide a diagram on how to wire it in?

I am not a software person so I couldn't figure out where the code was specifically for reading the VSS.
I can see you are using analog input for other sensors but your schematic indicates you are using digital
input for the VSS. Can you please post JUST the VSS relevant code ?
What function are you using to read it ?

@raschemmel The below code is the portion that reads and converts the digital input pin 5 to mph

``````bitSet(TCCR1B, CS12); // start counting pulses
bitSet(TCCR1B, CS11); // Clock on rising edge
delay(samplePeriod);
TCCR1B = 0; // stop counting
count = TCNT1; // Store the hardware counter in a variable
TCNT1 = 0;     // Reset hardware counter to zero
mph = (count/convertMph)*10; // Convert pulse count into mph.
imph = (unsigned int) mph; // Cast to integer. 10x allows retaining 10th of mph resolution.

int x = imph / 10;
int y = imph % 10;

// Round to whole mile per hour
if(y >= 5){
roundedMph = x + 1;
}else{
roundedMph = x;
}

//If mph is less than 1mph just show 0mph.
//Readings of 0.9mph or lower are some what erratic and can
//occasionally be triggered by electrical noise.
if(x == 0){
roundedMph = 0;
}

// Don't display mph readings that are more than 50 mph higher than the
// Accelerating 50mph in one second is rocketship fast so it is probably
// not real.
if((roundedMph - previousMph) > 50){
currentSpeed = previousMph;
}else{
currentSpeed = roundedMph;
}

previousMph = roundedMph; // Set previousMph for use in next loop.
``````

``````const byte tachInterrupt = 1; // tach signal on interrupt 1 (digital pin 3)[color=#222222][/color]
byte engineCylinders = 8; // for tach calculation (pulses per revolution = 2 * cylinders / cycles)[color=#222222][/color]
byte engineCycles = 2; // for tach calculation[color=#222222][/color]
int refreshInterval = 500; // milliseconds between sensor updates[color=#222222][/color]
float speedMph = 0;[color=#222222][/color]
volatile int RPMpulses = 0;[color=#222222][/color]
[color=#222222][/color]
static const int RXPin = 4, TXPin = 5;[color=#222222][/color]
static const uint32_t GPSBaud = 9600;[color=#222222][/color]
[color=#222222][/color]
float declinationAngle = 0.17685997269;[color=#222222][/color]
[color=#222222][/color]
//Fuel[color=#222222][/color]
int analogPin= 0;[color=#222222][/color]
int Vin= 5;[color=#222222][/color]
int raw = 0;[color=#222222][/color]
float Vout= 0;[color=#222222][/color]
float R1= 10;[color=#222222][/color]
int fuelLevel= 0;[color=#222222][/color]
float buffer= 0;[color=#222222][/color]
int currentFuelLevel = 0;[color=#222222][/color]
[color=#222222][/color]
//vehicle speed sensor[color=#222222][/color]
const int hardwareCounterPin = 5;[color=#222222][/color]
const int samplePeriod = 500; //in milliseconds[color=#222222][/color]
const float pulsesPerMile = 8000; // this is pulses per mile for Toyota. Other cars are different.[color=#222222][/color]
const float convertMph = pulsesPerMile/3600;[color=#222222][/color]
volatile unsigned int count;[color=#222222][/color]
float mph;[color=#222222][/color]
volatile unsigned int imph;[color=#222222][/color]
int roundedMph;[color=#222222][/color]
int previousMph;[color=#222222][/color]
int prevCount;[color=#222222][/color]
volatile unsigned int currentSpeed;[color=#222222][/color]
volatile unsigned int filteredSpeed;[color=#222222][/color]
int speedo;[color=#222222][/color]
[color=#222222][/color]
const long interval = 1000;[color=#222222][/color]
// The TinyGPS++ object
[color=#222222][/color]
``````

I am not very experienced with software but I can't tell where the actual sensor is in your code.
I don't see a comment saying "VSS SENSOR INPUT "
I also don't see any 'digitalRead' statements so it must be over my head.
My only question is , if it is a PPM signal like you say it is (as opposed to a PWM signal), why are you not using
pulseIn() ?
Shouldn't that be able to measure the pulse width ?
If that's a dumb question , it's ok to say so. I'm not ego-centric when it comes to learning new stuff. One of my
pet peeves is newbies posting dumb electronics questions without prefacing it with "I don't have a clue, is this
a valid question ?" They typically wait till they've tried running it before consulting instead of 'Hey, I wanna do
this, how should I go about it ?" You're way over my head with the software. I have no clue what you're doing.
but I do know what PPM is. Forgive me for asking but do you have an OSCILLOSCOPE to see what the signal
looks like so you can code accordingly ? Has it occurred to you (since you're so good with software, and
almost certainly do NOT have a scope or you would have included screenshots, ) to just put all that code you
posted on the shelf momentarily and just write a diagnostic routine to read the pulse and try to plot it ?
(if that's impossible feel free to say so)

To be honest, i really dont understand fully how the internal timer works for Arduino. From what i read, pin 5 is a part of the Timer1 monitoring, I took that code from an example that mirrored what i was trying to do. The person was using a VSS of his vehicle to measure the speed through the Arduino. He simply took the VSS raw signal and put it on pin 5.

My VSS says its a hall effect type generator. see the description in the link below:

I'm good with software but a real newb when it comes to circuitry. I tried just the pulseIn code example and I got nothing back.

If i use an Interrupt, it detects pulses as soon as i fire up the engine, so that wont work. I ordered a 100uf capacitor so i'll see if adding that helps.

Hi,
Did you get the code from

and just edit it to get the Vss code?
I see other bit and pieces in your code.

I would suggest you just write/edit the tacho code and get that going before adding anything else to your code.

This way you will make sure your problems are purely because of the Vss and its code.

Thanks.. Tom...

Hi,
Not a Fritzy picture.

Thanks... Tom...

@TomGeorge, Yes, that's the code I'm using from that link! I'm sure it would work fine if I could figure out how to make the signal less sensitive. I ordered a few capacitors that should be arriving today. I'll add one and see what happens. I'll try adding it as a low pass filter.

I've already commented out the Tach code and nothing else except for the compass is connected to the Arduino. But I have also tried a sketch with just the VSS code and same issue is happening. I've attached a diagram of my circuit currently:

In the diagram, those are 10K resistors, not 10.

Hi,
Without the sensor near any object, what is the output voltage, gnd or 5V?
What is the signal when you move a metal object or mount it to the sensor wheel.
What changes do you get if you can slowly move the wheel?

What cable and how long between sensor and controller?
Is it shielded?

I would suggest you supply 12V and gnd from the controller end of the cable, not from odd locations that are different to the controller gnd and supply.
The controller is measuring the signal with respect to its own gnd, not the gnd at the sensor end, there could be all sorts of currents running through the vehicle chassis between the sensor gnd connection and the controller gnd connection.

Thanks.. Tom...

I know the VSS sensor is good because I took the sensor wire that goes to pin 5 of the Arduino and plugged it into a working digital speedo that a friend gave me. The speed displays correctly. So here's my setup, I have my car on jack stands so that the rear wheels are off the ground, that way I can pull it into gear and the tires will spin simulating the car moving. I checked my VSS signal using a digital speedometer that was laying around. Its shows zero when the car is in park, when I put it in drive it shows 8 mph and when I rev it, it is increases as expected.

So I'm sure the issue I'm having is with my circuit set up. That's the part I don't understand. The code for the Arduino has been tested for a car via the link I posted earlier and it works. If someone could post a diagram of the correct way I should filter the VSS signal, id appreciate it. I'm a newb when it comes to circuits.

I guess my point was that if you had a scope you could see what the signal looks like when you put it in gear
when it is connected to a working digital speedo. It should read 0mph if the car is stationary but in gear.
Without the schematic of the digital speedo, I have no idea why it reads correctly. My only question is :
"Once the car is actually moving >10mph, does it read correctly with your arduino circuit or is there some
error all the time. ?"

So I did another test where I disconnected the pin 5 wire from the sensor, I then started the car and I got the same erratic reading from 4-8 mph and this is without the VSS signal connected to pin 5 :o . Pin 5 only has the disconnected wire plugged into it. If I removed the wire from pin 5 the reading goes to 0 mph. What the heck is going on? The wire in pin 5 is acting like an antenna...

Any ideas?

Hi,
What cable and how long between sensor and controller?
Is it shielded?

I would suggest you supply 12V and gnd from the controller end of the cable, not from odd locations that are different to the controller gnd and supply.
The controller is measuring the signal with respect to its own gnd, not the gnd at the sensor end, there could be all sorts of currents running through the vehicle chassis between the sensor gnd connection and the controller gnd connection.

Thanks.. Tom

The sensor is not a factor right now because its completely disconnected from the Arduino. There is just a wire plugged into pin 5 and its getting readings from like 2-7 mph. The wire is not connected to anything. If i remove the wire from pin 5 the readings show 0. I tried grounding the Arduino to the chassis of the car but no change. Ugh.

``````    bitSet(TCCR1B, CS12); // start counting pulses
bitSet(TCCR1B, CS11); // Clock on rising edge
``````

FYI, that is counting on a falling edge. If you want to count on rising edge, do this instead

``````TCCR1B = 1<<CS12 | 1<<CS11 | 1<<CS10
``````

You want to set TCCR1B in a single statement as doing the following

``````bitSet(TCCR1B, CS12)
``````

Would start the timer at 62500 Hz immediately

Just replace these two statements

``````    bitSet(TCCR1B, CS12); // start counting pulses
bitSet(TCCR1B, CS11); // Clock on rising edge
``````

with

``````TCCR1B = 1<<CS12 | 1<<CS11 | 1<<CS10
``````

@hzrnbgy
Is it more accurate to capture the pulses on the rise as opposed to when they are falling? What is the advantage to change that portion of the code?

So I did another test where I disconnected the pin 5 wire from the sensor, I then started the car and I got the same erratic reading from 4-8 mph and this is without the VSS signal connected to pin 5 . Pin 5 only has the disconnected wire plugged into it. If I removed the wire from pin 5 the reading goes to 0 mph. What the heck is going on? The wire in pin 5 is acting like an antenna...

Any ideas?

Yes.
When you connected pin-5 and your voltage divider you changed the impedance of the VSS signal. (dampened it)
Try using an op amp voltage follower buffer. If has a 10 Mohm input impedance and a low impedance
output that can drive the voltage divider. With the buffer inserted between the VSS and the voltage
divider it should not be affected and should read 0 mph when the wheels are not turning.