miniAVX 2.02.178 - DIY Arduino Mini Avionics Panel

I started this after finding out about the BitsAndDroids Connector software & Arduino library. It enables you to write code on your Arduino that receives/transmits data to/from MSFS via Simconnect. I wanted to have something like the Knobster (Air Manager), but without the extra need for software or touchscreen.

The really GREAT thing about miniAVX is that the MAIN rotary instantaneously decides the function of the display and the other two rotaries (left and right). You just scroll down the menu to the function you wish to change/see (often two at once) and miniAVX loads the display and the knobs with the according functions. That way you can quickly access a lot of functions.

Example: Turn the main knob to “COM 1” (NO button press needed) and the other two knobs start to control Mhz and Khz of that radio and switch frequencies. If you press the main button you switch over to COM2. The display is updated accordingly.

Example: Turn the main knob to “ALT - VS” and select the autopilot altitude with the left rotary and vertical speed with the right. Pressing either one activates the corresponding AP function (displayed with a dot like in an Airbus). And because the display reacts to MSFS only, it can never go out of sync.

Current functions include: COM1&2, NAV1&2, ADF1&2, XPNDR1&2, OBS1&2; AP HDG, ALT, VS; BARO, ALT, SPD;

Developement Screenshots:




Technical data below!

12 Likes

Material List:

1x Arduino Due Amazon.de
3x Rotary encoder with pushbutton (KY-040 or similar) Amazon.de
1x OLED I2C Display 128x64 (monochrome) Amazon.de
1x 8-Digit seven segment display with MAX7219 IC Amazon.de
Cables Amazon.de
Housing (I used pcb material and a stand-off kit Amazon.de)

Sketch:
Pontiac51/miniAVX: MSFS Radio and AP panel with Arduino (github.com)

Libraries used:

BitsAndDroids Connector - https://www.bitsanddroids.com/
OLED_I2C - OLED_I2C - Rinky-Dink Electronics
LedControl - LedControl - Arduino Libraries
BigFont.c - Dowload from my Github and add to OLED_I2C library

Schematic:

5 Likes

BitsAndDroids is great, awesome solution.

HappyScroll3

6h

Thanks a lot.

I got it running. I used your code which I severely trimmed for just the case of one breadboarded rotary encoder and I was able to change values in the game.

I had to download the SDK although I’m not sure if that is necessary. I couldn’t get it to work at first and then I decided to unplug and replug the usb cable after uploading the sketch. Then I hit start on the BitsandDroids application and then I was able to change in game values using the rotary encoder.

Next Step is to check If I can receive data from MSFS 2020. So far I don’t seem to need the 10 uf capacitor in the Documentation. Hope that doesn’t change with serial reading.

I’m glad that I don’t have to DFU and reflash the firmware to get the sketch running (just unplug and replug the usb cable). I had to reflash the original firmware each time for my ATS button box because the USB hid firmware does not allow uploading a sketch.

Thanks again,
Chris

@HappyScroll3 You wont need the MSFS SDK for this, SimConnect is default functionality.

The power cycling of the board is something you have to do frequently. I think the BitsAndDroids connector does not close ports correctly here. I have already forwarded that to the developer, he has a fix ready for the next version.

The 10uf only comes into play once you start receiving and it does not work on the DUE. Which Arduino are you using?

I am using an arduino UNO Rev3.

I’ve read a little bit about the issue. If I understand correctly, the Arduino IDE uses avrdude to upload the sketch to the ISP. However, a reset happens and avrdude ends up talking to the bootloader instead.

I have not had any issues with uploading sketches on the Arduino Uno Rev3.

From ArduinoISP on Uno requires 10uF cap -- WHY? - Microcontrollers - Arduino Forum

More recent versions of the Uno bootloader detect corrupt serial communication (the bootloader and ISP sketch use different baud rates) and quit immediately. This usually allows avrdude to start working properly without need for suppression of the auto-reset.

I will test the serial receive side and report any issues. Hope I don’t brick it.

It seems I can’t receive any serial data.

It should be as easy as adding this in void loop():

if (connector.getLightTaxiOn())
Serial.println(connector.sendIncWholeNav1());

Then in bits and droids Receive variable section, check the Taxilights and hit Start

Then in game, just turn on the taxilight and you should see Nav1 Whole number increase. The Send serial command side works as I can still use the encoder to change the Nav1 values.

Perhaps this is what the capacitor is supposed to solve?

Chris

As far as I know you cannot do sending and receiving simultaneously over one port. The developer of BitsAndDroids is using different Arduinos for sending and receiving up until now. He is working to fix it, but serial communication can be tricky.
I actually was the first to get it working with ONE Arduino and that was a DUE. And I still have to run two sessions of the program, one for sending on one port and one for receiving on the other.

You could try using multiple connectors (as I have, one for RX and one for TX), but I am not sure this will solve the problem in this case. As it currently stands, bidirectional communication is flawed.

Maybe try to get a simpler version running first, try to display anything.

One more hint: If you start the BitsAndDroids in receive mode, did you also start it in transmit mode? That’s two different buttons…

:edit: Could it be you ommitted this line in your loop?

connector.dataHandling();

If that’s the case then I need two COM ports. I completely missed this in the documentation. It does make sense from what I am observing. Perhaps the Send component of the BitsandDroids app captures the COM port for one direction serial communication when I click Start there. When I click Start on the Data or Receive component, it just won’t work because the COM port is being utilized by the Send Side already. I just wished the BitsandDroids App signaled the failure to capture the port a second time instead of indicating that it is “Running”.

If there is no bidirectional serial port communication, then I will definitely need two arduinos. One to receive variables and one to transmit. To utilize the IO pins on both arduino’s to interface to switches and encoders though, I need to shuttle information from one arduino to the other. I think this can be done by using the SDA/SCL lines in a master slave relationship. Then on the master arduino which will be the Receive Arduino, If I use an encoder or switch, I need to send to the Slave arduino (Transmit arduino) which encoder or switch was activated and that Transmit arduino can then activate the appropriate connector.function().

This will be a bit of work . The DUE is the only one with two USB ports. I assume you are using both and have two COM ports available. I wonder if BitsandDroids will eventually be able to provide bidirectional serial communication in one port or maybe this is a hardware limitation. I wonder how Mobiflight handles this issue.

Yes one after the other which is why I think the second is silently failing despite telling me it is running.

No, i have this in there.

It will take me a little while to see if I could get this running.

I wonder if the situation is the same for all types of arduino’s except the DUE.

Are you using a steering wheel to fly your plane?

Chris

Well I managed to establish SDA/SCL communication between a master and a slave arduino. The Master also has a rotary encoder connected to it. The rotary encoder works and with a clockwise or counterclockwise turn, it sends a uint8_t via I2C to the slave. The slave receives the byte and acts on it to transmit specific commands to BitsAndDroids that control sim functions. This works well.

However, the master arduino can’t seem to query BitsAndDroids for status of Taxi, Landing and Beacon Lights (which I have checked ). I used these lights to test the Receive side because I can turn then on and off easily in the cockpit. None of the actions assigned to activation of these lights seem to occur on the slave arduino. It’s like I am not getting any answer to the queries.

I notice that on the Receive Variables section on the BitsandDroids, I can’t seem to save a Set. Is the BitsandDroids app requiring some type of activation to enable features?

Thanks,
Chris

BitsAndDroids is working on a version of the program that can send and transmit without having to run two programs. He is also trying to get TX and RX running over one port, but from what I have heard it’s not trivial. Currently, you need two ports and he always uses one for sending and one for transmitting. So, it’s either the DUE or two Arduinos.

Mobiflight works with its own firmware, so I guess they solved it differently. It’s hard to say. But Mobiflight does not allow you to add your own code like BitsAndDroids does. That’s why I choose it, alltough the Mobiflight is much more user friendly.

If I understand you correctly you want to connect two Arduinos. But I am not sure I understand why. You want to send signals to another Arduino when you flip a switch, correct? But it should only send back to MSFS. And the receiving part should receive values from MSFS only. Otherwise you might run into snychronization issues. Or is this only to have more GPIO pins?

Yes, I am using both ports on the DUE. One for sending, one for receiving. I have one connector open for each port. And one program running for each port. This way sending and receiving is completely seperate and the never interfere while running the program. That way everything stays in synch even if i flip switches in the sim or MSFS or the Arduino “looses” information.

No, I am not using a steering wheel to fly my plane. But my cockpit is multipurpose. :wink:

image

Yeah, that is a problem that I had too in the beginning. Could you maybe share your code?

The Sets don’t do anything for me also. But the selected data and com options save none the less.

Here is the code for the Master: (Don’t know why it is block formatting some of the code)

//MASTER (RECEIVE) ARDUINO COM 7

#include<BitsAndDroidsFlightConnector.h>
#include <Wire.h>

#define TAXI_LIGHTS 0x01
#define AP_MASTER_ON 0x02
#define STALL_WARNING 0x03
#define BEACON_LIGHTS 0x04
#define LANDING_LIGHTS 0x05

#define NAV1_WHOLE_INC 0x33
#define NAV1_WHOLE_DEC 0x34
#define NAV1_FRACT_INC 0x35
#define NAV1_FRACT_DEC 0x36
#define HEADING_BUG_INC 0x37
#define HEADING_BUG_DEC 0x38

//For all the other Arduinos
BitsAndDroidsFlightConnector connector(false);

// data type for button
struct Button {
uint8_t gpioSw;
uint8_t lastStateSw;
};

//data type for rotary
struct Rotary {
uint8_t gpioClk;
uint8_t gpioDt;
uint8_t lastStateClk;
uint8_t lastStateDt;
Button button;
};

bool NavMega = true;

//Just to keep track of things and in case I want to sequentially access
const uint8_t data_input[5] = {
TAXI_LIGHTS,
AP_MASTER_ON,
STALL_WARNING,
BEACON_LIGHTS,
LANDING_LIGHTS,
};

const uint8_t action_output[6] = {
NAV1_WHOLE_INC,
NAV1_WHOLE_DEC,
NAV1_FRACT_INC,
NAV1_FRACT_DEC,
HEADING_BUG_INC,
HEADING_BUG_DEC,

};

#define ROTARIES 1
Rotary rotaries[ROTARIES];

void setupRotary(Rotary *cur, uint8_t gpioClk, uint8_t gpioDt , uint8_t gpioSw) {
pinMode(gpioClk, INPUT_PULLUP);
pinMode(gpioDt, INPUT_PULLUP);
pinMode(gpioSw, INPUT_PULLUP);
cur->gpioClk = gpioClk;
cur->gpioDt = gpioDt;
cur->button.gpioSw = gpioSw;
cur->button.lastStateSw = LOW;
}

void setup() {
// Start the I2C Bus as Master
Wire.begin();

//If you’re using a Leonardo / Pro-micro this line can be left out.
Serial.begin(115200);

//If you notice some instability gradually increase this value with increments of 5.
Serial.setTimeout(15);

//Serial Monitor
//Serial.begin(9600);

// rotaries
setupRotary(&rotaries[0], 13, 12, 11);

}

void loop() {
connector.dataHandling();
loopRotaries();
loopVariables();

}

void transmit(uint8_t x){
Wire.beginTransmission(9); // transmit to device #9
Wire.write(x); // sends x
Wire.endTransmission(); // stop transmitting

}

void loopVariables(){
if (connector.getLightTaxiOn())
transmit(TAXI_LIGHTS);
if (connector.getLightBeaconOn())
transmit(BEACON_LIGHTS);
if (connector.getLightLandingOn())
transmit(LANDING_LIGHTS);

}

void loopRotaries() {
Rotary *cur;

for (int i = 0; i < ROTARIES; i++) {
cur = &rotaries[i];
// first, check state
int currentStateClk = !digitalRead(cur->gpioClk);
int currentStateDt = !digitalRead(cur->gpioDt);
int currentStateSw = digitalRead(cur->button.gpioSw);
delay(1);

if (currentStateDt != cur->lastStateDt) {
  // check for change
  cur->lastStateDt = currentStateDt;
}

if (currentStateClk != cur->lastStateClk) {
  // check for change
  if (currentStateClk == 1) {
    if (cur->lastStateDt == 0) {
      // turned clockwise
      //Serial.println("Clockwise");
      
      if (NavMega) 
         transmit(NAV1_WHOLE_INC);
      else
         transmit(NAV1_FRACT_INC);
    } else {
      // turned counter-clockwise
      //Serial.println("Counterclockwise");
      
      if (NavMega)
         transmit(NAV1_WHOLE_DEC);
      else
         transmit(NAV1_FRACT_DEC);
    }
  }
  cur->lastStateClk = currentStateClk;
}

if (currentStateSw != cur->button.lastStateSw && currentStateSw == HIGH) {
  NavMega = !NavMega;


}
cur->button.lastStateSw = currentStateSw;

}
}

Here is the code for the Slave:

//SLAVE (TRANSMIT) ARDUINO COM 8

#include<BitsAndDroidsFlightConnector.h>
#include <Wire.h>

#define TAXI_LIGHTS 0x01
#define AP_MASTER_ON 0x02
#define STALL_WARNING 0x03
#define BEACON_LIGHTS 0x04
#define LANDING_LIGHTS 0x05

#define NAV1_WHOLE_INC 0x33
#define NAV1_WHOLE_DEC 0x34
#define NAV1_FRACT_INC 0x35
#define NAV1_FRACT_DEC 0x36
#define HEADING_BUG_INC 0x37
#define HEADING_BUG_DEC 0x38

//For all the other Arduinos
BitsAndDroidsFlightConnector connector(false);

//Just to keep track of things and in case I want to sequentially access
const uint8_t data_input[3] = {
TAXI_LIGHTS,
AP_MASTER_ON,
STALL_WARNING,
};

const uint8_t action_output[6] = {
NAV1_WHOLE_INC,
NAV1_WHOLE_DEC,
NAV1_FRACT_INC,
NAV1_FRACT_DEC,
HEADING_BUG_INC,
HEADING_BUG_DEC,

};

uint8_t message;

void setup() {
// Start the I2C Bus as Slave on address 9
Wire.begin(9);
// Attach a function to trigger when something is received.
Wire.onReceive(receiveEvent);

//If you’re using a Leonardo / Pro-micro this line can be left out.
Serial.begin(115200);
//If you notice some instability gradually increase this value with increments of 5.
Serial.setTimeout(15);

//Serial Monitor
//Serial.begin(9600);

}

void loop() {
//Serial.print("Received ");
//Serial.println(message,DEC);
connector.dataHandling();
switch (message) {
case NAV1_WHOLE_INC: Serial.println(connector.sendIncWholeNav1()); break;
case NAV1_WHOLE_DEC: Serial.println(connector.sendDecWholeNav1()); break;
case NAV1_FRACT_INC: Serial.println(connector.sendIncFractNav1()); break;
case NAV1_FRACT_DEC: Serial.println(connector.sendDecFractNav1()); break;
case HEADING_BUG_INC: Serial.println(connector.sendHeadingBugInc()); break;
case HEADING_BUG_DEC: Serial.println(connector.sendHeadingBugDec()); break;
case TAXI_LIGHTS: Serial.println(connector.sendHeadingBugDec()); break;
case BEACON_LIGHTS: Serial.println(connector.sendHeadingBugInc()); break;
case LANDING_LIGHTS: Serial.println(connector.sendIncWholeNav1()); break;
}
message=0;

}

void receiveEvent(int bytes) {
message = Wire.read(); // read one character from the I2C

}

Hope you can spot the errors.

The reason I want to connect two arduinos is so that I can utilize all available GPIO pins. The receive arduino will have the displays and LEDs. The transmit arduino will have all the controls. However, I think I will need more than the available GPIO on the transmit arduino, so I wanted a solution where the Receive arduino could have its own switches and buttons working and transmit their status to the transmit arduino. The receive arduino will only ever query for data. The transmit arduino will only send commands.

I really didn’t think you were flying a plane with a steering wheel. :wink:

I’ve got a racing wheel setup and I am thinking of putting together another one sometime at the end of the year just for flight simming. It will just be a chore to drag each setup in front of the couch whenever I need to drive or fly.

Thanks,
Chris

The code seems to be OK. I do not think you need the dataHandling() on the slave Arduino as it only sends. Serial.println should be enough for that.

My guess is the master arduino is reset each time it receives a signal, hence it never gets to the point where it can forward the data to the slave. I still do not know which Arduinos you are using, so its hard to tell. BitsAndDroids does have more information on this in his documentation.

My suggestion is to use the 2nd arduino as logger for now. Try to get a debug output on the Serial monitor of the slave depending on the received data on the master. This should give you a clue if there is no data or the master resets itself.

I think you are correct. I will have to obtain a capacitor to test for sure. I am using a couple of Arduino Uno R3. Can you recommend the appropriate capacitor? I know its 10 uf but what voltage?

Thanks,
Chris

Anything should be fine really. See what you can get cheapest. 16V is the smallest I can get and that should be plenty. 50V are often cheaper, so it really comes down to price, size should not be an issue.

I am going to have to order some parts:

I want to build the A320 autopilot panel and the Cessna 172 Radio Panel.

SPD and HDG - 2 x 4 digit display = 4 IO pins
ALT - 6 digit display example: 30 000 = 2 IO pins
V/S - 6 digit display example: +20 000 = 2 IO pins
4 push pull rotary encoders = 8 IO pins
3 LED require 3 IO PINS
4 rotary encoders each have 4 switches
6 lighted buttons: (don’t know what type or how to wire these yet)
–>LOC AP1 AP2 ATHR EXPED APPR
3 nonlatching black buttons
→ SPD/MACH, HDG/TRK, METRIC/ALT

TOTAL DIO pins needed = 19
TOTAL BUTTONS needed = 13


Cessna Radio Panel ( one unit only )
2 6 digit display = 4 IO pins
2 dual shaft rotary encoders = 4 x 2 =8 IO pins
TOTAL DIO pins needed = 12

7 buttons COM1 COM2 NAV1 NAV2 ADF DME XPDR
2 switches on rotary encoder = 2 buttons
2 standby/active buttons
Total buttons = 11

OTHER BUTTONS in Cessna Panel: 20

TOTAL FOR ALL BUTTONS = 11 + 13 = 24 +20 = 44 ( 7 Analog and 7 Digital pins in matrix gives 49 buttons )
TOTAL Digital IO PINS NEEDED = 19 + 12 = 31 + 7 = 38
TOTAL Analog pins needed 7 + 2 for SDA/SCL = 9

I quickly realized that I will need an arduino Mega (receive) for this project. I won’t need a capacitor now. I could still connect an UNO (send) to it via I2c if only to have separate serial input and output pipelines. I hope BitsandDroids will keep the bidirectional functionality a configuration setting. I am now partial towards a two arduino solution because two onedirectional pipes will be faster than one bidirectional pipe.

Do you think the digit displays would be enough for the intended applications?

I am going to need a nibbler for the square holes.

I am trying to figure out how to cover the square hole imperfections with a makeshift bezel, perhaps plastic that I can cut up and form into a square to hide the square hole edges.

The hardest thing to find cheaply is a dual shaft rotary encoder for the radio so there is an outer and inner knob, and push pull encoders for the A320 managed and select modes.

This will be a big project and will take a while to finish.

Arduino code to be used with BitsAndDroids Connector and Library (v0.8.4).

UPDATE 1.06
OBS 1 & 2 display now working
GPS course display
NAV1 and GPS Autopilot ON/OFF (NAV1 mode press OBS1, GPS mode press GPS)
ALT and SPD can be switched between radar/indicated and indicated/ground

Well this is way bigger than my project. I would ask BitsAndDroids directly, if the Arduino is able to handle this. He has way more experience with other Arduinos and he is rather quick to respond on his Discord.