Manipulating RPM signals using arduino

Hey everyone

I have converted my vehicle from gas to electricity, and am working on getting the electronic gauge cluster functioning again.
The car speedo interprets square waves, 0-12v for the MPH and 0-5v for the RPM signal.
Using a small signal generator, I was able to discover that the MPH is interpreted roughly by the function Mph = ((hz - 46.8) / 43.2) .
The electric car has no transmission, so the speed will be linear.

I need the arduino to

  1. Interpret an incoming RPM signal from the electric motor
  2. Create TWO new square waves

One signal will be the incoming RPM signal manipulated the function above to display MPH.
The other signal will be the incoming RPM signal from the electric motors, but the arduino will be required to recognize if the RPM signal is less that 100 RPM, and if so create a 500 RPM signal to ‘trick’ the ECU into thinking the car is on, and thus providing power steering.

So here is where I need help:

How would I create code to discern the electric motor’s RPM signal’s frequency?
Second, how would I create a new signal ? I was planning on just using the ‘tone’ function, however I would need to create two tones and the arduino is only capable of running one (as far as I know).

Thanks for the help !

thinmint: The electric car has no transmission, so the speed will be linear.

Therefore the RPM of the motor will be the RPM of the wheels. MPH can be calculated from the wheel circumference (Pi * diameter) and the RPM. For every revolution of your wheels, you know how far you've travelled (one circumference) and you know the RPM of the wheels, so MPH is a simple maths problem. Circ. * RPM *60 =distance per hour. Distance will need to be turned into miles by division. Inches/(12 * 3 * 1760) = miles.

Henry_Best:

thinmint:
The electric car has no transmission, so the speed will be linear.

Therefore the RPM of the motor will be the RPM of the wheels.
MPH can be calculated from the wheel circumference (Pi * diameter) and the RPM.
For every revolution of your wheels, you know how far you’ve travelled (one circumference) and you know the RPM of the wheels, so MPH is a simple maths problem.
Circ. * RPM *60 =distance per hour. Distance will need to be turned into miles by division.
Inches/(12 * 3 * 1760) = miles.

Thanks!
I have actually already figured that aspect of the program out, I am just stuck on how to count the frequency and how to output two waves simultaneously.

thinmint:

Henry_Best:

thinmint: The electric car has no transmission, so the speed will be linear.

Therefore the RPM of the motor will be the RPM of the wheels. MPH can be calculated from the wheel circumference (Pi * diameter) and the RPM. For every revolution of your wheels, you know how far you've travelled (one circumference) and you know the RPM of the wheels, so MPH is a simple maths problem. Circ. * RPM *60 =distance per hour. Distance will need to be turned into miles by division. Inches/(12 * 3 * 1760) = miles.

Thanks! I have actually already figured that aspect of the program out, I am just stuck on how to count the frequency

Have you considered a magnet on the motor shaft or wheel hub and a hall effect switch to count the revs? That will give you a square wave signal.

and how to output two waves simultaneously.

The Arduino can produce two independent PWM signals. You'll need a transistor to control the 12v signal.

Do you already have the input signal, and you're just trying to figure out how to determine the frequency? Or are you still trying to figure out how to get the signal to the Arduino?

I believe the pulseIn() function might be what you're looking for to determine frequency. It returns the length of the pulse and you can calculate the frequency from that.

The Arduino has 3 independent timers, any of which can be used to generate independent PWM signals. However, Timer0 is used for the system timing functions so if you need those you're left with timers 1 and 2.

If the 500 rpm signal is only needed to trick the ECU into believing the engine is running then I don't see any need for it to be variable speed - it could just be a fixed frequency square wave. The frequency is quite low and could easily be achieved in software using the approach demonstrated in 'blink without delay'. I would also use the same approach to generate the modified speedometer signal - have a global variable storing the current output interval, and toggle the output at that interval. Separately, read the input signal either by counting interrupts in a period (works better at higher frequencies) or by polling the input state and measuring the interval between state changes (works better at low frequencies), and update the global variable periodically.

I wouldn't use pulseIn(), just because it's a blocking function and that would require you to use hardware timers to generate the output signals - that's another layer of complexity that IMO you don't need.

PeterH:
If the 500 rpm signal is only needed to trick the ECU into believing the engine is running then I don’t see any need for it to be variable speed - it could just be a fixed frequency square wave. The frequency is quite low and could easily be achieved in software using the approach demonstrated in ‘blink without delay’. I would also use the same approach to generate the modified speedometer signal - have a global variable storing the current output interval, and toggle the output at that interval. Separately, read the input signal either by counting interrupts in a period (works better at higher frequencies) or by polling the input state and measuring the interval between state changes (works better at low frequencies), and update the global variable periodically.

I wouldn’t use pulseIn(), just because it’s a blocking function and that would require you to use hardware timers to generate the output signals - that’s another layer of complexity that IMO you don’t need.

I want the gauge cluster to display the electric motors’ RPM, but I need power steering when I am not moving (Ie pulling out of the garage). Power steering only turns on when it senses an RPM signal ~ 500 RPM, and because my motors don’t idle I need to create a fake signal.

I was thinking something along the lines of this, but haven’t been able to get it to work.

void measure() {                        //measures the period of the signal in microseconds

  if(digitalRead(31) == HIGH) {            
    startTime = micros();    
    pulseLow = startTime - stopTime;
  }
  if(digitalRead(31) == LOW) {
    stopTime = micros();
    pulseHigh = stopTime - startTime;
  }
  period = pulseLow + pulseHigh;

}

Another choice I have is to use the ‘freq measure library’ seen here: http://www.pjrc.com/teensy/td_libs_FreqMeasure.html

I have tried this and it works, however I still have the issue of creating TWO seperate waves simultaneously, because only 1 tone() function runs per code.

thinmint: I still have the issue of creating TWO seperate waves simultaneously, because only 1 tone() function runs per code.

No, tone() won't do it because it is a blocking function and can only output one signal at a time.

Your options are (1) use software to output both signals using the non-blocking approach demonstrated in 'blink without delay' - this is my recommendation, (2) set up timer interrupts to trigger your code at the required intervals and write interrupt handlers that switch the outputs to generate your output signals, (3) set up timers to generate the signals directly.

There are tone libraries that do all the hardware setup for you. I have had good luck with ToneAC. Probably not exactly what you want because it toggles two pins so you get twice the voltage diff (it was designed for audio and emulates AC in that way), but you could just wire it up with one pin and ground and ignore the other pin.