General Purpose Input Output (GPIO)

Python Example

Device Compatibility


The GPIO driver supports:

  • Reading pin input
  • Setting pin output

Device Pinouts:

Available ZeroMQ Ports

  • Base port: 20049
  • Keep-alive port: 20050
  • Error port: 20051
  • Data Update port: 20052

Code Example

The following sections show how to implement a connection to each of the GPIO driver's ports. You can download this example here.

Initial Variables

Before we go into connecting to each port, the variables defined below are needed in order to access the ZeroMQ and MATRIX Protocol Buffer libraries for Python. We also define a few helpful variables for easy references.

import os # Miscellaneous operating system interface
import zmq # Asynchronous messaging framework
import time # Time access and conversions
import sys # System-specific parameters and functions
from matrix_io.proto.malos.v1 import driver_pb2 # MATRIX Protocol Buffer driver library
from matrix_io.proto.malos.v1 import io_pb2 # MATRIX Protocol Buffer sensor library
from multiprocessing import Process # Allow for multiple processes at once
from zmq.eventloop import ioloop # Asynchronous events through ZMQ
matrix_ip = '' # Local device ip
gpio_port = 20049 # Driver Base port
# Handy functions for connecting to the keep-Alive, Data Update, & Error port 
from utils import driver_keep_alive, register_data_callback, register_error_callback

Base Port

Here is where the configuration for our GPIO example goes. Once we connect to the Base Port, we will pass a configuration to the GPIO driver. With this, we can set the update rate, timeout, and pin configuration. This example will use pin: 0 and toggle the pin state between on&off through a toggle() function.

Each pin will save its last set value until the next device boot.

# Define zmq socket
context = zmq.Context()
# Create a Pusher socket
socket = context.socket(zmq.PUSH)
# Connect Pusher to configuration socket
socket.connect('tcp://{0}:{1}'.format(matrix_ip, gpio_port))

# Configure GPIO update rates and timeout
def config_gpio_read():
    # Create a new driver config
    config = driver_pb2.DriverConfig()
    # Delay between updates in seconds
    config.delay_between_updates = 2.0
    # Timeout after last ping
    config.timeout_after_last_ping = 3.5
    # Send driver configuration through ZMQ socket

# Recursive function to toggle pin state
def config_gpio_write(pin, value):
    # Create a new driver config
    config = driver_pb2.DriverConfig()
    # set desired pin = pin
    # Set pin mode to output
    config.gpio.mode = io_pb2.GpioParams.OUTPUT
    # Set the output of the pin initially
    config.gpio.value = value%2
    # Send driver configuration through ZMQ socket

    # Wait 2 seconds
    # Increase value and run again
    value += 1
    config_gpio_write(0, value%2)
Keep-alive Port

The next step is to connect and send a message to the Keep-alive Port. That message will grant us a response from the Data Update Port for the current GPIO values. The utils import from the Initial Variables section takes care of this.

Error Port

The Error Port connection is also taken care of by the utils import. Below we define a function to be called and given any error messages that occur within MATRIX CORE.

def gpio_error_callback(error):
    # Log error

Data Update Port

A connection to the Data Update Port is then made to allow us to receive the current IMU data we want. The message received from the GPIO driver is converted into a 16 bit array, named gpioValues that represents each pin on your MATRIX device.

def gpio_callback(msg):
    # Extract data
    data = io_pb2.GpioParams().FromString(msg[0])
    # Convert GPIO values to 16-bit
    gpioValues = ('{0:016b}'.format(data.values))
    # Reverse string for chronological order
    gpioValues = gpioValues[::-1]
    # Convert string into an array
    gpioValues = list(gpioValues)
    # Log GPIO pin states from gpioValues[0-15]
    print('GPIO PINS-->[0-15]\n{0}'.format(gpioValues))

Data Output

The Python object below is an example output you'll receive from the Data Update Port. For readability, the code above has converted the output as a 16-bit value and turned it into an array.
values: 513

Start Processes

This is where we begin the asynchronous events for each of the driver ports and where we define the functions we want to use for each port.

if __name__ == "__main__":
    # Initiate asynchronous events
    # Start Error Port connection
    Process(target=register_error_callback, args=(gpio_error_callback, matrix_ip, gpio_port)).start()
    # Start Keep-alive Port connection
    Process(target=driver_keep_alive, args=(matrix_ip, gpio_port, 1)).start()
    # Start Data Update Port connection
    Process(target=register_data_callback, args=(gpio_callback, matrix_ip, gpio_port)).start()
    # Send Base Port configurations
        # Configure GPIO update and timeout
        # Toggle state of selected pin, start with pin on
        config_gpio_write(0, 1)
    # Avoid logging GPIO errors on user quiting
    except KeyboardInterrupt: