Getting started with the Python API

So you just received your shiny new qontrollers, and are ready to start programming? This note is for you! First, we’ll get you up and running, then show you some of the API’s features.

Setting up

Things to do before we get started:

  1. Make sure you have a working Python interpreter. Open a command prompt or terminal and type¬†python. If your Python is working, you’ll see details of your installation, such as your version. The Qontrol Python API is tested with both versions 2.7.10 and 3.7.2. If you don’t have Python,¬†install it.
  2. Install the latest pyserial. We are currently tested with pyserial version 3.4 only. Some older versions of pyserial have been known to cause issues.
  3. Download the latest Qontrol Python API and example code.
  4. Move and to your desktop (for now).
  5. Ensure your qontroller is connected to the PC, and that your experimental device is disconnected From the qontroller.
  6. Check that the USB device is recognised by your PC, and that virtual COM port drivers are installed. If not, these drivers can be downloaded from the FTDI website.

Great! If all that went to plan, you should now have a working system. Next, we’ll guide you through the example code.

API basics

First, we read in the API. with an import call. This file needs to be in your Python PATH variable. The easiest way to achieve this is by keeping it in the same directory as your application code (on the desktop, if you followed step 4).

To initialise an output device (or daisy-chain), like a Q8iv, first use a definition like

q = qontrol.QXOutput(serial_port_name = "COM1")

where q is our qontroller object, which stores information about the hardware, such as its device ID (q.device_id) and number of channels (q.n_chs), and handles all communications and commands. COM1 is an example of what the connected serial port name might be on Windows. Port numbers greater than 10 must be written like //./COM42. On Mac or Linux, this will look something like /dev/tty.usbserial-FT123ABC. When your code is done with the hardware, it’s good practice to close the connection with a call to


Controlling outputs, and reading inputs is easy. Writing to the qontroller object’s v or i arrays (using standard Python array indexing) sets the output for channel with that index. Reading from those arrays reads the input values back from the hardware. For example, we can set the voltage on output channel 3 to 4.5V with the code

q.v[3] = 4.5

and read back the current (in mA) with

measured_current = q.i[3]

We can do bulk changes to channels using slices. The slice character in Python, :, means either “everything between two indices” (e.g. v[2:5]), “everything from the beginning until an index” (e.g. v[:5]), or “everything from an index until the end” (e.g. v[2:]).

Running the example code

To run our script, we need two things:

  1. to have in our Python PATH variable (e.g. in the same place as, and
  2. to point Python to the location of

On Linux and Mac, in a terminal window (e.g., on Mac), do something like this:

    python ~/Desktop/

On Windows 7, in the command prompt (cmd), the following might work:


If the example code runs successfully, the lights on your qontroller will flash as commands are transmitted, and output channels are energised. The qontroller’s device ID will be read out, as well as its number of channels. The voltage on each channel will be briefly set to the channel’s number, then return to zero (e.g. channel 3 is set to 3 V). The current of each channel will be read out. Next, we’ll take a look at exactly what’s inside.

Contents of

import qontrol

# Setup Qontroller
serial_port_name = "/dev/tty.usbserial-FT06QAZ5"
q = qontrol.QXOutput(serial_port_name = serial_port_name, response_timeout = 0.1)

print ("Qontroller '{:}' initialised with firmware {:} and {:} channels".format(q.device_id, q.firmware, q.n_chs) )

# Set voltage on each channel to its index in volts, read voltage, current
for channel in range(q.n_chs):
	set_voltage = channel
	# Set voltage
	q.v[channel] = set_voltage
	# Measure voltage (Q8iv)
	measured_voltage = q.v[channel]
	# Measure current (Q8iv, Q8b, Q8)
	measured_current = q.i[channel]
	print ("Channel {:} set to {:} V, measured {:} V and {:} mA".format(channel, set_voltage, measured_voltage, measured_current) )

# Set all channels to zero
q.v[:] = 0


Happy experimenting!

Now hack the example code into whatever shape you desire. Need help? Want more functionality? Just curious? We’d love to hear from you: leave a comment below, or email us at

Leave a Reply

Your email address will not be published. Required fields are marked *

× 2 = 20