A Board Capable of Python and USB Joystick HID?

This is a special forum devoted to educators using Adafruit and Arduino products for teaching.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
MrRSquared
 
Posts: 14
Joined: Fri Sep 20, 2019 9:48 am

A Board Capable of Python and USB Joystick HID?

Post by MrRSquared »

Hello,
I mentor an FRC robotics team (6762, The Oscats). One of our off-season projects is to make a custom controller. To be FRC legal, it needs to be wired to a Windows PC. We have some Cypress boards, which are a bit difficult for our programmers to get running. So, we are looking for something else that can be programmed with Python. Does anyone have any recommendations? At the moment, it would be nice if it were capable of at least two analog inputs, a few digital, and PWM outputs to run a rumble motor or two.
Thank you for all you bring to the robotics community.
~Mr. R^2

User avatar
mikeysklar
 
Posts: 13823
Joined: Mon Aug 01, 2016 8:10 pm

Re: A Board Capable of Python and USB Joystick HID?

Post by mikeysklar »

All the popular chips such as the M4, ESP32, RP2040 and nRF52 that Adafruit offers can run CircuitPython with USB GAMEPAD HID (which contains a joystick parameter). Maybe start with a Feather RP2040 since you didn't mention a need for WiFi or BLE. There are two guides to checkout:

https://learn.adafruit.com/customizing- ... id-devices
https://learn.adafruit.com/custom-hid-d ... cuitpython

User avatar
MrRSquared
 
Posts: 14
Joined: Fri Sep 20, 2019 9:48 am

Re: A Board Capable of Python and USB Joystick HID?

Post by MrRSquared »

Hello,
Sorry for the delay. The end of the school year is always quite crazy.
Thank you for this recommendation. We have some esp32s, so I think we will begin with that. This is incredibly helpful.

User avatar
Lekofraggle
 
Posts: 23
Joined: Thu Jun 21, 2018 2:50 pm

Re: A Board Capable of Python and USB Joystick HID?

Post by Lekofraggle »

Hello,
Thank you again for your help.
Our school year is over, and I have a bit of time to play with this. We decided to take your recommendation and begin with a Pi Pico (the feather version is out of stock, so we did the normal one). As you surmised, we do not need wifi because wireless comms are not allowed at our events (thought we may switch to wireless for outreach events).

I looked at the tutorials, and the samples. I can get the normal HID examples to work (mouse and keyboard), but I am lost at the gamepad.

It seems the tutorials posted above need three software components (I assume all live on the pico).
1) main.py (code.py would work, but linting complains about overriding base modules, which is understandable) This is the interpreter of the analog stick(s) and button IO.
2) boot.py sends the messages from the device to the OS
3) a driver (hid_gamepad).

I am stuck with 3. int he tutorial is just this line.
You will also need to write a CircuitPython driver to handle your new device. There are examples in the adafruit_hid library.
If I click the link to the examples page, it sends me here. It is confusing because the only drivers for devices that do not need a boot.py
I assume the driver is an interpreter between the boot and the main, but I am not certain. I found some old example code, but none mention a driver.

Am I reading things correctly, or is there another piece I am missing?
If I am reading things correctly, are there any tutorials for writing a CircuitPython driver?
The sample I would like to start with is here. There is a more complex example in the same folder, but I cannot get it to work either.

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

# You must add a gamepad HID device inside your boot.py file
# in order to use this example.
# See this Learn Guide for details:
# https://learn.adafruit.com/customizing-usb-devices-in-circuitpython/hid-devices#custom-hid-devices-3096614-9

import board
import digitalio
import analogio
import usb_hid

from hid_gamepad import Gamepad #I cannot find this import.

gp = Gamepad(usb_hid.devices)

# Create some buttons. The physical buttons are connected
# to ground on one side and these and these pins on the other.
button_pins = (board.D2, board.D3, board.D4, board.D5)

# Map the buttons to button numbers on the Gamepad.
# gamepad_buttons[i] will send that button number when buttons[i]
# is pushed.
gamepad_buttons = (1, 2, 8, 15)

buttons = [digitalio.DigitalInOut(pin) for pin in button_pins]
for button in buttons:
    button.direction = digitalio.Direction.INPUT
    button.pull = digitalio.Pull.UP

# Connect an analog two-axis joystick to A4 and A5.
ax = analogio.AnalogIn(board.A4)
ay = analogio.AnalogIn(board.A5)


# Equivalent of Arduino's map() function.
def range_map(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min


while True:
    # Buttons are grounded when pressed (.value = False).
    for i, button in enumerate(buttons):
        gamepad_button_num = gamepad_buttons[i]
        if button.value:
            gp.release_buttons(gamepad_button_num)
            print(" release", gamepad_button_num, end="")
        else:
            gp.press_buttons(gamepad_button_num)
            print(" press", gamepad_button_num, end="")

    # Convert range[0, 65535] to -127 to 127
    gp.move_joysticks(
        x=range_map(ax.value, 0, 65535, -127, 127),
        y=range_map(ay.value, 0, 65535, -127, 127),
    )
    print(" x", ax.value, "y", ay.value)
Here is the sample boot.py I am using.

Code: Select all

import usb_hid

# This is only one example of a gamepad descriptor, and may not suit your needs.
GAMEPAD_REPORT_DESCRIPTOR = bytes((
    0x05, 0x01,  # Usage Page (Generic Desktop Ctrls)
    0x09, 0x05,  # Usage (Game Pad)
    0xA1, 0x01,  # Collection (Application)
    0x85, 0x04,  #   Report ID (4)
    0x05, 0x09,  #   Usage Page (Button)
    0x19, 0x01,  #   Usage Minimum (Button 1)
    0x29, 0x10,  #   Usage Maximum (Button 16)
    0x15, 0x00,  #   Logical Minimum (0)
    0x25, 0x01,  #   Logical Maximum (1)
    0x75, 0x01,  #   Report Size (1)
    0x95, 0x10,  #   Report Count (16)
    0x81, 0x02,  #   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x05, 0x01,  #   Usage Page (Generic Desktop Ctrls)
    0x15, 0x81,  #   Logical Minimum (-127)
    0x25, 0x7F,  #   Logical Maximum (127)
    0x09, 0x30,  #   Usage (X)
    0x09, 0x31,  #   Usage (Y)
    0x09, 0x32,  #   Usage (Z)
    0x09, 0x35,  #   Usage (Rz)
    0x75, 0x08,  #   Report Size (8)
    0x95, 0x04,  #   Report Count (4)
    0x81, 0x02,  #   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,        # End Collection
))

gamepad = usb_hid.Device(
    report_descriptor=GAMEPAD_REPORT_DESCRIPTOR,
    usage_page=0x01,           # Generic Desktop Control
    usage=0x05,                # Gamepad
    report_ids=(4,),           # Descriptor uses report ID 4.
    in_report_lengths=(6,),    # This gamepad sends 6 bytes in its report.
    out_report_lengths=(0,),   # It does not receive any reports.
)

usb_hid.enable(
    (usb_hid.Device.KEYBOARD,
     usb_hid.Device.MOUSE,
     usb_hid.Device.CONSUMER_CONTROL,
     gamepad)
)

User avatar
Franklin97355
 
Posts: 23902
Joined: Mon Apr 21, 2008 2:33 pm

Re: A Board Capable of Python and USB Joystick HID?

Post by Franklin97355 »


User avatar
MrRSquared
 
Posts: 14
Joined: Fri Sep 20, 2019 9:48 am

Re: A Board Capable of Python and USB Joystick HID?

Post by MrRSquared »

Thank you. That seems to be working.
My confusion was not realizing that hid_gamepad.py was the driver.

Locked
Please be positive and constructive with your questions and comments.

Return to “For Educators”