Skip to content

Control System

RSHodgkinson edited this page Feb 19, 2024 · 46 revisions

Overview

The control system is split into two distinct parts, the backend control system (Python and Arduino) and the frontend graphical user interface (GUI or just UI) (Electron/Nodejs). Both the back and front ends are further split into different modules. This 'separation of concerns' is to enable different sections of the software to be upgraded in the future without affecting core machine functionality or requiring the whole code base to be refactored.

Software Installation

Please refer to these two sections to install all the Python and Node.js libraries required for the UTM

  1. UTM Infrastructure - Database
  2. Control System - Python
  3. Control System - Arduino
  4. GUI Installation

UTM Control System

Control system (v1) Raspberry Pi - Python

The v1 control system has been designed in Python (v3.9) to make it easy for UTM users to follow and modify the code. This runs on the Raspberry Pi and controls just about everything on the UTM.

Control System Installation

Instructions on how to install the software

Infrastructure

Modules

Each of the subsystem DigitalExtensometer, LoadCell and Motor classes are written in a similar way and have similar methods. They run multi-threaded; where one thread deals with the main loop and another is continuously reading (or writing) and storing data in another while loop. As of UTM v1, each of these modules are hardcoded in the Controller as they are the minimum required modules in order to operate the machine. The Controller class imports all of these modules and uses their read() methods to get the required data for control and to send to the DataLogger and Test classes.

The current vision is that future add-on modules will be designed with a plugin architecture to allow people to extend the UTM capabilities. Examples of such upgrades might be sample temperature measurement or optical strain measurement. These plugins would require a data schema to describe the type of data that they are exposing to the Controller. This would allow the controller to import and use the plugin modules and to send data to the data_logger modules for recording.

The headless backend

The control system is designed to run completely headless (without any user interface) if required. This headless behaviour has been designed in from v1 so that new GUIs could be designed by users. It also enables the future development of robotic UTM 'cells', where testing for multiple UTMs could be coordinated from a centralised management workstation.

Communications - ZeroMQ library

Commands are sent between the GUI and control system Controller class using ZeroMQ. Two interprocess communication Unix sockets (pub.ipc, sub.ipc) are used in a publisher-subscriber model. ZeroMQ was chosen early in the UTM development as its performance is far superior to using stdin stdout when using Node.js child_process to spawn Python scripts. It also allows the possibility of controller.py to be automatically run when the Raspberry Pi boots up.

The Publisher socket (pub.ipc) publishes commands from the GUI to the Controller. It is bound by Node.js in the Electron GUI application and subscribed to by the Controller Python class.

The Subscriber socket (sub.ipc) publishes data from the Controller back to the GUI. It is bound by Python in the Controller class and subscribed to by the Node.js in the Electron GUI.

In order to write bespoke GUI applications the ZeroMQ sockets must be used to communicate the desired commands to the Controller. The Controller also

Command Protocol

Send commands - (From GUI to Controller) - uses the pub.ipc ZeroMQ channel

  • Controller

    • cmd:enable - Enables the controller
    • cmd:disable - Disables the controller and halts the motor
  • Motor

    • cmd:dir:0 - Stops the motor (direction = 0)
    • cmd:dir:1 - Turns the motor in forwards direction - this is direction specific to how the Arduino and motor have been setup
    • cmd:dir:2 - Turns the motor in backwards direction
    • cmd:speed:50 - Change the motor speed to 50% - converted to 0-65535 for 16bit PWM.
    • cmd:speed:0 - Change the motor speed to 0% - effectively stops the motor. The preferred way to do this is to use the cmd:dir:0 command
  • Load Cell

    • cmd:zero:load_cell - Zero the load cell. This will zero the loadcell_rel value but not the loadcell_abs value as this is still used to ensure safety limits
  • Digital Extensometer

    • cmd:zero:extensometer - Zero the digital scales/extensometer. This will zero the displacement_rel value but not the displacement_abs value as this is still used to ensure safety limits
  • Lighting

    • cmd:led:1:100 - Turn LED panel 1 ON with brightness 100% - 0-100% converted to 0-65535 for 16bit PWM
    • cmd:led:2:30 - Turn LED panel 2 ON with brightness 30% - 0-100% converted to 0-65535 for 16bit PWM
    • cmd:led:1:0 - Turn LED panel 1 OFF (brightness 0%)
  • Status

    • status - Get the status of EVERYTHING - this is the main command to use
    • status:controller - Get the status of the Controller
    • status:loadcell - Get the status of the LoadCell
    • status:extensometer - Get the status of the Extensometer
    • status:led:n - Get the status of the LED panel n = [1, 2]

Receive events - (From Controller to GUI) - uses the sub.ipc ZeroMQ channel

  • data - Sending JSON data for all channels to the GUI

    • {
          time: 121335973491.322, 
          displacement_abs: 153.45,
          displacement_rel: 134.56,
          load_abs: 2.45,
          load_rel: 2.44,
          stress_eng: 104.98,
          ...
      }
      
  • status - Sending status information to the GUI

    • v1 - These statuses are hardcoded into the communications system. v2 should use data schemas for each module in order to decide which modules are installed/active and to get their status using a status() method.
    •  {   
           controller: 'running', 
           load_cell: 'running',
           digital_extensometer: 'running',
           motor: 'stopped',
           led1: 50, // percentage brightness
           led2: 50 // percentage brightness
       }
      
  • info - Information from the controller for regular events such as the test ending, configuration changes etc.

    • v1 - There are three required fields/keys; time = time of event in (unix), system = which subsystem created the event and event = type of event.
    • {   
          time: 167539373424.332, 
          system: 'configuration',
          event: 'changed'
      }
      
  • alarm - Alarm information from the controller for events such as the load cell or digital scales going overlimit or the emergency stop button being pressed.

    • v1 - There are four required fields/keys; time = time of event in (unix), system = which subsystem created the error and error = type of error ie warning for subcritical errors and danger for critical emergencies that require a UTM full halt, value = value of the subsystem that caused the error.
    • {   
          time: 167539373424.332, 
          system: 'load_cell',
          error: 'limit danger',
          value: 53.45
      }
      

Motor control

The UTM linear actuator is controlled by the Motor class from motor.py. It acts as the intermediary between the the main controller class and the main micro-controller (UTM v1 => Arduino Pro Micro). The Motor class contains methods to enable, disable, start, stop, change direction of the motor. It also has a method to change the brightness of the LED panels on the main UTM printed circuit board if a camera is required to image the test sample.

Commands are all routed through the Controller class, which then calls Motor methods based how the command is parsed.

The Motor class is imported into the controller.py script and initialised based on the { motor : {...}} section of the configuration file.

Load Cell

The load cell on the UTM is connected to the main frame and upper sample grips. This enables the UTM to measure the force on a sample as it is tested. In the v1 design two physical load cells are connected the amplifier main PCB; a 50kg load cell and a 1000 kN load cell. The load_cell.py script contains a LoadCell class, which abstracts the interaction between the Controller class and the two 24 bit amplifiers (HX711 and NAU7802 breakout boards). The LoadCell class enables both amplifiers to be configured and read using the same method calls rather than having to create separate load cell classes for each amplifier. Through the LoadCell class you can tare, calibrate and read load cell force values. In some cases a user might find that the want to work with raw bit values from the load cell amplifiers and convert to forces/weights using their own code. This is not accounted for in the current code base but it is simple to add in a read_raw function.

Digital Linear Scales / Digital Extensometer

The digital scales installed on the UTM are used to measure the displacement of the lower sample grips during a test. As the linear actuator acts on a lever arm away from the sample, the rate of displacement of the actuator and the sample grips are not constant with each respect to each other. Therefore the linear scales enables a more accurate measure of displacement and displacement rate (speed) during a test.

The digital linear scales used in the v1 UTM were bought from ebay at the cost of £35 GBP. They are 300mm 'Shahe' Digital Readout (DRO) scales intended for use as addon measuring devices in workshop machining equipment. They have a spatial resolution of 0.01mm (10 microns) and a refresh rate of 10Hz. The scales have a relative position readout, rather than absolute. This means that they return to reading from 0.00mm if they are powered down at any time. This means that the UTM machine is not aware of where the actuator is in real space, only that is has moved a certain distance from the zero point when it was powered up. Other more expensive scales are available that have absolute AND relative position readouts, such as those from Mitutoyo.

All digital scales that are suitable for the UTM have some form of digital protocol that are read by an associate head/display unit that is typically sold with the scales. However, for the UTM we require that the position values are sent to the Raspberry Pi so that the control system can act on them.

Digital protocol decoding

There are a few common digital protocols for scales but the approach for decoding each is very similar. The Shahe scales used for UTM v1 have a 4 pin connection via a mini-USB type B connector. This connector is made specifically to connect the scales to the provided head unit and cannot be used with a standard USB connection. There are 4 wires inside the cable that are terminated at the USB connector. For our purposes we cut off the male USB plug and stripped back each of the 4 internal wires ready to to solder onto our micro controller GPIO pins. When powered up the digital scales provides its own clock pulses.

  1. Identifying wiring

    • Black = +3.3V
    • Green = GND
    • White = Clock
    • Red = Data
  2. Microcontroller

    • Raspberry Pi Pico (2040 chip)
    • Arduino - 3.3V compatible (if you use a 5V Arduino be very careful as the scales require driving with either 1.5V or 3.0-3.3V)
  3. Wiring diagram

    • Wiring Diagram for the scales and Pico
  4. Program to decode the data signal

    • Connect the Clock and Data lines to an oscilloscope and trigger on the rising edge of the clock signal
    • Lowest bit is displayed first on the oscilloscope
    • The protocol in the Shahe scales that were used in UTM v1 has 24bits - 6 x 4bit nibbles
    • The first 20 bits are used for position but only the first 16 bits are actually useful on a 300.00mm scale
    • The 21st bit (left to right on the oscilloscope) is to represent a negative sign for negative positions.
    • Examples of the scales clock and data signals and the associated decoded positions

More resources to assist in identifying and decoding your scales

Optical/Video Strain measurement

Clone this wiki locally