Driving an Air Core Speedometer

There are some posts from more than two years ago on this subject, but I’d like to share my experience driving an MX5 air core speedometer using a UNO and an SN754410 H Bridge driver. The attached commented code is self explanatory. I’m using a potentiometer as a potential divider into A1. You don’t need the value of pi, just scale the 1024 bits of the analogRead value to 2 x pi by dividing by 163. In my case, the speedometer only uses three quadrants so I divide by 220 instead to get three quadrants from potentiometer full scale.

Next step, to sniff the speed from a sensor on the propshaft!

Hope someone finds this useful.

Speedo code.txt (2.17 KB)

Just realised, I tried to attach the code as an attachment, but now realise there is a better way!

double cosine = 0;  // the value to drive the enable pin for the cosine coil
double sine = 0;    // the value to drive the enable pin for the sine coil
float pot = 0;  // Using a pot to adjust the speed. Needs to be a float variable for angle maths

int sine_plus = 6;
int sine_minus = 10;
int cosine_plus = 4;
int cosine_minus = 2;

// the enable pins for the two coils, driven with PWM signal proportional to sine and cosine respectively
int sine_drive = 5;
int cosine_drive = 3;

double lastmillis = 0;  // Used to check the cycle time
double thismillis = 0;

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);

  pinMode(cosine_drive, OUTPUT); // Enable Cosine
  pinMode(sine_drive, OUTPUT); // Enable Sine

  pinMode(cosine_minus, OUTPUT);
  pinMode(cosine_plus, OUTPUT);
  pinMode(sine_plus, OUTPUT);
  pinMode(sine_minus, OUTPUT);
}

void loop() {

  delay(50);  // small delay each cycle to simulate propshaft sensor routine

  pot = analogRead(A1);       // centre tap of potentiometer into A1
  sine = 255 * sin(pot / 220); // for four quadrants the divisor would be 163 instead of 220
  cosine = 255 * cos(pot / 220); // but my meter only uses three quadrants up to 150mph so scaled accordingly

  // Just to see what's going on
  Serial.print(pot);
  Serial.print("\t");
  Serial.print(sine);
  Serial.print("\t");
  Serial.print(cosine);
  Serial.print("\t");
  thismillis = millis();
  Serial.println(thismillis - lastmillis);
  lastmillis = thismillis;

  if (sine >= 0) {
    digitalWrite(sine_minus, LOW); // 1
    digitalWrite(sine_plus, HIGH);
    analogWrite(sine_drive, sine);
  }
  else {
    // reverse polarity
    digitalWrite(sine_plus, LOW); // 1
    digitalWrite(sine_minus, HIGH);
    analogWrite(sine_drive, -sine);
  }

  if (cosine >= 0) {
    digitalWrite(cosine_minus, LOW); // 1
    digitalWrite(cosine_plus, HIGH);
    analogWrite(cosine_drive, cosine);
  }
  else {
    // reverse polarity
    digitalWrite(cosine_plus, LOW); // 1
    digitalWrite(cosine_minus, HIGH);
    analogWrite(cosine_drive, -cosine);
  }
}

Driving a Air Core Aviation Heading Gauge

Hi,
based on a older solution from https://forum.arduino.cc/index.php/topic,22480.0.html i made my own version for a Collins HDG gauge. It is connected just with 2 resistors. No other hardware is required.
Hope it might be useful for someone.

/* Arduino controls AIRCORE Gauge. E.Staebler 0621
 * based on:
 * https://forum.arduino.cc/index.php/topic,22480.0.html
 * https://www.youtube.com/watch?v=ut9GZJTI3iA
 *
 * In this version no floating sine calculation is used.
 * A 90 degrees lookuptable in byte-resolution directly to feed the 8Bit PWM/DAC is used instead.
 *
 * Define the pins the meter is connected to. We need 1 PWM to vary the voltage in
 * each coil, and one more to reverse the polarity in that coil. So a total of 4 pins.
 */

#include <avr/pgmspace.h>
                                     ___
#define SinDirPin    7         // --|___|-- 560R to Sub-D-5 this controls the polarity to the "sine" coil
                                     ___
#define CosDirPin    8         // --|___|-- 560R to Sub-D-1 this controls the polarity to the "cosine" coil

#define SinPin       9         // to Sub-D 2 this controls the voltage to the "sine" coil (PWM)
#define CosPin       10        // to Sub-D-4 this controls the voltage to the "cosine" coil (PWM)

                                                // if scale is 180° shifted, wire:  Arduino  7 to Sub-D 2
                                                                                    Arduino  8 to Sub-D 4
                                                                                    Arduino  9 to Sub-D 5
                                                                                    Arduino 10 to Sub-D 1                                    

int delayTime = 50;                             // milliseconds between each angular step.

                                                // Sinustabelle 1.Quadrant 90 Werte 0-89° in 8 Bit Auflösung
const PROGMEM uint8_t Sine_Lookup[90] =         // DAC/PWM Lookuptable 0-89 degrees Sine in 8 bit resolution
{ 
   0,  4,  9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66,
  70, 75, 79, 83, 87, 91, 96,100,104,108,112,116,120,124,127,131,
 135,139,143,146,150,153,157,160,164,167,171,174,177,180,183,186,
 190,192,195,198,201,204,206,209,211,214,216,219,221,223,225,227,
 229,231,233,235,236,238,240,241,243,244,245,246,247,248,249,250,
 251,252,253,253,254,254,254,255,255,255
};
   
void setup(){
 Serial.begin(115200);              // for debugging or remote-setting
 pinMode(SinPin,       OUTPUT);     // Set the pins to OUTPUT
 pinMode(CosPin,       OUTPUT);
 pinMode(SinDirPin,    OUTPUT);
 pinMode(CosDirPin,    OUTPUT); 
 digitalWrite(SinDirPin, HIGH);     // Set the initial direction. (forward).
 digitalWrite(CosDirPin, HIGH);     // Of course it could be "reverse" depending on which lead you connected :-).

 // Vary the PWM-Frequency if noise is annoying   (Pin D9+D10)
 // TCCR1B = TCCR1B & B11111000 | B00000001;    // set timer 1 divisor to 1 for PWM frequency of 31372.55 Hz
 TCCR1B = TCCR1B & B11111000 | B00000010;     // for PWM frequency of 3921.16 Hz
 // TCCR1B = TCCR1B & B11111000 | B00000011;    // for PWM frequency of 490.20 Hz (The DEFAULT)
 // TCCR1B = TCCR1B & B11111000 | B00000100;    // for PWM frequency of 122.55 Hz
 // TCCR1B = TCCR1B & B11111000 | B00000101;    // for PWM frequency of 30.64 Hz
}

void loop() {                                   // Run over and over again
 for(int y = 0; y < 360; y++){                  // Rotate 0 through 360 degrees (in degrees!)
   setMeterPosition(y);
   delay(delayTime);                            // waits for delayTime milliseconds    
 }
} 
                                        
void setMeterPosition(int pos){                 // setMeterPosition() - put it at the angle in radians
 int  sinCoilValue; 
 int  cosCoilValue; 
 
 /* PolarityPin and table-read-direction
 *             Sin        Cos
 *   0 -  89   + ->       + <-
 *  90 - 179   + <-       - ->
 * 180 - 269   - ->       - <-
 * 270 - 359   - <-       + ->
 */
 
 while (pos>359) pos-=360;                                  // while pos>359 subtract 360. just in case ...

 if (pos>=270) {                                            // 4. Quadrant 270-359
   digitalWrite(SinDirPin, HIGH);                           // reverse. SinDirPin
   digitalWrite(CosDirPin, LOW);                            // neg. CosDirPin 
   sinCoilValue=255-pgm_read_byte(&(Sine_Lookup[359-pos])); // reverse SinPin, table-read-direction backwards
   cosCoilValue=pgm_read_byte(&(Sine_Lookup[pos-270]));     // non-reverse CosPin, table-read-direction forewards    
 }
 else if (pos>=180) {                                       // 3. Quadrant 180-269
   digitalWrite(SinDirPin, HIGH);                           // reverse SinDirPin
   digitalWrite(CosDirPin, HIGH);                           // reverse CosDirPin 
   sinCoilValue=255-pgm_read_byte(&(Sine_Lookup[pos-180])); // reverse SinPin, table-read-direction forewards
   cosCoilValue=255-pgm_read_byte(&(Sine_Lookup[269-pos])); // reverse CosPin, table-read-direction backwards    
 }
 else if (pos>=90) {                                        // 2. Quadrant 90-179
   digitalWrite(SinDirPin, LOW);                            // neg. SinDirPin
   digitalWrite(CosDirPin, HIGH);                           // reverse CosDirPin 
   sinCoilValue=pgm_read_byte(&(Sine_Lookup[179-pos]));     // non-reverse SinPin, table-read-direction backwards
   cosCoilValue=255-pgm_read_byte(&(Sine_Lookup[pos-90]));  // reverse CosPin, table-read-direction forewards    
 }
 else {                                                     // 1. Quadrant 0-89
   digitalWrite(SinDirPin, LOW);                            // neg. SinDirPin
   digitalWrite(CosDirPin, LOW);                            // neg. CosDirPin 
   sinCoilValue=pgm_read_byte(&(Sine_Lookup[pos]));         // non-reverse SinPin, table-read-direction forewards
   cosCoilValue=pgm_read_byte(&(Sine_Lookup[89-pos]));      // non-reverse CosPin, table-read-direction backwards    
 }

/*
 Serial.print(pos); 
 Serial.print(":  sinCoilValue: ");                         // Debug
 Serial.print(sinCoilValue);
 Serial.print("  cosCoilValue: ");
 Serial.println(cosCoilValue);
*/
 
 analogWrite(SinPin, sinCoilValue);                         // set the PWM-Values
 analogWrite(CosPin, cosCoilValue);
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.