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.

Advertisements

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.

Arduino Pills – Setting up IDE and Libraries

Another quick pill about Arduino, this is about setting up the IDE and manage libraries.

Arduino IDE (Integrated Development Environment) is not as advanced as other solutions but it’s quite light and easy to use. It can be found here.

Once installed, you might want to change the default sketchbook location by opening File→Preferences.
Now download, save and open a source file, for instance the one we are using in the Step by Step guide (it can be found here on AM-STUDIO’s GitHub) then compile it. You will get a number of errors, let’s review them.

Libraries

Libraries are, simply put, a collection of methods and functions that tell the board how to perform certain tasks. The default package contains only a little fraction of the available libraries, not to mention the fact that you can write your own. The “Joystick” library, that our project requires, does not come by default so we have to install it in a specific location. That location is the “libraries” subfolder of the aforementioned default sketchbook location.

arduino-pills-2-libraries
“libraries” subfolder location

Let’s download the Joystick library from GitHub and install it.
Careful though to respect the order of the subfolders: the ZIP file comes with a folder called “ArduinoJoystickLibrary-master”; if you copy this folder in your libraries your project won’t compile. So:

  1. open the ZIP file;
  2. open the “ArduinoJoystickLibrary-master” folder;
  3. copy the “Joystick” folder;
  4. Paste it into your Arduino “libraries” folder.

A couple of friends had to install the “keypad” folder as well. This library can be installed in a different and faster way. Go to Sketchβ†’Include Libraryβ†’Manage Libraries and look for “keypad”. Scroll until you find the library I have selected in the following screenshot and install it.

arduino-pills-2-keypad-library
Installation of the Keypad library

Lord of the boards

Last step is selecting the correct board and the relative port. Depending on which board you have bought, select either “Arduino Leonardo” or “Arduino/Genuino Micro” from the Toolsβ†’Board: “xyz”. Then, in a similar way, select the correct port from the “Port” menu: Toolsβ†’Port: “xyz”.
Both entries report the last option selected.

Quick troubleshooting

Always try to isolate the issue. Since we are using a source code that definitely work you should fairly easily found the issue, at this stage is either a library problem or missing or a connectivy issue. The IDE suggests you where the problem is. The following, for instance, is caused by the selection of an incorrect Port.

arduino-pills-2-error
Arduino uploading error: wrong port selected

Arduino Control Box: a Step by Step Guide – Part 6 – Release the Solderer!

“Solderer” – Is that even English? Not sure.. I’ve just seen the release trailer for the Kraken in Star Citizen and I got carried away..


Anyway, part 5 ended with every component allocated and screwed in its location. Now it’s time to replicate the wiring diagram into reality.

SbS_6-soldering-control-column

Soldering the wires is not difficult at all, it’s just a matter of practice. Here are a couple advices that might help you:

  • Don’t overheat! don’t leave the soldering iron in contact with wires and components for too long. You can melt the plastics of both the components and the wires.
  • Leave the Arduino board for last. Especially if you are not used to solder, it might happen to drop drops of melted solder wire. If one of them falls on the board, it might cause severe damages to it.
  • Place the wires first. Most of the components have a small hole on their pins. You can usually place your wire there before soldering it.
  • Pre-solder wires and contacts of any component that haven’t the aforementioned hole. By doing that you will need to hold your wire with one hand, the soldering iron with the other and that’s it: the solder material is already in place.
    To pre-solder just place the iron and the solder in contact with the uncovered core of a wire. You will notice that it will be quickly covered by the solder; making your life much, much easier.
  • Clean your soldering iron every now and then. Solder and antioxidant might accumulate on the iron after a while (they usually form a black mass). Hold the soldering iron tight with your hand, make sure there’s nothing in the area underlying the iron and hit your table with your fist: the burnt material will drop from the soldering iron. Nice and easy.
  • Save your furniture! Melted solder and the iron itself are hot, easily more than 300+ deg C. Although the solder becomes cold in milliseconds, it can still damage your furniture. Place some cardboard or do your soldering on an appropriate surface. You will thank me when your wife won’t kill you for damaging her precious table πŸ˜‰
  • If you have to connect a wire where another one is already soldered, add some solder and pre-solder the new wire. The new material will help spreading the heat.
  • Same as the previous point, if you do a mistake and can’t remove a soldered wire, add some solder: it may sound unintuitive but it helps spreading the heat uniformly.

That being said, this phase is quite straightforward as long as you follow a plan. I usually follow the same order I adopt when designing the wiring diagram; therefore I start from the wire that comes from the top pin of the board (although the board is always my last step) then proceed with every common connection such as GND. When the matrix is completed I then solder the encoders.

SbS_6-soldering-ufc

After completing the soldering of the circuit we can proceed and perform a quick test the continuity of GND, lines and buses by means of a multimeter. Do this check before connecting the board to the USB. The board is protected and we are working with low tensions but you know, better safe than sorry.
If the test doesn’t show any issue we can plug the board, load up Arduino IDE and write our firmware.

Arduino Control Box: a Step by Step Guide – Part 5 – Drilling time!

Part V of the guide, we’re almost there: the wiring diagram is ready, we have our buttons and encoders and we have our box. Before starting the assembling phase, let’s review some of the tools that might come handy.

Drill driver: I have an old DeWalt cordless drill driver, it holds drill bits max Ø10mm. It does the job.
Drill bits: I used to build model for WH40k years ago and I have a 1-5mm set. I have bought another cheap set, max Ø10mm. I recommend two sizes: a small one, to prepare a guide for wider holes (2-3mm will do, whatever you have in your garage). Most of the smaller buttons I have found have a diameter of 5-6mm so a second drill bit of that size will come handy.
Cone drill bits: I have bought a cheap set only recently and damn, they make your life so much easier. Since we will be working mostly with plastic, even quite cheap sets work like a charm.
Countersink drill bit: optional. Before buying the Cone bits I used this tool to make holes wide enough to host some particularly wide buttons. It comes handy when dealing with unusual diameters or to “clean” the hole instead of using sandpaper.
Caliper: the real man best friend πŸ™‚ Simply a must have; you need one.
Thin permanent marker: you can decided to either mark the points to drill with a marker or cut them into the plastic. It’s up to you, I personally do both.
Multimeter: a must have for debugging the wiring. Unless you have done everything perfectly and I bow to you πŸ™‚

Mirror mirror

IMPORTANT! We will drill on the internal part of the enclosure. Therefore, when planning and defining the position of the holes, remember that our wiring diagram is the specular image of what we actually need.
The easiest solution is to paste the image in GIMP and flip it.

Marking time

Get the wiring diagram on your PC and calculate the distances between the borders or the box and the centre of the buttons. I’ve found that drawing a reference matrix is actually easier. If you are using LibreOffice Draw, this operation will take just a few minutes and will be also very precise if you have draw your components and the box in 1:1 scale.

Now get the cover of the enclosure and the calipre. Measure the distances between the borders of the box, both vertically and horizontally and mark the points where your components will be placed with the marker. Proceed until every button of your UFC has is respective dot on the cover. For sake of clarity and to avoid confusion, you can write the expected diameter of every hole near every reference dot.

This is a detail of my Auxiliary Box. As you can see, the marks and cuts are clearly visible inside the enclosure cover (green arrows).

SbS_5-enclosure-cover-cuts
Reference marks and cuts inside the enclosure cover

Once every reference is marked, it’s time to start drilling. I usually start with a drill bit of very small diameter, then enlarge it depending on the final diameter required. This is a fairly quick operation, assuming every button is Ø12mm, you can start with the 2mm drill, check that the hole is exactly where you want it then use any other drill to make the hole wider enough to use the Cone drill bit. The Cone drill bit cuts throught the plastic very easily so pay attention and avoid making an excessively large hole.

When everything is done, get your buttons and encoders, place them in their slots and clamp screws and nuts and check the result.
SbS_5-bolts-and-nuts
Don’t put the encoders knobs in place, you risk unnecessary scratches.

Some buttons won’t be perfectly aligned but remember we are not using a CNC or any very precise tool. Small errors and imperfections might occur.

The manual part is almost over. Next step is soldering and then, finally, my favourite part: coding!

PS: it may sounds taken for granted but remeber to drill a hole for the USB cable πŸ™‚

Arduino Control Box: a Step by Step Guide – Part 4 – Wiring Diagram II

I have decided to split the chapter about the Wiring Diagram to ease the reading of the guide.

Wiring Diagram

IMPORTANT NOTE: there’s an almost infinite amount of ways to wire a button matrix, mine is just one of them. I usually start from the top pin then proceed vertically. If you prefer any other order, go for it!
less important note: the order of the buttons might be a bit wonky, unless amended via code. I personally don’t care at all about it: we will assign controls in DCS by pressing a button, not by selecting it from a combo box or something like that.

SbS_4-diagram-wiring-full

Too messy? Let’s clean the diagram and analyse it step by step.
I usually separate the wires into vertical and horizontal. The fact that I start from the vertical wires is clearly reflected on the wiring diagram.


The task of the horizontal wires – I usually refer to them as buses; whereas I call the vertical as lines – is to link the vertical wires and intuitively you can understand why their path is much more complex. In other words, each bus has to “touch” every line, one per colour and only once, with just one noticeable exception.

A 3-way Conundrum

A 3-way switch has three pins. How come? If you google 3-way switch diagram (←sorry) you find plenty of explanations from the electrical point of view. From the button matrix PoV instead, a 3-way switch is a combination of two buttons. The common pin is normally the middle one and it should be wired to a bus, whereas the top and bottom pins should be wired to two different lines.
When the bus is wired to the middle pin it is de facto connecting two different lines in one go: the switch basically counts as two; that’s why the red, blue and yellow buses connect a total of four physical switches, whereas the grey and the green connect five buttons.

Still having issue? Take a look at this pic:
SbS_4-diagram-wiring-3-way
In this application, there is no difference between a single 3-way momentary switch and the two pushbuttons. This image also makes even more clear how a single bus manages to connect two lines.
We can, therefore, replace the 3×3-way switches with 6x pushbuttons:

SbS_4-diagram-wiring-3-way-swap
6x pushbuttons as 3×3-way momentary switches

Encoders: the Easy Part

Encoders are the easiest part. They come with 3 pins (as we have already seen, the two separated pins are the pushbutton): mid is the GND, the others two go in the order you prefer, straight to the the Arduino board.

SbS_4-diagram-wiring-encoders
Wiring Diagram – Encoders

Any GND pin can be used, so pick the one that makes your life easier πŸ™‚

If everything is clear – drop a message here or ED’s forum otherwise – we can move on and start the dirty, manual part: drilling and soldering.

Arduino Pills – Change USB HID names

When multiple control boxes are connected they all come with the same name. In theory that’s not a big issue but I have noticed that DCS sometimes messes up. There must be a way to fix this situation, isn’t it?

A-firm, the solutions is quite simple: we just need to change a couple lines in the boards.txt file, then recompile and write the code.

My Kingdom for a Board!

boards.txt is a sneaky file though because it’s located in multiple folders. The one we are aiming for (and it should work for you as well) is located in AppData.

As of now, the path is:
C:\Users\USERNAME\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21
If the path doesn’t exist start from AppData and walk your wait down to boards.txt.

arduino-pills-vid_pid
boards.txt Path

Open boards.txt and locate this three fields:

leonardo.build.vid
leonardo.build.pid
leonardo.build.usb_product

These are the values we want to change. These, for instance, are mine:

arduino-pills-1-boardstxt
vid, pid and product from boards.txt

If you are using a Genuino Micro instead of Arduino Leonardo (it’s still based on the ATmega32u4), the values you need to change are different. These are from my Radio box, for instance:

micro.build.vid=0x1212
micro.build.pid=0x3434
micro.build.usb_product="K Radio Panel"

If you are wondering where I got my VID and PID values well, I’ve blatantly invented them. IIRC for commercial applications you should buy them; I guess they work as the MAC address. It’s not a problem for us since we are working on simple, personal, project.