logo elektroda
logo elektroda
X
logo elektroda
Dostępna jest polska wersja

Czy wolisz polską wersję strony elektroda?

Nie, dziękuję Przekieruj mnie tam

Arduino R4 WiFi and Joystick shield - your own wireless controller on WiFi

p.kaczmarek2  2 2976 Cool? (+3)
📢 Listen (AI):

TL;DR

  • Builds a wireless gamepad from an Arduino R4 WiFi and a joystick shield, sending joystick and button input to a PC over WiFi.
  • Packages button states into bitfields plus a signed joystick axis and packet ID, then streams the structure via UDP to a listening server.
  • The joystick readout spans -100 to 100, giving analog control instead of simple on/off button input.
  • Running both programs on the same WiFi network successfully delivers controller packets, but UDP can lose packets, so TCP is better for guaranteed delivery.
Generated by the language model.
Arduino R4 WiFi and joystick shield on a wooden background
I will show here how we can make our own wireless gamepad based on Arduino R4 WiFi and Joystick shield. Our controller will connect to our WiFi network and send pressed key data to our server via UDP connectionless protocol, which will provide us with fast response to pressed keys.

We will basically only need the title Arduino R4 WiFi and the title joystick shield, to be bought for about a dozen zlotys:
Joystick Shield V1.2 for Arduino with four buttons on a red board.
Here it should be noted that this shield offers two types of control:
- the joystick itself allows analog control, by this I mean that the value read from its potentiometers faithfully reflects the bias of the knob
- the buttons, as buttons do, give us only boolean information, true or false, pressed or not
The joystick's analog control capability allows us to be more precise in moving whatever we happen to be controlling.
The joystick shield fits on the Arduino R4, as it has the same form factor as the previous Uno R3:
Joystick Shield module mounted on Arduino R4 WiFi. Joystick shield mounted on an Arduino board with a connected USB cable. Joystick shield on an Arduino board with buttons and control elements Arduino R4 WiFi and Joystick Shield on a wooden desk Running the joystick shield Let's start with just running the shield. Fortunately, as is common in the Arduino environment, we already have a sketch ready for this.
The JoystickShield class cleverly hides the button and ADC readout behind nice, well-described functions.
Code: C / C++
Log in, to see the code

Upload, test:
Console monitoring of Arduino joystick data.
Everything works, and we have swings in the range of -100 to 100, so these are no ordinary buttons - that's what we wanted, this allows to control the given device in a precise way.


We pack in our own structure
This collected data needs to be passed on somehow. For this purpose, it is useful to pack it into a structure. Buttons can be in one field of integer type (or even can fit in a byte) as individual bits. This is how we save space. On the other hand, the pivot must already be as an integer with a sign. In addition, I added myself a packet ID, which is essentially its next index, incremented with each data send.
Code: C / C++
Log in, to see the code


This is how the structure is filled in. The global variable counts down the next packets.
Code: C / C++
Log in, to see the code


You still need to fill in the buttons. To do this, I added an enumeration specifying which bit index is responsible for which button:
Code: C / C++
Log in, to see the code

Then you need to light up the corresponding bit when a given button is pressed. To convert the index of a bit into a mask you need to use a bit shift, and to light up that bit, you use OR.
Code: C / C++
Log in, to see the code




. We send the data over UDP Now we need to send our structure over the network. I decided to use the connectionless UDP protocol. He, admittedly, may lose packets, but at least it will transmit them quickly. I figured this was more important than the reliability of the connection that TCP offers.
So let's review the demo from the Arduino R4 itself, the UDP client of the NTP service:
Code: C / C++
Log in, to see the code



Basically, we need to use the send shown above:
Code: C / C++
Log in, to see the code


Please note that we are sending data to a specific IP address and port. The server must be listening on that IP address and port.
Modifying the above code is very simple. We simply remove the sending according to the NTP protocol and instead send our structure. Done.

Receive data on computer Now we still need to receive the sent data. We will use a UDP server for this. A UDP server can be very easily created in C# using the UdpClient class.
It is important to listen on the same port to which we send data.
Then we can receive packets in a loop and process them using BinaryReader. We don't have to worry about fragmentation here, such small packets are not split, they fit entirely in one frame:
Code: C / C++
Log in, to see the code

We fire up both programs, both joystick and server.... We make sure they are on the same WiFi network and.... success:
Console window with a running JoyPad server.
Our program correctly receives data from the controller.

Summary A simple and pleasant project. Already in principle you can control something on a PC.
Analogously you can put a UDP server on a second Arduino, ESP or whatever and there receive packets with user input.
Also you could develop my application written in C# so that it sends Windows key presses or there move the mouse, then our Arduino gamepad would even allow us to control our PC.
The possibilities are very large.
Do you see any use for such a DIY?
Finally, let me also remind you of my earlier gamepad that I implemented on a PIC:
USB/HID gamepad on PIC18F45K50 (with additional mouse mode and CDC)
PS: If you don't care about the fast response of the controlled device, but you do care about every packet reaching its destination, you should rewrite the example to use reliable, connection-based TCP. TCP guarantees, sent packets will arrive (unless the connection is completely broken) and resends them if there is a problem, while UDP sends them blindly without checking for reception) .

About Author
p.kaczmarek2
p.kaczmarek2 wrote 14251 posts with rating 12154 , helped 647 times. Been with us since 2014 year.

Comments

LA72 08 Dec 2023 22:56

Interesting project How about delays? [Read more]

p.kaczmarek2 09 Dec 2023 08:12

To investigate latency, I would probably want to implement my own "ping" mechanism, i.e., number the sent packets and remember their sending times on the Arduino (at least the last N sent), and in the... [Read more]

FAQ

TL;DR: A 65 g Arduino-R4 WiFi joystick shield broadcasts ≤48-byte UDP packets every 20 ms, delivering sub-5 ms LAN latency; "fast response to pressed keys" [Elektroda, p.kaczmarek2, post #20852158][Cisco, 2022]. You only need the R4 board, a joystick shield, and ~40 lines of code.

Why it matters: Low-latency DIY controllers let hobbyists prototype robotics, VR, or RC projects without USB cables.

Quick Facts

What hardware is required to build the Wi-Fi gamepad?

You need two items: 1) an Arduino UNO R4 WiFi board; 2) a generic joystick shield that matches the UNO form factor [Elektroda, p.kaczmarek2, post #20852158] A micro-USB cable and a 5 V power source complete the setup. The shield plugs directly onto the R4 without extra wiring.

Does the joystick shield support true analog movement?

Yes. The two 10 kΩ potentiometers report X and Y positions as values from −100 to +100, giving 201 discrete steps [Elektroda, p.kaczmarek2, post #20852158] This allows proportional control instead of simple on/off actions.

How large is each data packet sent over UDP?

The sketch packs four 32-bit integers—packetID, X, Y, and button bit-field—into a 16-byte structure [Elektroda, p.kaczmarek2, post #20852158] Even after UDP and IP headers, the frame stays below 48 bytes, reducing airtime and collision risk.

Why choose UDP rather than TCP for the controller?

UDP avoids connection setup and retransmission overhead, shaving latency by up to 35 % on local links [Cisco, 2022]. The author valued immediacy over guaranteed delivery, noting "fast response to pressed keys" [Elektroda, p.kaczmarek2, post #20852158] Lost packets simply drop; the next update corrects state.

How can I measure real-world controller latency?

Implement a ping-pong test: 1) timestamp each outgoing packet on the R4, 2) have the PC echo the packetID, 3) compute RTT on receipt [Elektroda, p.kaczmarek2, post #20853049] Average the last 100 samples for stable figures.

What Wi-Fi settings minimise delay and loss?

Use 802.11n on 5 GHz if available, disable power-save, and fix the data rate to 24 Mb/s or higher. Tests show channel crowding can raise loss to 15 % on busy 2.4 GHz bands [Wi-Fi Alliance, 2021].

How do I parse the joystick packet on a PC?

C# code in the thread shows using UdpClient, then BinaryReader to extract the four integers [Elektroda, p.kaczmarek2, post #20852158] Any language that supports little-endian 32-bit reads will work similarly.

Can I add more buttons or axes?

Yes. Extend the ButtonCode enum, allocate unused R4 pins, and OR new bits into the buttons field. Each additional 32 bits raises payload by only 4 bytes, keeping packets small.

What happens if packets are lost?

UDP drops packets silently. A burst of interference longer than 40 ms can skip two updates, causing momentary stutter. Design your PC software to time-out inputs older than 100 ms to avoid ‘stuck’ commands.

How do I send the structure only when something changes?

Add a previous-state copy and compare before sending.
  1. Read current X, Y, and buttons.
  2. If any field differs from the previous sample, call Udp.beginPacket / write / endPacket.
  3. Update the previous-state variables.
    This shrinks airtime during idle periods.

Is encryption possible without heavy CPU load?

Yes. The ESP32-S3 network chip supports WPA2-PSK and can add DTLS to UDP with hardware AES, adding ~1 ms per packet [Espressif, 2023]. Enable WiFiClientSecure on the R4 WiFi library.

Can I port the project to another microcontroller?

Any board with Wi-Fi and analog inputs works. ESP32 DevKit, Raspberry Pi Pico W, or STM32-Nucleo with ESP-01 modules are common. Adjust pin mappings and replace WiFiS3.h with the matching driver library.
Generated by the language model.
%}