11. Networking and Communications
Goals
Individual assignment:
- [x] design, build, and connect wired or wireless node(s) with network or bus addresses and local input &/or output device(s)
Group assignment:
- [x] send a message between two projects
Tools Used
- Blender - Free and opensource 3D software that can be used for anything from sculpting to animation and much more.
- Thonny
- ChatGPT
- CircuitPython
- Xiao-Fab
- NeoVim
TLDR; Nice images
Group Project
For this week’s group project we tested TXRX communication between two RP2040 boards.
Summary
The step by step can be found on the group site.
Individual Project
1. Further develop input devices using HID
Plan: The plan for this week is to further refine my input devices using the CircuitPython library HID
To date I have been using breadboards and rotary pot for my testing but I know the pots on my final project will be linear.
So I will be making a test module for my FabXiao for my linear potentiometers and refining my CircuitPython code using the CircuitPython library HID.
1.0 Ditching the breadboards
To date I have been using breadboards and rotary pot for my testing but I know the pots on my final project will be linear.
There are three problems with this;
- Breadboards are not very reliable and can be a pain to work with.
- My final project will be using linear potentiometers.
- The linear pots im using do not really fit on the breadboard I have.
Although I did try …
So to progress the code I jumped into fusion and put together a quick module for the FabXiao. Starting with downloading the foodprint from Digikey
1.1 Designing the new module.
The data sheet shows the numbered pins, power to pin one, data to pin two, and ground to pin three.
I have taken to making the rules for milling the PCB from the Fab Library and increasing the width of the traces and the spacing. I had some trouble early in fabacademy and this so far has been a reliable process for me. I had some trouble early in fabacademy and this so far has been a reliable process for me. I had some trouble early in fabacademy and this so far has been a reliable process for me.
The only slide pots I could find were through hole but I decided that it should be ok to modify them slightly to surface mount them.
So in the footprint editor in Fuision 360 I removed the through holes and added SMD pads
. Holding option
while moving the pads was a nice trick as it means you are not snapping to the grid.
I like to autoroute
the PCB for the first pass then move traces after to give feature more room to breath.
After exporting my pngs for the traces and the outline there didn’t seem to be a straightforward way in fusion to create an image for the holes.
So I used GIMP and the paint bucket tool
to fill in the holes and saved it as a new file for mods.
1.2 Milling and assembly
Milled the board as per previous weeks using mods and v-panal.
I used needle nose pliers to bend the pins to suit the SMD pads.
And soldered everything in place.
2 Programing my blender interface using HID and CircuitPython
My code to date has a few main problems.
- The movement of the pots is linear, so it is hard to make small precise movements.
- As im using keyboard input the can be jerkier than I would like.
This week I plan to address these issues in my movement script.
2.1 Starting point
import board # Import board module to access pin names
import analogio# Import analogio to work with analog inputs/outputs
import digitalio
import time # Import time module to handle delays
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
button = digitalio.DigitalInOut(board.D7) # Define button on pin D7
button.direction = digitalio.Direction.INPUT # Set as an input (reading data)
button.pull = digitalio.Pull.UP # Enable internal pull-up resistor (default HIGH)
# Variable to track previous button state
previous_state = button.value # Start by storing the initial button state
keyboard = Keyboard(usb_hid.devices)
pot_x = analogio.AnalogIn(board.A0)
pot_y = analogio.AnalogIn(board.A1)
pot_z = analogio.AnalogIn(board.A2)
center = 65535 // 2 # The center of the pot
neutral_zone = 10000 # Area on pot where there is no input
while True:
pot_value_x = pot_x.value
deviation_x = pot_value_x - center
pot_value_y = pot_y.value
deviation_y = pot_value_y - center
pot_value_z = pot_z.value
deviation_z = pot_value_z - center
current_state = button.value
if previous_state and not current_state:
keyboard.press(Keycode.HOME)
keyboard.press(Keycode.SHIFT, Keycode.C)
keyboard.release_all()
previous_state = current_state
print(pot_value_x)
if abs(deviation_x) > neutral_zone: #abs is removing negitave values
if deviation_x > 0:
keyboard.press(Keycode.KEYPAD_SIX)
print(pot_value_x)
else:
keyboard.press(Keycode.KEYPAD_FOUR)
print(pot_value_x)
else:
keyboard.release(Keycode.KEYPAD_SIX)
keyboard.release(Keycode.KEYPAD_FOUR)
print(pot_value_y)
if abs(deviation_y) > neutral_zone: #abs is removing negitave values
if deviation_y > 0:
keyboard.press(Keycode.KEYPAD_EIGHT)
print(pot_value_y)
else:
keyboard.press(Keycode.KEYPAD_TWO)
print(pot_value_y)
else:
keyboard.release(Keycode.KEYPAD_EIGHT)
keyboard.release(Keycode.KEYPAD_TWO)
print(pot_value_z)
if abs(deviation_z) > neutral_zone: #abs is removing negitave values
if deviation_z > 0:
keyboard.press(Keycode.KEYPAD_PLUS)
print(pot_value_z)
else:
keyboard.press(Keycode.KEYPAD_MINUS)
print(pot_value_z)
else:
keyboard.release(Keycode.KEYPAD_PLUS)
keyboard.release(Keycode.KEYPAD_MINUS)
time.sleep(0.001)
2.2 The HID
As I have mentioned in previous weeks the reason I switched over to CircuitPython from MicroPython is because of its HID libraries that allow me to send keystrokes to the computer via USB.
This is very well documented by Adafruit (here)[https://docs.circuitpython.org/en/latest/shared-bindings/usb_hid/index.html#usb_hid.devices]
The short description is that hid (Human Interface Device) allows the board to send data to the computer as a ‘device’, in our case we are using it to send keystrokes.
Inside the library the we have access to ‘keyboard’ and ‘mouse’ modules that allow us to emulate these inputs when we use our board. In the case of the program above we are sending a keypress every time the main loop completes when the potentiometer readings are within a certain range.
The below piece of code is added to the top of the file to import the necessary libraries
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
2.3 The basic idea
Lets run through a bit if the logic;
pot_x = analogio.AnalogIn(board.A0)
This reads in the analog values from pin A0, and converts them to int values between 0 and 65535.
center = 65535 // 2 # The center of the pot
This defines a variable called center which defines the center of the slide pot.
neutral_zone = 10000 # Area around the center of the pot where there is no input
This defines a variable called neutral_zone which defines the area around the center of the pot where there is no input.
while True:
Opens up our main program loop that will run forever
pot_value_x = pot_x.value
This defines a variable called pot_value_x which stores the value of the potentiometer.
deviation_x = pot_value_x - center
This defines a variable called deviation_x which stores the current value of the pot minus the center value. This is useful as later we can use this with the absolute function to give us a value that is always positive.
if abs(deviation_x) > neutral_zone: #abs is removing negitave values
Create an If statement that checks if the absolute value of deviation_x is greater than neutral_zone. If it is we can then call this our ‘positive direction’ and call the following
keyboard.press(Keycode.KEYPAD_SIX)
This uses the parts of the HID library to send a keypress event to the computer. In this case we are sending the hotkey to orbit clockwise in Blender.
else:
keyboard.press(Keycode.KEYPAD_FOUR)
This uses the parts of the HID library to send a keypress event to the computer. In this case we are sending the hotkey to orbit counter-clockwise in Blender.
keyboard.release_all()
After we have pressed the key we need to release it so that it doesn’t keep sending the keypress event.
time.sleep(0.001)
This asks the loop to sleep for 0.001 seconds before running again.
2.4 Demo Video
In Summary
Being able to start to implement the components that will be used in the final project is a big step forward for the project.
However, the ‘feel’ of the input is not good yet. So while we are making progress, the software side still requires a lot of work.
Things I would do differently next time
Back to top Overall I feel like most steps I made this week were necessary so im not sure I would do anything differently next time.
However, there is always more I could have done. For example I have spent a lot of time using the rotational axis in my test code but ultimately this will actually be done with an encoder rather than a pot.
The work will still transfer to the linier axis but I should have spent more time on panning and zooming rather than just orbiting.
See below link to to files created this week: