mimicking a speed signal output from arduino

Naturally aspirated tech and talk
User avatar
notny41
Posts: 210
Joined: Tue Apr 12, 2022 9:15 am
Has thanked: 29 times
Been thanked: 36 times
Hi Tom, I know you created an arduino box for testing and demonstration of your awesome speedobooster
https://carpokes.com/viewtopic.php?f=4&t=68

Testing drive box specifically at:
https://youtu.be/7r7GCt7R_-8?t=191

We talked in someone else's post about how your arduino in that box generates the ground pulses for the speedometer in the cluster. I didn't want to keep hijacking that thread so I figured I'd start a new one because I am still a little puzzled on how this is achieved. Would you mind elaborating a bit on how you do that and maybe post some arduino code?

The main reason I'd like to build this is to use it to test some cruise control boxes that I have without putting them in a car and taking them for a spin.

On the cruise contol box, I see the ground that goes to the cruise control box is on pin 8 of connector 1, the 12+ is pin 4 of connector 1, and the speedo signal goes to pin 1 on connector 1. So how would I integrate an arduino between those pins to mimmic the ground pulses of a simulated speed signal?

I want to give credit to dme from a different forum for posting these pinouts as they are very helpful to know:

Connector 1 (input) uses all 8 pins.
pin 1 speedometer signal
pin 2 brake signal - normally 0 volts until you press the brake (12v)
pin 3 'Cancel' from the stalk - normally high (12v) unless you press the cancel switch (0v)
pin 4 constant 12 volts
pin 5 'Reset/Resume' from the stalk - normally 0v unless you press Resume then goes high (12v)
pin 6 'Set' from the stalk - normally 0v unless you press Set (12v)
pin 7 Clutch signal - closed to ground until clutch is pressed and then it is open
pin 8 Ground


Connector 2 (output) uses only 7 pins
Pin 1 - Servo 'clutch'
Pin 2 - Servo 'clutch'
Pin 3 - Not used
Pin 4 - Servo Potentiometer
Pin 5 - Servo motor +
Pin 6 - Servo motor -
Pin 7 - Servo Potentiometer
Pin 8 - Ground

The servo connector is round and has 7 pins. Look close, they are numbered. Here is the relationship between the controller connector and the servo connector.
Controller Pin to Servo Pin
1 to 5
2 to 6
3
4 to 2
5 to 7
6 to 1
7 to 4
8 to 3


#1

User avatar
Tom
Site Admin
Posts: 5301
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 498 times
Been thanked: 2337 times
Contact:
I'll start by tagging @dme, who is among us here in Carpokes Nation, in case he wants to pitch in on any of this.

Next, some light reading I posted on RL a long time ago that explains the speedometer signal in detail.

The speedometer is driven by an electronic sensor in the transmission, which generates eight ground pulses for every one full rotation of the tire. When then sensor isn’t creating a ground pulse, the signal from the sensor is open (i.e., not connected to anything). For example, if the tire is rotating once every 16 seconds, the sensor signal is grounded for one second, then open for one second, then grounded for one second, and so on. The faster the pulses, the faster the speedometer reads. A stock 225/50/16 tire is about 83.66 inches in circumference and one mile is 63,360 inches. That means the tire rotates 63,360/83.66 times per mile, or about 757 times per mile. At 60 mph, therefore, the tire is turning 757 times per minute, or a little more than twelve and a half times per second. Since the speedometer sensor creates eight ground pulses per rotation, there are just over 100 ground pulses per second at 60 mph. Remember that there are also 100 non-grounded periods per second as well, meaning each ground pulse is equal to about 1/200th of a second.

The Arduino keeps track of time in milliseconds or microseconds. A millisecond is 1/1000th of a second and a microsecond is 1/1,000,000th of a second. At 1/200th of a second, each ground pulse at 60 mph lasts .005 seconds or 5 milliseconds or 5000 microseconds (all ways of expressing 1/200th of a second), followed by the same amount of time not grounded. The speedometer calibrator works by measuring the amount of time between ground pulses and then creating a replacement signal with a slightly faster or slower pulse as needed. Let’s say the speedometer reads 70mph when the car is really only moving 60mph. In this case, the Arduino would measure 10,000 microseconds between ground pulses from the sensor, since the car is actually going 60mph. The Arduino then creates its own (slightly slower) pulse train as needed to make the speedometer read 60 mph. The correction factor can be built in to the firmware or can be calculated based on where the trim-pot is set.



More to follow....


#2

User avatar
Tom
Site Admin
Posts: 5301
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 498 times
Been thanked: 2337 times
Contact:
Next, here is a summary of how I made the very first speedometer calibrator, based on an Arduino Nano. The key breakthrough was adding the 74C14 "inverting Schmitt trigger" in the circuit, which filters out the electrical noise on the speedometer sensor calibrator. Without it, the Arduino interrupt pins are so fast that they interpret the noise as super fast ground pulses. With it, the Arduino picks up only the real pulses and gets a perfect reading. R2, R3, and R4 are the trim pot input signal, which the arduino reads to decide how much to speed up or slow down the modified speedometer output signal.

In order to install this circuit in the car, the factory harness wire carrying the speedometer sensor signal must be cut and routed into Pin 1 of the calibrator. Pin 2 of the calibrator then feeds the speedometer with the new pulse created by the Arduino. The sensor wire is the blue wire with red stripe in the middle edge connector on the back of the gauge cluster. Pull the gauge cluster out to gain access to the edge connector. Cut the blue/red wire on pin 14 of the middle edge connector and connect the sensor side of the cut wire to Pin 1 on the calibrator, and connect the speedometer side of the blue/red wire to Pin 2 on the calibrator.

speedocalibrator circuit.jpg
speedocalibrator circuit.jpg (286.72 KiB) Viewed 803 times
speedocalibrator part list.jpg
speedocalibrator part list.jpg (416.23 KiB) Viewed 803 times
speedocalibrator wiring.jpg
speedocalibrator wiring.jpg (380.9 KiB) Viewed 803 times



And finally, here is the Arduino code I used to drive the hardware. It won't win any coding awards, and has remnants from pre-Schmitt-trigger filtering efforts, but it works and demonstrates the basic concept. It's difficult without additional hardware to untether output pins to simulate the un-connected state of the speedometer sensor, but as shown in the code below I found that the speedometer works just find toggling between ground and 5v (rather than ground and no connection). Whether the same is true for the cruise control computer, I do not know!

Code: Select all

//1986 Porsche 944 Turbo Speedometer Calibrator

//Subject to Carpokes.com Terms of Service and Licensing Terms

//raw 944 transmission sensor signal must be processed by external Schmitt trigger

//Use LM2940-10 with decoupling caps per datasheet to power Arduino in automotive setting

//Arduino Pin 7 supplies modified signal for speedometer

 

const int debounce = 2500;

const int speedometerPin = 7;                    

const int sensorPin = 3;                                     

int pulseState = LOW;                                        

volatile unsigned long currentMicros = 0; 

volatile unsigned long previousMicros= 0;  

volatile unsigned long currentSpeed = 0;  

volatile unsigned long previousSpeed = 0;

volatile unsigned long interval = 0;                 

unsigned long modInterval = 0;                

float calFactor = .91;   // decrease to slow down speedometer                           

                                     // calFactor of 1 makes no change to speedometer


 

void setup()

{

pinMode (13, OUTPUT);                        

pinMode(speedometerPin, OUTPUT);    

pinMode(sensorPin, INPUT);                 

digitalWrite (sensorPin, HIGH);             

attachInterrupt (1, iSr, FALLING);        

}

void loop()

{

  noInterrupts();                                                 

  modInterval=interval;                                    

  interrupts();                                                      

  currentMicros = micros();                             

  if (currentMicros-previousSpeed<1000000) 

  {

   if (currentMicros - previousMicros>((modInterval/2)/calFactor))          

       { previousMicros = currentMicros;                                                    

        if (pulseState == LOW) pulseState = HIGH; else pulseState = LOW;

        digitalWrite(13, pulseState);         //to blink onboard LED                                                         

        digitalWrite(speedometerPin, pulseState);

        }                                  

   }

}

 

void iSr()

{

  currentSpeed=micros();                   

  if (digitalRead(sensorPin)==LOW) 

     {

        if ((currentSpeed - previousSpeed) > debounce)  

           {

            interval = currentSpeed - previousSpeed;        

            previousSpeed=currentSpeed;                         

           }

      }

}

More to follow....


#3

User avatar
Tom
Site Admin
Posts: 5301
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 498 times
Been thanked: 2337 times
Contact:
And finally....what you actually asked about. :)

As best I can tell, here is the code I used to drive the Speedometer in my simulator box. I don't have a schematic for it since I did it on the fly, but looking at this code, it seems clear that I connected a potentiometer (0-10k most likely) to 5v and ground, and sent the output (a voltage adjustable via the knob) to pin A0 on the arduino. The analogRead return 0 to 1023 depending on the voltage read, so the 1,640,000 number approximates the speedometers pulse rate in microseconds at 180+ mph, and as the A0 reading is changed by turning the pot/knob, the resulting pulseRate declines proportionately. If you study the Arduino example "BlinkWithoutDelay" you will see that I just copied that approach, but used microseconds and created an adjustable interval via the potentiometer/knob.

Not sure if any of that makes sense, so happy to help if I can....

Code: Select all

const int pulsePin = 12;         // Signal to speedometer on Pin 12
int pulseState = LOW;           // State of signal pulse
unsigned long previousMicros = 0;        // Used to time the pulses
unsigned long currentMicros = 0;         // Used to time the pulses
unsigned long pulseRate =500000;           // The signal rate -- bigger numbers are slower speeds


void setup() 
{
//Serial.begin(9600);
pinMode(pulsePin, OUTPUT);      
}


void loop()
{
if (currentMicros - previousMicros > 3000) {pulseRate =  analogRead(A0); pulseRate = 1640000/(pulseRate);}

currentMicros = micros();  

if(currentMicros - previousMicros > pulseRate) 
  {
    previousMicros = currentMicros;   
    if (pulseState == LOW) pulseState = HIGH;
    else {pulseState = LOW; pulseRate =  analogRead(A0); pulseRate = 1640000/(pulseRate);}
    digitalWrite(pulsePin, pulseState);
    digitalWrite(13,pulseState);
    
   
  }
}


#4

User avatar
notny41
Posts: 210
Joined: Tue Apr 12, 2022 9:15 am
Has thanked: 29 times
Been thanked: 36 times
This is awesome! Thanks Tom. I don't have a spare speedo, but I might be able to at least display the speed on a lcd display I just got for my arduino. :)


#5

modularfox
Posts: 3
Joined: Sun Mar 17, 2024 12:09 pm
Has thanked: 3 times
Hi, new to the forum, I have a question about the code:

Code: Select all


const int pulsePin = 12;              // Signal to speedometer on Pin 12
int pulseState = LOW;                 // State of signal pulse
unsigned long previousMicros = 0;     // Used to time the pulses
unsigned long currentMicros = 0;      // Used to time the pulses
unsigned long pulseRate = 500000;     // The signal rate -- bigger numbers are slower speeds


void setup()
{
  //Serial.begin(9600);
  pinMode(pulsePin, OUTPUT);
}


void loop()
{
  if (currentMicros - previousMicros > 3000) {
    pulseRate =  analogRead(A0);
    pulseRate = 1640000 / (pulseRate);
  }

  currentMicros = micros();

  if (currentMicros - previousMicros > pulseRate)
  {
    previousMicros = currentMicros;
    if (pulseState == LOW) pulseState = HIGH;
    else {
      pulseState = LOW;
      pulseRate =  analogRead(A0);
      pulseRate = 1640000 / (pulseRate);
    }
    digitalWrite(pulsePin, pulseState);
    digitalWrite(13, pulseState);


  }
}

From my research, the GM speedometer is a 4000 pulse per mile signal

I am wanting to make an Arduino operate a factory GM speedometer for my project using the MPH values from canbus data. I've made a few sketches and have made the arduino nano control x27 stepper motors that operate as intended and have functioning tach, coolant temp, oil pressure all from the canbus.. but I want to combine this project to operate the factory speedometer and get rid of a separate canbus module that does that job (Dakota Digital STA-1000 module)

heres a link to one of my videos showing the canbus setup reading oil pressure and turning on a LED when its below a setpoint
http://87chevy.com/video/canbus/can_oil_psi_display.mp4
any help on how to accomplish this would be greatly appreciated!
clint


#6

User avatar
Tom
Site Admin
Posts: 5301
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 498 times
Been thanked: 2337 times
Contact:
modularfox wrote: Sun Mar 17, 2024 12:58 pm Hi, new to the forum, I have a question about the code:

Code: Select all


const int pulsePin = 12;              // Signal to speedometer on Pin 12
int pulseState = LOW;                 // State of signal pulse
unsigned long previousMicros = 0;     // Used to time the pulses
unsigned long currentMicros = 0;      // Used to time the pulses
unsigned long pulseRate = 500000;     // The signal rate -- bigger numbers are slower speeds


void setup()
{
  //Serial.begin(9600);
  pinMode(pulsePin, OUTPUT);
}


void loop()
{
  if (currentMicros - previousMicros > 3000) {
    pulseRate =  analogRead(A0);
    pulseRate = 1640000 / (pulseRate);
  }

  currentMicros = micros();

  if (currentMicros - previousMicros > pulseRate)
  {
    previousMicros = currentMicros;
    if (pulseState == LOW) pulseState = HIGH;
    else {
      pulseState = LOW;
      pulseRate =  analogRead(A0);
      pulseRate = 1640000 / (pulseRate);
    }
    digitalWrite(pulsePin, pulseState);
    digitalWrite(13, pulseState);


  }
}

From my research, the GM speedometer is a 4000 pulse per mile signal

I am wanting to make an Arduino operate a factory GM speedometer for my project using the MPH values from canbus data. I've made a few sketches and have made the arduino nano control x27 stepper motors that operate as intended and have functioning tach, coolant temp, oil pressure all from the canbus.. but I want to combine this project to operate the factory speedometer and get rid of a separate canbus module that does that job (Dakota Digital STA-1000 module)

heres a link to one of my videos showing the canbus setup reading oil pressure and turning on a LED when its below a setpoint
http://87chevy.com/video/canbus/can_oil_psi_display.mp4
any help on how to accomplish this would be greatly appreciated!
clint
At a very high level, you need to do three things to get this working:

1. Get the speedometer data out of CANBUS and into your Arduino. The code above reads the raw data from the sensor, but in your case you will need the Arduino to communicate with the CANBUS and extract some form of speed data and convert that into a variable -- if I understand your goal correctly. Is it safe to assume you already have this part sorted out? In other words, if you wanted could you have the Arduino read the speed from the CANBUS and display the MPH on an LCD hooked up to the speedometer? If so, check the box in step 1. :)

2. My code above then manipulates the input as need to 'calibrate' the speedometer. Would it be safe to assume this is not needed in your case, and that any/all calibrations would occur in the ECU generating the CANBUS signals? Much of the 'complexity' of my code is to calibrate the speedometer. Assuming you don't have to do that, my code may not be the best starting point -- yours can by much simpler.

3. The last step -- and I think the key for you -- is getting the Arduino to generate the signal needed to make the speedometer show a particular MPH. Here you need to know what kind of signal the speedometer is expecting to see. My guess is your speedometer runs off a square (on/off) pulse similar to the Porsche speedometer in my code above. If so, and assuming the speedometer has a high-impedance input that won't fry an Arduino output pin, then it's pretty simply. (I'd still use a voltage follower for good order's sake.) If 4000 pulses is one mile, then you just need the formula for translating that in to a time interval between pulses at any given MPH. Check my math (I'm spit-balling here), but seems like your formula for the interval is 1/(1.11*MPH), so for example at 60 mph, you would have one pulse every .015 seconds (aka 15 milliseconds in Arduino-speak). I got that formula because 4000 pulses per mile translates to 66.667 pulses per minute at 1 mph, and 1.111 pulses per second at 1 mph. Then just multiply that by the actual MPH to get pulses per second at any given MPH, and invert all that to get seconds per pulse. With that, you can take the MPH date from CANBUS (per step 1 above) and use it to calculate a pulse rate for the speedometer. You could use fancy frequency outputs or timing interrupts, but if this is all the Arduino is doing, it has more than enough processing power to just create the pulses in a loop like the code above. The pseudo code is something like:

LOOP START
GET START TIME
GET MPH FROM CANBUS
CALCULATE PULSE RATE IN MILLISECONDS FOR THAT MPH
WAIT UNTIL CURRENT TIME MINUS THE START TIME = PULSE RATE
SEND A PULSE TO THE SPEEDOMETER
GO TO LOOP START

Does any of that make sense and/or help?

If I were doing this, I'd start by just trying to create a pulse output in the Arduino that operates the speedometer. You can start with the Blink Sketch and adjust the delay to confirm you have the pulse rates correct for any given mph. Once you can do that, the rest should be easy assuming you can read the CANBUS signal into the Arduino (per step 1 above).


#7

dr bob
Moderator
Posts: 207
Joined: Thu Jul 08, 2021 9:30 pm
Location: Central Oregon
Has thanked: 63 times
Been thanked: 70 times
At the risk of collapsing the spinnaker, having it fall and drag under the keel, and fouling the rudder/steering, ...

There are really cheap 555-based pulse generators on amazon for under $10. Output to a transistor like 2n2222 to pull the test circuit to ground, and you have your speed pulse simulator with adjustable frequency and duty cycle. Fancy stuff is great, but since there's no CANBUS interface needed a simple-as-possible pulse generator might be all that's needed. You can buy fancy dedicated function generators with knobs and buttons and digital readout for about $30.


dr bob

1989 928 S4, black with cashmere/black inside
SoCal 928 Group Cofounder
928 Owner's Club Charter Member
Bend Yacht Club Commodore Emeritus

Free Advice and Commentary. Use At Your Own Risk!

#8

User avatar
Tom
Site Admin
Posts: 5301
Joined: Fri Jun 25, 2021 2:04 pm
Location: Silicon Valley, CA
Has thanked: 498 times
Been thanked: 2337 times
Contact:
dr bob wrote: Sun Mar 17, 2024 8:09 pm At the risk of collapsing the spinnaker, having it fall and drag under the keel, and fouling the rudder/steering, ...

There are really cheap 555-based pulse generators on amazon for under $10. Output to a transistor like 2n2222 to pull the test circuit to ground, and you have your speed pulse simulator with adjustable frequency and duty cycle. Fancy stuff is great, but since there's no CANBUS interface needed a simple-as-possible pulse generator might be all that's needed. You can buy fancy dedicated function generators with knobs and buttons and digital readout for about $30.
All very true. Seems like processing power and high level programming has replaced engineering elegance these days. Of course, in my case, it's just that I lack the engineering skills. ;) Oh, and harking back to our conversation about the $4 freeze over sensor, there's this:
IMG_0477.jpeg
IMG_0477.jpeg (39.17 KiB) Viewed 228 times


#9

User avatar
j1nx3d
Posts: 46
Joined: Tue Jul 06, 2021 6:07 pm
Location: New Zealand
Has thanked: 76 times
Been thanked: 20 times
Just curious... is there a way to adapt this to give a signal from a 968 6-spd to a 1986 944 speedometer? I have a magnetic pick up from LR on one of the rear axles and it's not very accurate or reliable.
https://www.lindseyracing.com/LR/Porsch ... PEEDO.html


CGM '86 944S3 conversion
(968 3.0L, 6 -spd LSD)

#10

Post Reply