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.

 1from time import sleep
 2
 3from approxeng.input.controllers import find_matching_controllers, ControllerRequirement
 4from approxeng.input.selectbinder import bind_controllers
 5
 6discovery = None
 7
 8# Look for an attached controller, requiring that it has 'lx' and 'ly' controls, looping until we find one.
 9while discovery is None:
10    try:
11        discovery = find_matching_controllers(ControllerRequirement(require_snames=['lx', 'ly']))[0]
12    except IOError:
13        print('No suitable controller found yet')
14        sleep(0.5)
15
16# Bind the controller to the underlying event stream, returning a function used to tidy up
17unbind_function = bind_controllers(discovery, print_events=False)
18
19try:
20    # Get a stream of values for the left stick x and y axes. If we were using robot code from gpio.zero we could
21    # set the controller.stream[...] as a source, as sources are just iterators which produce sequences of values
22    for lx, ly in discovery.controller.stream['lx', 'ly']:
23        print('Left stick: x={}, y={}'.format(lx, ly))
24        sleep(0.1)
25except StopIteration:
26    # Raised when the stream ends
27    pass
28
29# Tidy up any resources (threads, file handles) used by the binder
30unbind_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.