Jump to content

Recommended Posts

Not sure if here is the right place for this, but here goes:
I thought I'd share a device I've made for quickly working out the servo times for gauge positions.
I don't have photos of mine at the moment because I made it on breadboard and dismantled it when I was done.

Here's the schematic:



Here's the Arduino Code:


/* Servo calibration program
 *  Designed to be used to determine the times of servo pulses for setting up 
 *  flight simulator gauges.
 *  Pin assignments are for Arduino Nano.  Other arduinos my work without modifying
 *  the code, but you may need to adjust pin numbers dependent on function.
 *  The display used is a 20x4 character LCD with I2C backpack.
 *  The two ceramic 100nF capacitors kill noise from the rotary switch.
 *  Potentiometer code is included, but disabled as the rotary encoder 
 *  is more reliable.
 *  Written by Tim Jacobs
 *  Publicised May 2021

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 20 chars and 4 line display

#include <Servo.h> 

Servo myservo;

byte vertline0[8] = {16,16,16,16,16,16,16,};  // Custom character bitmaps for bars
byte vertline1[8] = {8,8,8,8,8,8,8,};
byte vertline2[8] = {4,4,4,4,4,4,4,};
byte vertline3[8] = {2,2,2,2,2,2,2,};
byte vertline4[8] = {1,1,1,1,1,1,1,};

unsigned int ServoTimeOutput;
unsigned int ServoTimeOutputLast;
unsigned int ServoTimeMin;
unsigned int ServoTimeMax;
unsigned int ServoTimeMid;
unsigned int manualpos;

int ServoTimeIncrement;

int bar_charNo;
int bar_number;
int bar_character;

#define ServoPin 6   // Servo output pin (PWM pin)
#define PotPin A3    // NOT USED
#define encoder0PinA 2 // Encoder input A (Interrupt pin)
#define encoder0PinB 3 // Encoder input B (Interrupt pin)
#define encoder0Btn 7  // Encoder button input (Any input pin)

// A4 and A5 are automatically defined for I2C use by the WIRE library

int encoder0PinALast = LOW;
int n = LOW;

int ButtonState;
int ButtonStateLast;
int incrementButtonClicks;

void setup() {

  pinMode(encoder0PinA, INPUT_PULLUP);
  pinMode(encoder0PinB, INPUT_PULLUP);
  pinMode(encoder0Btn, INPUT_PULLUP);

  attachInterrupt(0, encoderRead, CHANGE);
  attachInterrupt(1, encoderRead, CHANGE);

    lcd.init();                      // initialize the lcd 

    lcd.createChar(0, vertline0);  // Custom character definition
    lcd.createChar(1, vertline1);
    lcd.createChar(2, vertline2);
    lcd.createChar(3, vertline3);
    lcd.createChar(4, vertline4);

    lcd.setCursor(0,0);  //  column, row

    ServoTimeMin = 500;  // safe defaults
    ServoTimeMax = 2300;
    ServoTimeMid = ((ServoTimeMax-ServoTimeMin)/2)+ServoTimeMin;
   ServoTimeOutput = ServoTimeMid;  //  set servo to mid-point

   incrementButtonClicks = 1;  // Set default increment digit 0 = 1, 3 = 1000

  myservo.writeMicroseconds(ServoTimeOutput);  // 


void loop() {

// PotInput();




void incrementButtonRead(){
  ButtonState = digitalRead(encoder0Btn);

  if (ButtonState != ButtonStateLast){

    if (ButtonState == LOW){

    incrementButtonClicks = incrementButtonClicks + 1;
    if (incrementButtonClicks >=4){incrementButtonClicks = 0;}
   ButtonStateLast = ButtonState;

  switch (incrementButtonClicks) {
  case 0:
    ServoTimeIncrement = 1;
  case 1:
    ServoTimeIncrement = 10;
  case 2:
    ServoTimeIncrement = 100;
   case 3:
    ServoTimeIncrement = 1000;

manualCursorBlink();  // Sets manual mode cursor position to blink


//  Potentiometer input not used
void PotInput(){
  manualpos = analogRead(PotPin);
  ServoTimeOutput = map(manualpos, 0, 1023, ServoTimeMin, ServoTimeMax);

void TimeBarDisplay(){

if (ServoTimeOutput >= ServoTimeMax){
    ServoTimeOutput = ServoTimeMax;
  if (ServoTimeOutput <= ServoTimeMin){
    ServoTimeOutput = ServoTimeMin;

  if (ServoTimeOutput != ServoTimeOutputLast){

//  lcd.clear();  // May take too much time.

  lcd.print("Servo output:  "); // Clear the line
  if (ServoTimeOutput >= 1000){

  lcd.print("us  "); 


  ServoTimeMid = ((ServoTimeMax-ServoTimeMin)/2)+ServoTimeMin;



  lcd.print("                    "); // Clear the line

  bar_number = map(ServoTimeOutput, ServoTimeMin, ServoTimeMax, 0, 99);
  bar_charNo = bar_number/5;
  bar_character = (bar_number) - (bar_charNo * 5);

  lcd.write (bar_character);

  ServoTimeOutputLast = ServoTimeOutput;

  manualCursorBlink();  // Sets manual mode cursor position to blink


void manualCursorBlink() {  // Sets manual mode cursor position to blink
 lcd.cursor();  // Straight underline cursor
//  lcd.blink();     // Full block flashing cursor

switch (ServoTimeIncrement) {
  case 1:
  case 10:
  case 100:
   case 1000:


void encoderRead() {
  n = digitalRead(encoder0PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == HIGH) {
      ServoTimeOutput = ServoTimeOutput - ServoTimeIncrement;
    } else {
      ServoTimeOutput = ServoTimeOutput + ServoTimeIncrement;
  encoder0PinALast = n;


Connect the device to the servo that drives a gauge.
When the device first starts, it has some "safe" min and max servo times set. These can be changed if you want, but I just went with the numbers given.
To adjust the time, turn the rotary encoder and the selected digit will change, and also the servo output.
Pressing the rotary encoder button changes the selected digit.
You can then adjust the time until the gauge needle reaches the required end positions and note the times to put into the DCS servo lines.

Note that if your servo draws too much current, it could overload the arduino's regulator and "brown-out" the arduino.  In this case, you might have to drive the circuit (or just the servo) off an external 5V supply.

I hope that helps someone.  I may one day get around to building a permanent version

  • Thanks 1
Link to post
Share on other sites
On 5/28/2021 at 9:02 PM, crash test pilot said:

Wonderful! Thanks for a really handy tool! A note: even the small 9g servo draws up to 700 mA, which is far too much for a nano (max 200mA), so an external power source is a must.

Agreed.  Though I've not had much trouble driving one or two 9g servos from a Nano - they don't tend to be pulling hard when used in gauges.
I may have just been lucky.

Link to post
Share on other sites

A few years ago I invested in about $2000 worth of Flight Illusion gauges and use them with P3D and X-Plane. Does anyone know how or where I might find someone who might be able to create a software interface to drive them?

Link to post
Share on other sites
On 6/2/2021 at 2:43 PM, DH14300 said:

A few years ago I invested in about $2000 worth of Flight Illusion gauges and use them with P3D and X-Plane. Does anyone know how or where I might find someone who might be able to create a software interface to drive them?

You should probably create your own new topic so more people could see your question.

Link to post
Share on other sites
On 6/4/2021 at 1:06 PM, DH14300 said:

This question was intentionally directed to gauge builders.

This part of the forum is pretty much ALL gauge builders, and you'll get more of a response in a separate thread because people skip threads they're not interested in.
It's entirely possible someone out there knows the answer to your question, but isn't reading this topic.

It would also make it easier for others to find the info later.  Unless you're one of those annoying people who delete their posts after getting the info they want...

Link to post
Share on other sites

I appreciate your guidance here. To make sure I understand you correctly, start a new thread under the 'Home Cockpits' category or 'Inputs and Outputs'? Thank you.

Link to post
Share on other sites
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...