Streaming Axis and Button Hold values

Some other APIs, most notably Gpiozero, can configure devices to read from iterators over data such as axis values. To use this facility we need to be able to produce generators (iterators which work over lazily evaluated, potentially infinite, sets of data) containing streams of axis and button hold values. These generators can then be set as the source for anything in e.g. Gpiozero which has a SourceMixin defined, including motors and similar.

The example below doesn’t use Gpiozero, but instead shows how a stream of x,y values from the left analogue stick is created, then used by an infinite loop to print those values. The loop only exits with a StopIteration exception when the controller disconnects. This is also an example of explicitly creating and binding a controller, rather than using the resource abstraction shown in the other examples.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from time import sleep

from approxeng.input.controllers import find_matching_controllers, ControllerRequirement
from approxeng.input.selectbinder import bind_controllers

discovery = None

# Look for an attached controller, requiring that it has 'lx' and 'ly' controls, looping until we find one.
while discovery is None:
    try:
        discovery = find_matching_controllers(ControllerRequirement(require_snames=['lx', 'ly']))[0]
    except IOError:
        print('No suitable controller found yet')
        sleep(0.5)

# Bind the controller to the underlying event stream, returning a function used to tidy up
unbind_function = bind_controllers(discovery, print_events=False)

try:
    # Get a stream of values for the left stick x and y axes. If we were using robot code from gpio.zero we could
    # set the controller.stream[...] as a source, as sources are just iterators which produce sequences of values
    for lx, ly in discovery.controller.stream['lx', 'ly']:
        print('Left stick: x={}, y={}'.format(lx, ly))
        sleep(0.1)
except StopIteration:
    # Raised when the stream ends
    pass

# Tidy up any resources (threads, file handles) used by the binder
unbind_function()

Note particularly that there’s only one call to create the stream, on line 21, and that afterwards this is just like any other iterable thing in Python, each time around the loop the next value (in this case a tuple of lx and ly axis values) is taken off the stream.