Wireless controller with ATmega and NRF24L01

07/11/2018


What is this project all about?

Have you ever wondered why the keyboard layout in some games is so bad? Fear not, because with electronics you can build a custom controller and map the buttons to keystrokes. While we are at it, why not to make it wireless. Easy right?

Yeah, I really thought it would be easy. I planned to stick a NRF24L01+ to an Arduino with a battery, and same thing into the receiving end. These wireless modules are ridiculously cheap and cost like 0,70 EUR per piece. I used an Arduino Pro Mini (ATmega328P running at 8 MHz) as the controller and started thinking about the receiving side. I planned to use Arduino Leonardo as the receiver, because it has a built-in USB-HID and it can work as a keyboard, mouse or game controller. The only problem was that it didn't have SPI headers for the NRF24L01+ module. I found out that I could use the ISP header to provide the necessary SPI interface, but no matter how hard I tried I couldn't get it working.

The NRF24L01+ modules from China can range from bad to awful. Some of them work like a charm and some of them don't. Usually a capacitor between the VCC and GND is a really good idea. I prefer using around 10μF capacitor but the value isn't that important. Just get a steady supply of 3.3 v and you should be fine. Avoid long wires and use jumper wires ONLY IF YOU HAVE TO. It isn't worth debugging a circuit that has a loose wire and works only momentarily if you wiggle it. Go the hard way and solder it directly to the Arduino. (Only if you want obviously)

If you decide to use jumper cables I highly recommend crimping your own wires. Just get some male and female dupont connectors with the plastic housing and Bob's your uncle, you got your own custom cables. I found them to be way more reliable than ordering already built wires from China. Just remember to add the wires before crimping.


Update: 8/11/2018

I got the Arduino Leonardo working. The problem was just the bad wires. I crimped my own cables and it works like a charm. Now I just need to map the values to keystrokes. I might want to add a serial interface to change the mappings on the fly and then save them to the internal EEPROM. The only problem is that this board is huge. It would be better to use something smaller than the Arduino Leonardo.


Update: 9/11/2018

Now the code is fully functional. It maps the buttons to keystrokes and seems to be working just fine. 

We tested the controller system with this game:
https://www.twoplayergames.org/play/651-Sports_Heads_Football_2.html

The update rate should be around 100 Hz (at least it's the maximum). I haven't done any tests to prove it, but it seemed to be fast enough for gaming.

You can connect the Leonardo to the NRF24L01+ like this: (NRF24L01+ -> Arduino)

Vcc -> 3.3V
GND -> GND (pin 6 on the ISP header)
CE -> D7
CSN -> D8
MISO -> MISO (pin 1 on the ISP header)
MOSI -> MOSI (pin 4 on the ISP header)

I still need to figure out how to fit the electronics into the controller and receiver, but at least it's a working prototype in this stage.


Update: 10/11/2018

I designed a bigger chassis for the controller. Now I just need to print it, but my 3d printer is just plain awful. It sounds like a jet trying to take off with a broken engine. Also the quality of the prints is very bad. Only if I slow it down it will do "just fine" quality. Let's just hope it won't catch on fire.

Just finished printing the battery compartment to notice that it's too small. I added 4.6 mm more and let's hope for the best!

Thankfully the next version was a success. It's just a bit too tight and hard to assemble. If I had a smaller battery I would have used the first version. This new raised version is really big and bulgy


Update 11/11/2018

I got the code working with two controllers. I had some sort of problem with the addresses and used some addresses from an example code. It might affect the quality of the link if someone is nearby trying the example. But for now, it seems like I got the project sort of to the finish. It ain't perfect, but it works. The only problem being the frustrating assembly.


Summary

In this project I built a "game controller" that works like a programmable keyboard. You could also reprogram the receiver to send any kind of signals you would like.

Hardware:

- 2 pcs of Arduino Pro Mini (3.3 V! If you use the 5 V version you need to buy external 3.3 V regulator.)
- 2 pcs of NRF24L01+
- 2 pcs of Li-ion battery (Li-po works as well, but it's more dangerous. Just make sure that the battery has a protection circuit. Also use a battery that's in good condition. You don't want your hands to blow up.)
-3d printed parts
- 16 pcs of 20*20 mm buttons
-ISP programmer (I used the usbtinyisp) or serial adapter (FT232RL is very reliable)
- Arduino Leonardo (I would recommend the Arduino Pro Micro, but I don't own one and haven't tested it yet. At least it would be a lot smaller.)



Software:

Software for two controllers:

If you want to use two controllers, compile and program the controllers with the code in gamecontroller_dualcontroller folder. I prefer using Arduino IDE to compile and upload the files. Just remember to change the line n. 22 in the radioLink.ino. This is because you need different addresses for the controllers. Otherwise the packets would collide and nothing would work. This is the line you have to change:

radio.openWritingPipe(address[0]); //for the 1st controller use [0] and for the 2nd controller use [1] 

For the 1st controller use this:
radio.openWritingPipe(address[0]); 

And for the 2nd controller use this:
radio.openWritingPipe(address[1]);  

For the receiver just upload the gamecontroller_dual_receiver_w_keystrokes. If you want more power, replace the line 21 on the radioLink_receive.ino with this:
radio.setPALevel(RF24_PA_MAX);

If you have problems with uploading to the Arduino Leonardo, press the upload code and wait until the Arduino IDE starts scanning the serial ports. Then double click the reset button to force the Leonardo to the bootloader. That should work in most cases.

Software for only one controller:

If you want to use only one controller, upload gamecontroller.ino to the controller and gamecontroller_receiver_w_keystrokes.ino to the receiver.


You can find all of the codes from my GitHub.