ValveControl Scripting in Python

The Arduino driving the valves can run the supplied ValveControl Arduino Sketch. This example control program can apply either closed-loop or open-loop valve control. It be configured for the specific actuator, valve, and optional feedback sensor arrangement.

The sketch acts upon command messages received over the USB serial port. The simplest means of testing is to use a terminal program to directly issue commands to the controller. This could simply be the console within the Arduino IDE, or a separate terminal program such as minicom or CoolTerm.

The more flexible way to drive the system is to use a Python script on a separate computer to send commands to the embedded controller. A self-contained Python sample appears below. It does require a pySerial installation to communicate with the Arduino.

This example uses only open-loop ‘speed’ commands to set the fill and empty rate on the two pairs of valves. The primary building block function for the sequence is set_flow().

pneumatics_exercise.valve_sequence.set_flow(port, flow, extend=1, retract=2, pause=None, verbose=False)[source]

Issue an open-loop set of flow commands for a valve pair attached to an actuator. Returns immediately or after an optional delay. No return value.

Parameters
  • port – serial port stream handle

  • flow – net flow from -100 full retraction rate to 100 full extension rate

  • extend – channel number for extension valve pair

  • retract – channel number for retract valve pair

  • pause – time in seconds to delay after issuing command

  • verbose – flag to enable printed debugging output

Returns

None

The full script is below. It can also be directly downloaded from the Python source tree on the course site.

  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
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
#!/usr/bin/env python
"""\
valve_sequence.py

Play back a sequence of pneumatic valve activations using a serial port
connection to an Arduino running ValveControl.

Copyright (c) 2015-2017, Garth Zeglin.  All rights reserved. Licensed under the
terms of the BSD 3-clause license.

"""
################################################################
# Import standard Python 2.7 modules.
from __future__ import print_function
import os, sys, time, argparse

# This module requires a pySerial installation.
#  Package details: https://pypi.python.org/pypi/pyserial,
#  Documentation: http://pythonhosted.org/pyserial/
import serial

################################################################
def set_flow( port, flow, extend=1, retract=2, pause=None, verbose=False):
    """Issue an open-loop set of flow commands for a valve pair attached to an actuator.
    Returns immediately or after an optional delay.  No return value.

    :param port: serial port stream handle
    :param flow: net flow from -100 full retraction rate to 100 full extension rate
    :param extend: channel number for extension valve pair
    :param retract: channel number for retract valve pair
    :param pause: time in seconds to delay after issuing command
    :param verbose: flag to enable printed debugging output
    :return: None
    """


    if flow > 0:
        ext_command  = "speed %d %d" % (extend, flow)
        ret_command = "speed %d %d" % (retract, -100)
    elif flow == 0:
        ext_command  = "speed %d %d" % (extend, 0)
        ret_command = "speed %d %d" % (retract, 0)
    else:
        ext_command  = "speed %d %d" % (extend, -100)
        ret_command = "speed %d %d" % (retract, -flow)

    if verbose:
        print ("Issuing %s, %s" % (ext_command, ret_command))

    port.write("%s\n%s\n" % (ext_command, ret_command))

    if pause is not None:
        time.sleep(pause)

    # ignore any sensor feedback
    port.flushInput()

    return

################################################################
# The following section is run when this is loaded as a script.
if __name__ == "__main__":

    # Initialize the command parser.
    parser = argparse.ArgumentParser( description = """Scripted sequence of pneumatic valve activations using the ValveControl controller on an Arduino.""")
    parser.add_argument( '-v', '--verbose', action='store_true', help='Enable more detailed output.' )
    parser.add_argument( '--debug', action='store_true', help='Enable debugging output.' )
    parser.add_argument( '-p', '--port', default='/dev/tty.usbmodem1411', help='Specify the name of the Arduino serial port device (default is /dev/tty.usbmodem1411).')

    # Parse the command line, returning a Namespace.
    args = parser.parse_args()

    # Open the serial port, which should also reset the Arduino
    print("Connecting to Arduino.")
    port = serial.Serial( args.port, 115200, timeout=5 )
    if args.verbose:
        print("Opened serial port named", port.name)

    print("Sleeping briefly while Arduino boots...")
    time.sleep(2.0)

    # throw away any extraneous input
    print("Flushing Arduino input...")
    port.flushInput()

    # Begin the motion sequence.  This may be safely interrupted by the user pressing Control-C.
    try:
        print("Beginning movement sequence.")
        set_flow(port,   50, pause=2.0, verbose=args.verbose)
        set_flow(port,    0, pause=2.0, verbose=args.verbose)
        set_flow(port,  -50, pause=2.0, verbose=args.verbose)
        set_flow(port,    0, pause=2.0, verbose=args.verbose)
        set_flow(port,  100, pause=2.0, verbose=args.verbose)
        set_flow(port,    0, pause=2.0, verbose=args.verbose)
        set_flow(port, -100, pause=2.0, verbose=args.verbose)
        print("Movement complete.")

    except KeyboardInterrupt:
        print("User interrupted motion.")

    # Close the serial port connection.
    port.write("stop\n")
    port.close()