A new Arduino project: the RIO seat – Part I

Heatblur released their sublime F-14 a few weeks ago and I’m totally amazed by the RIO role. Coming from rotary-wings, I learnt a great deal of things about how fixed-wing are operated and about a (fairly recent?) radar works. Obviously, I couldn’t just rely on my mouse and current setup to handle the amount of new controls therefore I ended up planning a new ad hoc control box (actually, I planned two). This is a good chance to write another step-by-step tutorial about how to plan and build a control box. For this purpose I will use the same structure I have used for my step-by-step guide; I will not go into the detail as much though.

Step I: Planning

This step took me a few weeks. For real. Since the release of the manual, I thought about how new boxes would fit into my tetris-like setup.
In primis I identified which functions are used more often: the DDD panel, alt/elev knobs plus bars and azimuth, TID, HCU and countermeasures are definitely the one that are used more often (I did not consider Radio and Tacan because I use my usual boxes for those). If you are not sure about which functions are more used in a particular airframe the answer is always the same: fly it! After a while you will have an idea decent enough to start planning.

Once I had a good understanding of which functions I wanted, I drew a 1:1 scale of the boxes with LibreOffice Draw.

Eventually I added the sketches to diagram of my setup.
rio-1-planning-libreoffice-full-setup

None of the boxes were set in stone yet but having a full picture is very important before ordering buttons, switches, resistors and whatever else is needed in order to avoid wasting money.

Step II: Drilling

I find this step the most boring sans the soldering.. Anyway, thanks to the 1:1-scaled diagrams, this part is quite easy. A quick tip: place your switches on the box itself before drilling. Having real items in your hands is different than planning on a monitor. Pay also attention to factors such as the thickness of the box or the size of the blog where the screw rests.

..and, a couple hours later, the first glimpse at how the final panel will look like.
rio-2-drillingsmall_fullset

Advertisements

Arduino pills: Sending Keystrokes

Arduino has a very simple and effective way to send a keystrokes to the PC. It just takes a single instruction, Keyboard.write and the parameter is the key that we want our board to simulate. As usual, details and more info are available in the official documentation.

I use this instruction to send the F12 key and reset my Track IR.

Keyboard.write(KEY_F12);

I have assigned the big round button of my Radio Box to it since I have the habit of recentering my ancient Track IR v4 quite often.

Playing with resistors Part I: 3-way latched switches

Right after finishing my second Control Box (the so-called Radio Box since I planned it to control R800L1 and R828) I looked for a way to increase the flexibility and the capabilities of my control boxes. Something I really wanted to control were the 3-way latched switches. These switches look exactly as the 3-way momentary switches I used on my very first Control Box but are not spring-loaded to return to the central position after the release (I’m going to call them “Momentary” and “Latched” for semplicity from now on). This apparently little detail have a number of consequences: for instance Latched switches cannot be used in a basic button matrix because, by holding their position, they are a constant closed circuit whereas the Momentary are just a temporary one.

A long time ago in a High School far, far away…

There are (as usual I’d say) a number of ways to solve the issue. Mine comes from some reminiscences from the high school: Voltage Dividers. I have mentioned already the theory behind this simple circuit in the article I linked above. Now I’m going a bit more into the details of its implementation.

In primis we need some additional materials, namely two resistors for every Latched we want to implement. I usually build them in pairs unless I’m working on something specific, such as my UFC/PRTz. These resistors will be classic 10kΩ each. In addition, a stripboard or similar is also great.

The Circuit

I have used Voltage Dividers to update the initial implementation of my Radio Box. The following is an extract from the wiring diagram of the first version.

resitors-vd-radio-box-old

As you can see, nothing different from the examples I wrote about in my step by step guide. The Momentary switch is, in fact, part of a button matrix.

As I mentioned earlier, a stripboard is great to build the voltage divider. This is how it will look like:

resitors-vd-voltage-divider-circuit
Voltage Divider

You can build your own board in a different way: for instance, #1 can go straight to GND but I put it there in order to have a more clean and organized wiring diagram.
The circuit is quite simple: GND and Vcc are self-explanatory, An is the Analog input, 1-2-3 are the positions on the 3-way switch. The Analog input is required: it reads a different value depending on the position of the switch and a digital input simply cannot do that. This highlights immediately one of the limitations of this solutions, i.e. the fact that the number of Analog pins on an Arduino Leonardo board is limited to 4.

This is the result when we put everything together:

resitors-vd-radio-box-v2

This is not really difficult, isn’t it?
That’s all for the hardware, now let’s go back to the IDE. I know you can’t wait 🙂

Coding

Since the Latched is not part of the button matrix anymore and works in a complete different way, we have to write some ad hoc code.
In primis we have to verify that the circuit is working correctly. There is a very simple firmware I use very often when I work with Analog inputs. It’s just a loop that outputs the value of an Analog input to the serial monitor. I will write an “Arduino Pill” about it at some point but for now, this is its simplified code:

#define ANALOG_PIN A3 //change A3 with your analog pin number
void setup() {
Serial.begin(9600);
pinMode(ANALOG_PIN, INPUT_PULLUP);
}
void loop() {
int analogValue = analogRead(ANALOG_PIN);
Serial.println(analogValue);
delay(200);
}

Please note the pinMode INPUT_PULLUP instruction. This instruction must be used in the Control Box firmware as well. Going into its details now sounds a bit pointless to me but make sure to have a look here for more info about how it works.

If the firmware is working correctly you should read different values depending on the position of the switch. It should be either:

  • close to zero;
  • close to 10 bit (that’s the analog pin’s precision); therefore 1023;
  • a value in-between: due to how the circuit works and the fact that we have used two identical resistors, the value should be split in two equal parts; therefore int(1023/2)=512.

Unfortunately real life is not as perfect as life is in theory, so due to electrical noise, tolerances, temperature and interferences these values can change a bit. Therefore the easiest way to implement the code is a series of nested IFs instead of comparing a precise value.
resitors-vd-coding
The code looks simple and kinda rushed but works fine. For testing purposes you can toggle the Joystick output into the nested IFs but I have found that it degrades considerably the performance of the board. I guess it’s because the Box “bombards” the PC with Joystick outputs instead of sending them when there is an actual status change (my code does exactly that, as a matter of fact). Anyway, the case-switch construct is easy to use, does its job and it’s very intuitive to amend when friends with no coding experience want to play with my firmwares.
WARNING: justification/rant ahead! Note that we have plenty of memory available and the box doesn’t perform any real-time or timing-sensitive operation. If you have worked with single-resister 8-bit PICs you know what I mean..
/endrant

NOTE: I understand you are probably hating me for putting screenshots of the code instead of actual text but I absolutely hate how WP formats the code. I am using a free hosted versions, I haven’t found any decent plugin so far and I have no intention to pay for a full-feature hosted site. Please bear with me! 🙂

This is a picture of my Radio Box v2. The brownish board you see holds two Voltage dividers.
Radio Box - Version 2

Keep Delving!

As a last note, please google “Voltage Divider Arduino” or similar to find tons of info about how Voltage Dividers can be applied to Arduino. I’m sure you will also find solutions similar and probably better thought and explained than mine (I admit I relied a lot on trial-and-error; luckily I didn’t break anything 😛 ).
Another interesting subject is the PULLUP resistor. I just mentioned it here because its explanation is beyond of the scope of my site but I really suggest you to spend a few minutes and understand how it works. It will be very helpful later!

Radio Box v3 – Getting ready for the Tomcat!

The F-14 Tomcat is finally close to the release date (13/03, 9 days!) and I really can’t wait to fly one of the few FW modules that has really managed to capture my interest despite being myself primarily a RW pilot.

The F-14 is quite different from the F/A-18 and especially the Ka-50 (you don’t say??) and there’s a little detail that really buggers me: the Master Arm. You might have noticed in fact that the F-14 has a protective cover over the Master Arm that needs to be lifted before turning it on. Other aircraft, such as the aforementioned F/A-18 or the Ka-50 have no such thing. Having to interact with two entities (protective cover and Master Arm switch) means that four buttons are now required. Can you imagine how impractical would be having to push a button to lift the in-game cover then open the Control Box cover and finally toggle the physical switch? The solution, however, is very, very simple.

..1 ..2 ..3!

Three lines of code are enough to solve the issue. This solution is rough but works decently and proves how issues can be easily solved when we write our own code.
The following is the original code. It reads the value from a pin and toggles two Joystick outputs accordingly.

radio-box-3-original-code
Master Arm switch – Original Code

As you probably have already figured out, the easiest solution is to add two more toggles so each Joystick output can control a step of the toggling process.. and that’s exactly what I did. A not-so-minor detail though: the animation. Raising the cover takes a few milliseconds so we have to insert a delay. I am using 500ms at the moment and it works for the F-5E Tiger II.

radio-box-3-new-code
New Code for Master Arm + Cover. Note the delay.

How does it work? The original code was very simple: if the pin is HIGH then Button#2 is turned on and Button #3 is turned off. Therefore by assigning Button#2=Master Arm ON and Button#3=Master Arm OFF, toggling the physical switch has the effect of toggling the in-game Master Arm. Now we have two additional entities on top of Master Arm ON and Master Arm OFF: Cover UP and Cover DOWN.
This is how the Joystick outputs must be assigned in order to make it work:
Button#2: Cover UP
Button#3: Master Arm OFF
Button#23: Master Arm ON
Button#24: Cover DOWN

Why this order, you may ask? Quite simple actually: when the pin is set HIGH then Cover UP is activated while Master Arm OFF is deactivated (we’re about to turn the in-game Master Arm ON!). Therefore the cover is now lifted and after a few milliseconds the in-game Master Arm is activated. Cover DOWN is not needed and therefore turned off.
When we toggle the physical switch again the pin is set to LOW: Cover UP is deactivated and the Master Arm OFF is turned ON; ergo the in-game Master Arm is now off and after a few milliseconds the cover is lowered.
(NOTE: If you feel more confused after this explanation than before it’s normal. Feel free to rewind your mind and pretend that the previous paragraph doesn’t exist).

If you are wondering why I have used #23 and #24 the answer is easy: those buttons didn’t exist in the previous version of the Radio Box and I haven’t changed anything else, therefore I can load the previous configuration in DCS without being forced to remap the whole Box.

Improving the idea

There are a few issues with this implementation, namely the physical switch shouldn’t be toggled back before 500ms and the animation of a particular aircraft might take more (or less) than 500ms.
If I will have issues with the F-14 I will implement an asynchronous timer to control a predefined number repetition of Button#23 ON/OFF and Button#24 ON/OFF after a certain amount of time. The process will also be controlled by a flag that interrupts it in case I toggle the physical switch back.

I’m sure that are many other ways to improve this solution, use the one you prefer!

Arduino Pills – Be Flexible or Be DCS-BIOS

This is more a Showerthoght than an actual “Arduino pill” and it’s about HID vs DCS-BIOS. It’s potentially a quite long discussion but I will keep it as short as possible by pointing out the factor that, in my opinion, is the most important: flexibility.

By using HID (Human Interface Device) your control box is “seen” by the PC as any other game controller, allowing it to be used with almost any game (I managed to fly my ships in Star Citizen via the UFC, for instance). DCS-BIOS-based controllers instead use a bus to communicate with DCS and they work on just one module (not entirely true, see below). Therefore, if your intention is to use your Control Boxes with multiple games and modules then HID is probably your best option. It must be noted thought that HID is not supported by every Arduino board (at the moment) so if you need a specific feature not provided by Arduino Leonardo or similar, well, that can be a problem.

DCS-BIOS on the other hand provides an impressive interface between your device and DCS. By using DCS-BIOS you have access to the status of most of the avionics (in the form of numerical values), then what do to with those values is entirely up to the coder. For instance, I use DCS-BIOS to interface my TFT (Arduino Uno). A fellow 132nd Virtual Wing friend uses DCS-BIOS to bring the idea of building Control Boxes to next level. Have a look!

A quick note about DCS-BIOS and multiple modules: I did some tests and my TFT worked both for the Ka-50 and the Mi-8 at the same time. I implemented a number of checks in order to understand which module was running (reading a certain variable, for instance) and then by running only the routines needed for that particular module.
Unfortunately I later scrapped the Mi-8 code because I was running out of memory..

A quick look at the Firmware

The guide I wrote about building a F/A-18 UFC-like control box based on Arduino uses doens’t need any modification to the firmware hence no coding whatsoever: just get the firmware, load up the libraries and write it. I wrote about the steps required to set up Arduino here.

But what if you want to divert from the guide, maybe adding an encoder or two? Adjusting the wiring diagram is easy: starting from the now well-known diagram, you just need to resize the button matrix. Once the diagram has been adjusted, the soldering and testing is done, it’s time to code.

NOTE: if you are in a hurry or know what you are doing already, you can grab the firmwares from the Download page.

Coding is easy!

Especially when you don’t have to code at all! In fact, as long as only variables such as the pins involved and the size of button matrix and the encoders are changed, there’s really not much to do.
Here are the parts of code you need to update to match your wiring diagram.

Definitions

coding-code-extract-1a
#define defines (no s**t Sherlock!) a constant value. The names are quite self-explanatory. NUMROTARIES and NUMBUTTONS define how many buttons and rotary encoders are present in your control box. The size of the matrix is defined by NUMROWS and NUMCOLS. The original author has decided to use only 24 buttons though, hence why NUMBUTTONS!=NUMROWS*NUMCOLS.
So, e.g. let’s change the code in order to make it work for my Radio Box (6x encoders, 3×3 button matrix):
#define NUMROTARIES 6
#define NUMBUTTONS 9
#define NUMROWS 3
#define NUMCOLS 3

Quite simple, isn’t it?

Matrix Buttons

coding-code-extract-1b
This bi-dimensional array may look complicated but it’s actually very simple: this is where each physical button is associated to the joystick output. If you don’t care about having buttons in a particular order (I do not. At all.) you can assign buttons in any order you want.
Following the previous example, a 3×3 matrix will look like:
byte buttons[NUMROWS][NUMCOLS] = {
{0,1,2},
{3,4,5},
{6,7,8}
};

As I said, please note that you can put virtually any value there.

Rotary Encoders

coding-code-extract-2
The definition of the rotary encoders a slighly more complicated. In order to understand how they work we must first take a look at the struct that defines this bi-dimensional array:
struct rotariesdef {
byte pin1;
byte pin2;
int ccwchar;
int cwchar;
volatile unsigned char state;
};

The struct tells us that the values of the array mean:
pin1 and pin2 are self-explanatory: they are the pins where the encoders are physically attached (→soldered).
cwchar and ccwchar are the joystick values sent to the PC when the encoder is rotated clock-wise or counter clock-wise. For instance, if cwchar = 12, when you rotate the encoder CW, your computer will show that the button number 12 has been pressed.
state is a variable that doesn’t concern us. Live it be!

Our example (the Radio Box) uses 6 encoders, therefore the new array will look like this:

rotariesdef rotaries[NUMROTARIES] {
{0,1,9,10,0},
{2,3,11,12,0},
{4,5,13,14,0},
{6,7,15,16,0},
{8,9,17,18,0},
{10,16,19,20,0},
};

The Matrix

coding-code-extract-3
Easy stuff here, just tell Arduino which pins are part of the matrix.
The Radio Box uses a 3×3 matrix, therefore:
byte rowPins[NUMROWS] = {21,20,19};
byte colPins[NUMCOLS] = {18,15,14};

A last detail

coding-code-extract-4
This is the initialization of the Joystick. See that 32? That’s the total amount of buttons included in your control box. I know what you are thinking: the aren’t 32 buttons here! And you are indeed correct: in fact you can change to value to match the number of buttons in your Control box. As long as that number is bigger than your buttons it’s not a problem. Windows USB Game Controllers test will show 32 buttons when you plug-in your box but you will be able to use just a part of those. Different story if your box has more buttons than 32 (my aux box has 70 buttons, my UFC has 80). In this case you have to adjust the value to match (or being highter than) the number of buttons of your box or you won’t be able to use most of them.

Arduino control box: The Radio Box

This is the second control box I built almost one year ago and it’s still the box I use the most. Its job is to make pushing between frequencies a much easier task: the Ka-50 has two radio, the R-800L1 and the R-828; the former is tuned by operating four knobs, the latter requires one. Each knob can be rotated CW and CCW for a total of 10 functions, plus the “tune” button required on the R828. It’s quite a number of buttons and during a mission, when maintaining close formation, scanning for targets or avoiding obstacles going head-down on the radio panel to tune the correct frequency is definitely not something you want to do!

But why are radios so important? SP pilots probably rarely use their radio but in MP is different, especially when flying in a group that uses SRS or UR. Any training session or mission in the 132nd Virtual Wing has one or more human controllers. The R-828 is used for intra-flight comms, therefore is usually just once wheres the R-800L1 instead is tuned to:

  1. ATIS, for the latest information about weather and QNH;
  2. Ground, to check-in and requesting taxi to runway;
  3. Tower, for departure;
  4. Control, after departure, en-route towards the AO;
  5. Additional controllers, such as JTAC or AWACS.

As you can see, a dedicated control box starts making sense 🙂

Radio Box V1: Buttons matrix + encoders

The first version of the control box was very simple: the 6 encoders use a total of 12 pins. The remaining formed a 3×3 button matrix.
The second row of encoders sported the pushbutton function; top-left there were 2x 3-way momentary switches.
Radio Box - Version 1Radio Box - Version 1
The use was simple: top row of encoders for the R-800L1, bottom-right encoder for the R828 (push for tuning); bottom-left encoder for the Kneeboard (push for toggling visibility). The big round button centers the Track IR by sending a keyboard command and the others were used for controlling lights.

Radio Box V2: Latched 3-way switches

While I was planning my next control box I got stuck into the problem of latched 3-way switches. There are a number of ways to deal with the issue and I decided to use voltage dividers. Voltage diverders are a very easy solution with a number of applications; in our case they will allow our Arduino Board to understand the position of the 3-way switch by effecting the reading of the analog pins.
The concept is simple (I will write a dedicate Arduino Pill about it at some point): each end of the switch is connected to either GND or Vcc each through a resistor therefore the position of the lever changes the value read on the analog pin in an unique way (alright, let’s pretend noise doens’t exist for a moment). Code-wise, a simple series of cascading IFs will associate the value to the correct button and fire the appropriate Joystick.setButton() event.
As you can see, this approach is very simple and straight-forward but has a major flaw: the number of analog pins on a board is limited therefore if more than four 3-way latched switches are required, different solutions must be used.
Radio Box - Version 2
In this image you can see the small board hosting the four resistor required to control the 2x 3-way latched switches. I have also added 2-way latched switch and left the three remaining pins for the encoders’ pushbutton function and the Track IR. The final result can be seen in any picture of my updated setup.