One of the best things about the Raspberry Pi is its GPIO pins. They’re just sitting there, waiting to be connected to all kinds of interesting peripherals so your Pi can interact with the world around it. We can send alerts, attach sensors, and even plug cards like the Sense HAT over top of the pins to do even more.
A few months ago, I bought a set of 37 sensor modules. I knew they wouldn’t directly interface with the Pi, but that it was entirely possible to do it, so they were set aside for later. Well, it’s time to try one out, and I figure the mini-joystick might offer some interesting opportunities!
Materials
There are a few things we need first:
- Raspberry Pi Starter Kit
A decent starter kit includes the Pi, adapter, memory card, case, breadboard and cobbler, wires and LEDs, etc. - Long Breadboard
Some of the kits come with a shorter breadboard, but a longer board gives us more space to work, allowing for more wires, LEDs, switches, etc. - Kuman 37 Sensor Module Kit for Arduino
That’s the one I got, but I’m sure there’s plenty of similar ones. Mine came with a joystick control (which I used for this post), and a load of other sensors and input devices. There was no documentation, but I found a link to (somewhat sparse) instructions for each module on Amazon. - Male to female jumper wires
We need wires to connect the joystick to the breadboard. - Adafruit MCP3008 – 8-Channel 10-Bit ADC With SPI Interface [ADA856]
A tiny chip that bridges the gap between an analog control and the Pi. It’s cheaper directly from Adafruit, but watch out for shipping. If you’re buying several instead of just one like me, consider Adafruit’s site. Here’s the datasheet.
Interfacing with Analog Controls
The joystick is an analog control, consisting of two potentiometers that send a variable voltage depending on the position of the joystick (here’s a video that shows how they work), and it won’t just connect directly to the GPIO pins on the Pi. If your joystick can be pressed down like mine can, then that bonus button just has an on/off state and can be connected directly to any regular GPIO pin. But I’ll wire it up same as the potentiometers, since that’s what the articles linked below do as well.
To get it to work, we need to learn a little about the SPI bus protocol and how to enable it on the Pi, then how to wire up a small chip that uses SPI to bridge the gap between analog controls and the Pi. Fortunately, there’s a set of helpful tutorials on the Raspberry Pi Spy website, which I’d suggest checking out:
- Enabling The SPI Interface On The Raspberry Pi
- Using A Joystick On The Raspberry Pi Using An MCP3008
- Analogue Sensors On The Raspberry Pi Using An MCP3008
The first link shows how to enable the Serial Peripheral Interface (SPI) bus on certain GPIO pins. Method 1 worked fine for me – just open up a config screen in Raspbian and select the SPI option.
The second link walks through wiring up the MCP3008 chip, providing the bridge between the joystick and Pi. The third link isn’t necessary, but it’s got some helpful info in it that’s not in the other one. I suggest reading both.
Also, for changing colors on an RGB LED, it may help to read about pulse-width modulation (PWM).
Here are some pictures and a diagram of my setup, although the author of the linked articles provides a good set of pics too. There’s some additional stuff in my circuit that’s not in his, namely the RGB LED and resistors/wires to make it work. I used a 100Ω resistor for red and 220Ω for green and blue, same as here.
Fritzing Diagram
If you’d like, you can download the original Fritzing file and play around with it.
Reading Input
You should’ve already verified that Python Spidev (pi-spydev) was installed after you enabled SPI. We’ll need that for reading input from the analog device.
Since I’ve been messing with an RGB LED lately, I thought it’d be interesting to map the position of the joystick to the RGB color wheel and then light up the LED appropriately. Imagine the X-axis running horizontal above Blue and Green, and the Y-axis running vertical through Red and Cyan.
Here’s the code in its entirety:
|
|
I wrote the adjust_angle_for_perspective_of_current_led
function to make calculations easier. Imagine a 360 degree circle overlaying the color wheel. Each color (red, blue, green) is separated by 120 degrees. So if red is at 90 (the top), then blue is at 210 and green is at 330. That function rotates the imaginary circle, placing the LED we’re concerned about at 0 degrees.
The is_joystick_near_center
function was necessary because the joystick is not that accurate. Even when it’s sitting still, the readings coming off it fluctuate a bit. That’s not a huge deal when the joystick is positioned far away from the center, but imagine what happens when the position is near center and the X and Y coordinates keep jumping around the vertex of our “angle”. The angle varies wildly, so that when the joystick is “at rest”, the color flickers all over the place on the LED. So instead, I just display white if you’re near center.
If you clone the repo, you’ll see a separate file with tests in it. To run the tests in this project, first install the DDT (Data-Driven Tests) package for Python unit testing via pip.
See it in Action
You can see it in action here.
If you have a question about any of the code, leave a comment below and I’ll try to clarify. There’s one tricky piece in the read_spi_data_channel()
function, and that’s the call to spi.xfer2()
. Suffice to say, that’s the pi-spydev module doing work.
If you want, check out the spidev_module.c file and do a search for “xfer2″. It’s roughly 100 lines of C code.