Board index FlightGear Support Hardware

Homebrew stick -> Arduino -> Linux -> Fly flightgear - HOW?

Joysticks, pedals, monitors.

Homebrew stick -> Arduino -> Linux -> Fly flightgear - HOW?

Postby ScottBouch » Tue Jan 24, 2017 2:00 pm

Hi all,

I've got to a point in my project where I need a hand to be pointed in the right direction for a half decent tutorial... There are lots of tutorials out there, but I'm unsure where to follow for my specific requirements.

I have a very nice control stick, with two precision potentiometers (this came from an air force F16 pilot reaction training bench). You might say why not just get a USB stick? Well, all of my projects are done ona close to £zero budget, and a friend gave me this stick, so I plan to use it.

I have wired it to an Arduino Uno, and can successfully send the positions to the serial monitor on my Linux Mint PC.

Now, how best to get this data into Flightgear? How should I arrange the string of data from the Arduino to be read by flightgear? What range does flightgear expect analogue data to arrive in? I'd imagine 8 bit (256 values) would be plenty?

Once read by flightgear, how do I get it to be used for Pitch and Roll?

My very simple beginnings of the Arduino sketch so far:

Code: Select all
/*
Flightgear hardware integration 01: Stick X and Y only so far.

Scott Bouchard UK www.scottbouch.com 24-01-2017
*/

const int xaxis = A0; //Define stick x input
const int yaxis = A1; //Define stick y input

int roll = 510;       //Start roll (x) central, real world resting point
int pitch = 506;      //Start pitch (y) central, real world resting point


void setup() {

  Serial.begin(9600);
}


void loop() {

  roll  = analogRead(xaxis);
  pitch = analogRead(yaxis);

  Serial.println(pitch);

  delay(500);
}


I also plan to add another analogue for a basic rudder bar, and two for throttles. The Stick also has a trigger and 4 way trim hat switch which I'd like to eventually use too, but thought I'd start with the basics first.

I must point out that I've had a play with a few arduino projects before, but am still learning, but I have never messed about with the guts of FGFS, so guidance will need to be fairly explicit for me if possible.

Many thanks in advance,

Cheers, Scott
User avatar
ScottBouch
 
Posts: 183
Joined: Wed Jun 22, 2016 4:14 pm
Location: Midlands, UK
OS: Linux Mint

Re: Homebrew stick -> Arduino -> Linux -> Fly flightgear - H

Postby ludomotico » Tue Jan 24, 2017 2:44 pm

I would code a middleware in the PC reading from the arduino and sending the relevant codes to FlightGear.

This is the project I worked on a couple years ago for the Seneca II.

Final prototype:

Image

Arduino

A panel with 25 switches. When a switch moves, the arduino sends a message throught the serial connection. For example: "K15on" means the switch number 15 is on. "K20off" means the switch number 20 is set to off. If I recall correctly, the first thing the arduino does is sending the state of all switches.

Hardware: a matrix of switches (5 columns, 5 rows), all switches with diodes to allow them independent operation:

Image

Arduino code:

Code: Select all

const byte rows = 5;
const byte cols = 5;

//input
byte rowPins[rows] = { 3, 4, 5, 6, 7 };
// output
byte colPins[cols] = { 8 , 9, 10, 11, 12 };
byte buttons[rows][cols];

void setup() {
  Serial.begin(9600);
 
  for(byte r=0; r<rows; r++ ) {
    for(byte c=0; c<cols; c++ ) {
      buttons[r][c] = 2; // set an impossible value to update all buttons the first time
    }
  }
 
  for ( byte c=0; c<cols; c++ ) {
    pinMode(colPins[c], OUTPUT);
    digitalWrite(colPins[c], LOW);
  }

 
  /*for ( byte r=0; r<rows; r++ ) {
    pinMode(rowPins[r], INPUT);
  }*/

 
}

void loop() {
  for ( byte c=0; c<cols; c++ ) {
    // begins column pulse
    digitalWrite(colPins[c], HIGH);
   
    delay(1);
   
    for ( byte r=0; r<rows; r++ ) {
      byte v = digitalRead(rowPins[r]);
     
      if ( v != buttons[r][c] ) {
        byte b = r * cols + c;       
        Serial.print(F("K")); Serial.print(b);
        if ( v == 0 )
          Serial.println(F("off"));
        else
          Serial.println("on");
        buttons[r][c] = v;
      }
    }
   
    delay(100);
   
    // set pin to high impedance input. Ends column pulse
    digitalWrite(colPins[c], LOW);
   
  }
}



Computer


A Python script reading from the serial port and sending commands to FlightGear using telnet. Run flightgear using "fgfs --telnet=9000"

Python code, reading the arduino commands from the serial port and sending telnet commands to FlightGear, which is listening to port 9000:

Code: Select all
# -*- coding: utf-8 -*-

import serial
import sys
import logging
import telnetlib

# configure logging
logging.raiseExceptions = 0
logging.basicConfig(level=logging.DEBUG)

class PanelinoConnection:
   
    def __init__(self, port, baud, fgfs, conffile):
        self.conn = sys.stdin
        self.conn = serial.Serial(port, baud);
        self.fgfs = fgfs
       
        self.mapCommand = dict()
       
        f = open(conffile, 'r')
        for lines in f:
            key, command, text = lines.strip().split("\t", 3)
            self.mapCommand[key] = (command, text)
            logging.info('for key=%s, %s(%s)'%(key, command, text))
   
    def run(self):
        while True:
            l = self.conn.readline().strip();
            if self.mapCommand.has_key(l):
                command, text = self.mapCommand[l]
                if command == 'SET':
                    logging.info('SET command')
                    self.commandSET(text)
                else:
                    logging.warn('UNKNOWN command')
            else:
                logging.warn('UNKNOWN key: %s' % l)
   
    def commandSET(self, text):
        self.fgfs.send("set %s"%text)       

class FGFSConnection:
    def __init__(self, server, port):
        self.conn = telnetlib.Telnet(server, port)
        logging.info('Connected to: %s:%d'%(server, port))
   
    def send(self, text):
        logging.debug('Sending: %s'%text)
        self.conn.write(text + '\r\n')

if __name__ == '__main__':
    fgfs = FGFSConnection('127.0.0.1', 9000)
    panel = PanelinoConnection('/dev/ttyACM0', 9600, fgfs, 'senecaii.conf')
    try:
        panel.run()
    except KeyboardInterrupt:
        pass



This script needs a configuration file with the telnet commands to send to FlightGear when a switch is on/off. This is the configuration file:

senecaii.conf:

Code: Select all
K3on   SET   /controls/engines/engine/magneto true
K3off   SET   /controls/engines/engine/magneto false
K8on   SET   /controls/engines/engine/magneto[1] true
K8off   SET   /controls/engines/engine/magneto[1] false
K23on   SET   /controls/engines/engine/primer true
K23off   SET   /controls/engines/engine/primer false
K13on   SET   /controls/engines/engine/starter-switch true
K13off   SET   /controls/engines/engine/starter-switch false
K18on   SET   /controls/engines/engine[1]/starter-switch true
K18off   SET   /controls/engines/engine[1]/starter-switch false
K0on   SET   /controls/engines/engine[1]/primer true
K0off   SET   /controls/engines/engine[1]/primer false
K5on   SET   /controls/engines/engine[1]/magneto true
K5off   SET   /controls/engines/engine[1]/magneto false
K20on   SET   /controls/engines/engine[1]/magneto[1] true
K20off   SET   /controls/engines/engine[1]/magneto[1] false
K2on   SET   /controls/lighting/landing-lights true
K2off   SET   /controls/lighting/landing-lights false
K7on   SET   /controls/lighting/taxi-light true
K7off   SET   /controls/lighting/taxi-light false
K22on   SET   /controls/lighting/nav-lights true
K22off   SET   /controls/lighting/nav-lights false
K12on   SET   /controls/lighting/beacon true
K12off   SET   /controls/lighting/beacon false
K17on   SET   /controls/lighting/strobe true
K17off   SET   /controls/lighting/strobe false
K15on   SET   /controls/engines/engine/fuel-pump true
K15off   SET   /controls/engines/engine/fuel-pump false
K10on   SET   /controls/engines/engine[1]/fuel-pump true
K10off   SET   /controls/engines/engine[1]/fuel-pump false
K4on   SET   /controls/electric/battery-switch true
K4off   SET   /controls/electric/battery-switch false
K9on   SET   /controls/electric/engine/generator true
K9off   SET   /controls/electric/engine/generator false
K24on   SET   /controls/electric/engine[1]/generator true
K24off   SET   /controls/electric/engine[1]/generator false


Keep in mind I coded this like two years ago. It worked at the moment, but I don't know if it still works!
User avatar
ludomotico
 
Posts: 1269
Joined: Tue Apr 24, 2012 2:01 pm
Version: nightly
OS: Windows 10

Re: Homebrew stick -> Arduino -> Linux -> Fly flightgear - H

Postby ScottBouch » Tue Jan 24, 2017 3:41 pm

Brilliant stuff, thanks for sharing with me!

I note this is all for digital signals, have you ever tried it with analogues?

I'll ponder and think over the coming weeks and hopefully get something working!

It's been a while since I've played with Python, and even then I only scratched the surface... so this will be a good learning curve!

Many thanks, Scott.
User avatar
ScottBouch
 
Posts: 183
Joined: Wed Jun 22, 2016 4:14 pm
Location: Midlands, UK
OS: Linux Mint

Re: Homebrew stick -> Arduino -> Linux -> Fly flightgear - H

Postby Johan G » Tue Jan 24, 2017 10:57 pm

The documentation that come along with Python is great. :) If you start with the tutorials and work your way through them you will most likely grasp the concepts. It will help that you have done some programming before.
Low-level flying — It's all fun and games till someone looses an engine. (Paraphrased from a YouTube video)
Improving the Dassault Mirage F1 (Wiki, Forum, GitLab. Work in slow progress)
Some YouTube videos
Johan G
Moderator
 
Posts: 6629
Joined: Fri Aug 06, 2010 6:33 pm
Location: Sweden
Callsign: SE-JG
IRC name: Johan_G
Version: 2020.3.4
OS: Windows 10, 64 bit

Re: Homebrew stick -> Arduino -> Linux -> Fly flightgear - H

Postby AndersG » Wed Jan 25, 2017 10:14 am

ScottBouch wrote in Tue Jan 24, 2017 2:00 pm:Hi all,

I've got to a point in my project where I need a hand to be pointed in the right direction for a half decent tutorial... There are lots of tutorials out there, but I'm unsure where to follow for my specific requirements.

I have a very nice control stick, with two precision potentiometers (this came from an air force F16 pilot reaction training bench). You might say why not just get a USB stick? Well, all of my projects are done ona close to £zero budget, and a friend gave me this stick, so I plan to use it.

I have wired it to an Arduino Uno, and can successfully send the positions to the serial monitor on my Linux Mint PC.


When I looked at building a custom joystick some years ago I found that a Arduino Leonardo can be programmed to directly act as a USB joystick (or presumably any other USB HID device). This is not true for all Arduino variants since it depends on how the hardware is organised on the board (IIRC the Leonardo is simpler than most and handle USB directly on the "main" CPU/SOC, which is good for this use case). Unfortunately, I never got around to actually build anything - though I tried connecting it up as a USB joystick device which really did work.
Callsign: SE-AG
Aircraft (uhm...): Submarine Scout, Zeppelin NT, ZF Navy free balloon, Nordstern, Hindenburg, Short Empire flying-boat, ZNP-K, North Sea class, MTB T21 class, U.S.S. Monitor, MFI-9B, Type UB I submarine, Gokstad ship, Renault FT.
AndersG
 
Posts: 2524
Joined: Wed Nov 29, 2006 10:20 am
Location: Göteborg, Sweden
Callsign: SE-AG
OS: Debian GNU Linux

Re: Homebrew stick -> Arduino -> Linux -> Fly flightgear - H

Postby ScottBouch » Wed Jan 25, 2017 10:08 pm

Yes, I did look at HID joysticks, as that could potentially be a simple plug and play option, but it seems to be more relevant for Windows users than Linux from what i've read.

I plan on creating a few cockpit items, so am at ease with the serial data interface as it'll likely be used by the other items too. However, I have read about TCP/IP interface with FGFS, This could work for switches and indicators, but I don't know how good it would be for analogue controls like the stick and rudder... the TCP method can be used to avoid the bit of middleware (Python in this case to talk to telnet).

Cheers, Scott
User avatar
ScottBouch
 
Posts: 183
Joined: Wed Jun 22, 2016 4:14 pm
Location: Midlands, UK
OS: Linux Mint


Return to Hardware

Who is online

Users browsing this forum: No registered users and 1 guest