Please note: Friday June 18 is a holiday celebrating Juneteenth, please allow extra time for your order to arrive and plan accordingly.
0

Circuitpython Raspberry Pi Pico as USB Joystick
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Circuitpython Raspberry Pi Pico as USB Joystick

by Larches on Sat Apr 24, 2021 9:41 pm

I set up my new Raspberry Pi Pico with Circuitpython in the hope of using it to simulate a USB joystick for Flight simulator 2020. ie To have a Potentiometer as input to the Pico and for the Pico to output via USB as a joystick axis In Windows.

I found several libraries and examples for doing this as a keyboard or mouse but not a joystick.

I be grateful for any advice on where to find the appropriate library and hopefully an example.

Larches
 
Posts: 1
Joined: Sat Apr 24, 2021 9:22 pm

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by mikeysklar on Mon Apr 26, 2021 3:34 pm

I believe the CircuitPython terminology would be gamepad in this case.

Code: Select all | TOGGLE FULL SIZE
import usb_hid
from adafruit_hid.gamepad import Gamepad

gp = Gamepad(usb_hid.devices)

# Click gamepad buttons.
gp.click_buttons(1, 7)

# Move joysticks.
gp.move_joysticks(x=2, y=0, z=-20)


https://circuitpython.readthedocs.io/pr ... en/latest/

mikeysklar
 
Posts: 4559
Joined: Mon Aug 01, 2016 8:10 pm

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by luehrs on Mon May 31, 2021 9:18 am

Hi,
I try to do the same. And yes, there are several links with using "adafruit_hid.gamepad".
But this seems to be gone. The latest release doesn't have "gamepad" anymore.
So, the question here is why this was taken away and when does it hopefully come back??
Ole

luehrs
 
Posts: 1
Joined: Mon May 31, 2021 9:15 am

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by mikeysklar on Mon May 31, 2021 2:56 pm

@luehrs,

It looks like some things have been shuffled around, but not removed.

I think the syntax for accessing Gamepad now looks like:

Code: Select all | TOGGLE FULL SIZE
import board
import digitalio
import analogio
import usb_hid

from gamepad import Gamepad

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)

mikeysklar
 
Posts: 4559
Joined: Mon Aug 01, 2016 8:10 pm

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by grrg on Sat Jun 05, 2021 4:46 am

Yes, the gamepad can sort of mimic a joystick but it is limited to a resolution of 256 steps, i.e 8 bit. This is way (!) to low for using it in flight simulation.

Now to use the full potential of the pico's 12 bit ADC one needed to set up a precision joystick that can be feed with short integer values (i.e. 16 bit integer), like one can do with the mouse class.

Most unfortunately i am running into severe problems when trying the usb_hid customization of CP7 using alpha 3. Though I have no problems in setting up a report descriptor for the needs sketched out above ... this results in the pico not showing up at all as a usb mass storage and not being accessible via terminal. That is, a complete disaster :) ...

I tried to mimic Dan Halbert's approach (https://learn.adafruit.com/customizing- ... -3096614-9) but I do experience all sorts of strange issues when trying ... most notably the report descriptor seems to be altered en route ... Nevertheless I am convinced this is the only way to go.

QUESTION: Is there any working example for the usage of CP to set up customized hid (joystick or gamepad) devices using an arbitrary report descriptor?

Any help is highly appreciated.

Regards

grrg
 
Posts: 5
Joined: Sat Jun 05, 2021 4:34 am

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by mikeysklar on Sun Jun 06, 2021 6:21 pm

grrg,

Would it make sense to start use the "consume controlled" device which appears to support between values between 1 - 652. In this example code it looks as though consumer control supports a 16-bit control code which might work for you.

https://circuitpython.readthedocs.io/en ... index.html
https://circuitpython.readthedocs.io/pr ... ntrol.html

Code: Select all | TOGGLE FULL SIZE
# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
`adafruit_hid.consumer_control.ConsumerControl`
====================================================

* Author(s): Dan Halbert
"""

import sys

if sys.implementation.version[0] < 3:
    raise ImportError(
        "{0} is not supported in CircuitPython 2.x or lower".format(__name__)
    )

# pylint: disable=wrong-import-position
import struct
import time
from . import find_device


[docs]class ConsumerControl:
    """Send ConsumerControl code reports, used by keyboards, remote controls, etc."""

    def __init__(self, devices):
        """Create a ConsumerControl object that will send Consumer Control Device HID reports.

        Devices can be a list of devices that includes a Consumer Control device or a CC device
        itself. A device is any object that implements ``send_report()``, ``usage_page`` and
        ``usage``.
        """
        self._consumer_device = find_device(devices, usage_page=0x0C, usage=0x01)

        # Reuse this bytearray to send consumer reports.
        self._report = bytearray(2)

        # Do a no-op to test if HID device is ready.
        # If not, wait a bit and try once more.
        try:
            self.send(0x0)
        except OSError:
            time.sleep(1)
            self.send(0x0)

[docs]    def send(self, consumer_code):
        """Send a report to do the specified consumer control action,
        and then stop the action (so it will not repeat).

        :param consumer_code: a 16-bit consumer control code.

        Examples::

            from adafruit_hid.consumer_control_code import ConsumerControlCode

            # Raise volume.
            consumer_control.send(ConsumerControlCode.VOLUME_INCREMENT)

            # Advance to next track (song).
            consumer_control.send(ConsumerControlCode.SCAN_NEXT_TRACK)
        """
        self.press(consumer_code)
        self.release()


[docs]    def press(self, consumer_code):
        """Send a report to indicate that the given key has been pressed.
        Only one consumer control action can be pressed at a time, so any one
        that was previously pressed will be released.

        :param consumer_code: a 16-bit consumer control code.

        Examples::

            from adafruit_hid.consumer_control_code import ConsumerControlCode

            # Raise volume for 0.5 seconds
            consumer_control.press(ConsumerControlCode.VOLUME_INCREMENT)
            time.sleep(0.5)
            consumer_control.release()
        """
        struct.pack_into("<H", self._report, 0, consumer_code)
        self._consumer_device.send_report(self._report)


[docs]    def release(self):
        """Send a report indicating that the consumer control key has been
        released. Only one consumer control key can be pressed at a time.

        Examples::

            from adafruit_hid.consumer_control_code import ConsumerControlCode

            # Raise volume for 0.5 seconds
            consumer_control.press(ConsumerControlCode.VOLUME_INCREMENT)
            time.sleep(0.5)
            consumer_control.release()
        """
        self._report[0] = self._report[1] = 0x0
        self._consumer_device.send_report(self._report)



You could also request additional feature enhancements as you suggest on the CircuitPython Github issue tracker.

https://github.com/adafruit/circuitpyth ... en+usb_hid

mikeysklar
 
Posts: 4559
Joined: Mon Aug 01, 2016 8:10 pm

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by grrg on Wed Jun 09, 2021 3:46 am

Mikeysklar,

thank you very much for your reply. Unfortunately having had a look at the code I doubt that this is viable ... the generic consumercontrol inmpements a way to tramsmit trigger events from consumer controls defined in https://www.usb.org/sites/default/files/hut1_21_0.pdf#page=118.
To be more specific, the 16bit integer provided as an agrument is interpreted as a usage id for the devices defined in the document quoted. I need to transmit an arbitrary 16bit integer in a way that the host just receives a message like "device x has sent value y".

Thank you very much for your contribution.
grrg

grrg
 
Posts: 5
Joined: Sat Jun 05, 2021 4:34 am

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by mikeysklar on Wed Jun 09, 2021 2:26 pm

@grrg,

Since you are interested in high quality flight simulators I think it would be best that you open a discussions through the github issue tracker for this library. It might be a reasonable enough feature request to pass a 16-bit value that it gets implemented into joystick or some custom HID interface.

https://github.com/adafruit/circuitpython/issues

mikeysklar
 
Posts: 4559
Joined: Mon Aug 01, 2016 8:10 pm

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by danhalbert on Wed Jun 09, 2021 2:45 pm

In CircuitPython 7, now in alpha, you can now define an arbitrary HID device that uses a single report ID. We are going to be supporting multiple report ID's soon. So you will be able to define a joystick device with whatever configuration you want. You will need to write a Python library to support it, but that should be straightforward, as it would be similar to the current gamepad library, etc.

See https://learn.adafruit.com/customizing- ... id-devices and https://github.com/adafruit/circuitpython/issues/4868

danhalbert
 
Posts: 2430
Joined: Tue Aug 08, 2017 12:37 pm

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by grrg on Wed Jun 09, 2021 5:27 pm

danhalbert wrote:In CircuitPython 7, now in alpha, you can now define an arbitrary HID device that uses a single report ID.
[...]
See https://learn.adafruit.com/customizing- ... id-devices and[...]


dhalbert,
I just tried that as pointed out in my first post. Using cp 7 alpha 3 i fell flat on my face. Now this was the reason why I asked for some working examples.
Is there any example (available to the public) for any HID device using that approach you have hinted?
I needed some full code ... your inspiring article just gives abbreviated code samples ... which unfortunately are not enough to find out where I went wrong,.

To spare you all the discussion of my code, could you point out some full implementation examples?

Cheers
grrg
Last edited by grrg on Wed Jun 09, 2021 5:34 pm, edited 1 time in total.

grrg
 
Posts: 5
Joined: Sat Jun 05, 2021 4:34 am

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by grrg on Wed Jun 09, 2021 5:31 pm


Thank you for pointing that out ... and sharing the link .. :)

grrg
 
Posts: 5
Joined: Sat Jun 05, 2021 4:34 am

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by danhalbert on Fri Jun 11, 2021 10:55 am

If you have an existing joystick, you can plug it in and read the HID report descriptor it includes, and then mimic it. Here's a post about how to get the report descriptor, and there are other ways to be found as well by a websearch: https://todbot.com/blog/2021/01/29/get- ... nt-page-1/

Or, you may find a suitable Flight-Simulator-compatible joystick HID report descriptor via some websearch.

You can parse and understand the web descriptor using: http://eleccelerator.com/usbdescreqparser/. There is other useful info at that website as well.

Eventually we will have some guide about how to do this, with examples. Sorry, this is all very new, and the feature is still evolving, so it's more of a DIY project right now.

danhalbert
 
Posts: 2430
Joined: Tue Aug 08, 2017 12:37 pm

Re: Circuitpython Raspberry Pi Pico as USB Joystick

by grrg on Sun Jun 13, 2021 5:29 am

Dan,

you have obviously not taken the effort to read the thread ... of course I have been trough all that already.

So it boils down to that your post in the learn section of adafruit was more meant to advertise how things could be like in the future ... and there is neither a proof of principle nor a piece of working code for any hid device type yet.

This has mislead me I must say ... and made me waste hours. May I suggest to do it the other way round ... just to spare others the frustrating experience ...

Guys, I am out'a'here ...

--grrg

grrg
 
Posts: 5
Joined: Sat Jun 05, 2021 4:34 am

Please be positive and constructive with your questions and comments.