libsting
Step Timing and INformation Gathering Library
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
Step Timing and INformation Gathering library

Introduction

As its name suggests, libsting was created for two purposes: to limit the temperature rise of actuators by limiting motor steps taken over time, and to accumulate and store lifetime operating information about individual actuators. Of these, only the former functionality has been implemented and tested as of this writing (June 2019). The design and usage are described below.

Current State of Development

In summary, libsting is unfinished as of June 2019. Even within its currently reduced scope (thermal management), libsmoco implementation has been limited to the subset of functionality required for smocod in the SCS 2.0 release. This includes the core timing thread and the single actuator operation API call sting_act_move_relative().


Development History and Rationale

Thermal Equilibrium Management

libsting was created to address problems noted in practice with actuators used for manipulating HET mirror segments as a part of the Segment Control System (SCS).

The performance of some actuators was found to degrade over time due to overheat events, in which motor coil insulation would fail at various points causing coil windings to short. This would reduce the impedance of the motor, drawing more current and causing such events to be more likely in the future. Due to the poor provision for cooling in the actuator housing design and the lack of temperature sensors in the assembly, a means was needed to limit the temperature rise by implementing a duty cycle – limiting the distance an actuator could travel in a given span of time while not limiting its actual travel speed, as travel at full speed provides higher efficiency and lower power consumption.

By observing temperature rise in the actuator at its normal operating speed, it is possible to represent the thermal dissipation characteristic of the actuator housing at a selected safe maximum operating temperature, in terms of a fraction of that speed, or duty cycle percentage. In terms of the actuators used for SCS, the operating speed is 6000 steps per second, and through rough calculations adjusted after testing, an average speed of 2500 steps per second was identified as a speed at which thermal equilibrium could be achieved at a safe temperature, less than 50F above ambient. The library operates a background timing thread that provides commands to motors on behalf of the calling application, to move and pause as needed to maintain the average speed configured in the library initialization.

The library has been tested not only for its correct operation, but also in its ability to successfully limit temperature rise of SCS's Diamond Motion actuators during extended operation.

Motor Lifetime Information Gathering

The second planned purpose for libsting was as a central collection point for the operating history of motors and actuator assemblies in SCS, for the purposes of planned maintenance, inspection and overhaul. To this end the library would provide a registration step for actuators which would include hardware information such as barcodes or other identifying details which could be configured as a part of segment swaps and segment frame setups. In this way, actuator assemblies could be tracked throughout their history regardless of their location in the primary mirror array, and an "age" in terms of lifetime step count could be accumulated for each actuator in a database.

Especially given the significantly different SAMS-driven movement behavior of segments at the outer edges of the array compared to those at the center, this tracking could be very useful in determining and comparing the impacts of movement step and accel/decel cycle counts on motor performance over time.

These information gathering features have not been implemented in libsting, though opportunities may be presented in the future to add them.

Development Decisions

The development of libsting as a separate library stems from the design goals of libsmoco, as it was spun off from the creation of smocod. libsmoco was intended as a library providing the specific command set of the SMOCO hardware and its CAN protocol in the form of a C API. This implies a direct one-to-one mapping of commands exposed by libsmoco to those command identifiers utilized by SMOCO firmware.

The needed movement step timing functionality, in contrast, requires an abstracted command set in which generalized movement commands can result in possibly several low-level commands sent to the controller hardware. For this reason, the routines were placed in their own library with its own API.

While it might be reasonable to implement this set of routines as a layer above libsmoco such that libsting makes direct use of libsmoco to do its work, libsting was instead designed to be hardware-agnostic, a final decision that led to the architecture of libsting as it currently exists. As a result, an application can use libsmoco (or any other motor control code) to control stepper motors, and separately can use libsting to track motors and limit movement and temperature rise. Put another way, an application's dependency on libsting does not imply a dependency or a use of any particular motor control library or system.


Application Design Overview

When writing an application to use libsting, keep a key premise in mind: libsting does not know how to control actuators. It only knows when to control actuators.

The above statement is significant in its details. Taking its use with SMOCO and SCS as an example, the sentences above make no mention of mirror segments or SMOCO nodes; nothing about locations in the primary mirror, axes, I, J and K positions or three actuators per SMOCO controller. libsting knows nothing about these – only about individual actuators, about which it maintains a simple list provided by registrations from the calling application. (In future enhancements, this list may be persisted in a database.) This has two fundamental implications to the design of an application using libsting.

  • Actuator list management: An application must register actuators to libsting before it can use the library to operate them. From there, two methods are available for an application to manage each actuator on libsting's terms. Registering an actuator provides an opaque handle that an application can supply with subsequent commands. Presuming that an application will have its own need to store information specific to each actuator it operates, libsting can also accept an optional pointer to that information structure during registration, from which a valid handle can be later recovered.
  • Callback-based operation: Everything libsting does with motors must be accomplished with a callback function that an application provides to it upon initialization of the library. The callback is provided all the necessary information to perform hardware operations, plus the pointer to the application's own actuator-specific data. The application then provides a return value to libsting to report success or failure of the operation.

So the application must maintain some association to libsting's actuator resources, either by storing the STING_ACT handle with its own internal actuator data, or by giving libsting the pointer to such data, or both.

Tuning Parameters

In the call to sting_init(), three values are submitted, which determine libsting's movement-limiting behavior. These parameters are documented in the reference material, but we'll cover the practical selection of these values in more detail here:

  • step_buffer This is the maximum travel distance that a motor can take in a single move without pausing, assuming that it has not recently made any other moves. A useful metaphor is a tank containing available steps, and this value represents the size of that tank. If a move is requested with a number of steps greater than the quantity remaining in the tank, then the it will fully deplete and the motor will pause. This value should be determined through testing and analysis of the actuator's motor temperature during operation. Determine how many steps of continuous motion it takes to rise from a resting temperature to the selected safe limit.
  • minimum_move The second tuning parameter is the threshold of remaining steps in our "tank", below which the motor will not move. Increasing this value will cause longer pauses, and fewer acceleration and deceleration cycles, which may be desirable in cases where these operating regimes are especially inefficient. A motor will only be moved by a smaller distance than this value, in the case that it has fewer steps remaining in a requested move.
  • steps_per_sec This is the most important tuning value which is based on the motor/actuator's ability to dissipate heat, and is used to determine the effective duty cycle. The background timing thread adds steps to each registered actuator's "tank" of available steps at the rate in this parameter. Test the selection of this value and tune as needed, using continuous motion to ensure the pauses effectively limit temperature rise as expected.

It is recommended to supply these parameters from a configuration file or other resource, such that they can be updated if environmental changes require it.


Example

#include "mydefs.h"
#include <motorctrl_lib.h>

typedef struct actuator {
    uint32_t motor_hwid;

    uint16_t controller_hwid;
    uint32_t actuator_assy_barcode;
    //...
    STING_ACT st_act;
} my_actuator_t;

/* Callback function, for performing hardware operations as required by libsting */
STING_OPERATION_RESULT my_sting_op(st_cb_operation_t *p_op, void *p_data) {

    /* Get our actuator data */
    my_actuator_t *p_act = (my_actuator_t *)p_data;

    switch(p_op->optype) {
    case ST_OPTYPE_MVUP:
        mtrctl_movemotor(p_act->motor_hwid, p_act->controller_hwid, p_op->value);
        break;
    case ST_OPTYPE_MVDN:
        mtrctl_movemotor(p_act->motor_hwid, p_act->controller_hwid, p_op->value * -1);
        break;
    case ST_OPTYPE_MVABS:
        mtrctl_movemotor(p_act->motor_hwid, p_act->controller_hwid, p_op->value - mtrctl_get_position(p_act->motor_hwid, p_act->controller_hwid));
    case ST_OPTYPE_GETPOS:
        p_op->value = mtrctl_get_position(p_act->motor_hwid, p_act->controller_hwid);
        break;
    case ST_OPTYPE_SETPOS:
        mtrctl_set_position(p_act->motor_hwid, p_act->controller_hwid, p_op->value);
        break;
    case ST_OPTYPE_FINDLIMIT:
        switch(p_op->fl_type) {
        case STFLT_UPPER:
            /* Move to upper travel limit */
            //...
        break;
        case STFLT_LOWER:
            /* Move to lower travel limit */
            //...
        break;
        case STFLT_HOME:
            /* Home the stepper/actuator */
            //...
        break;
        }

        break;
    }

/* No error handling in this example */
return ST_OPRES_SUCCESS;
}


int main(int argc, char *argv[]) {
    STING_CTX stctx = sting_init(my_sting_op, MAX_MOVE, MIN_MOVE, AVGSPEED);

    /* Initialize motor control system */
    //...

    /* Set up our actuator resource */
    my_actuator_t act1;
    act1.hwid = 100;
    //...


    /* Register the actuator with libsting session, and save the STING_ACT value */
    act1.st_act = sting_act_register(stctx, (void *)&act1);


    /* Get motor's current position from motor control API (support not yet available in libsting), home motion axes, etc */
    //...

    /* Move motor 1000 steps, using libsting */
    sting_act_move_relative(stctx, act1.st_act, 1000);

    /* Move it back */
    sting_act_move_relative(stctx, act1.st_act, -1000);     


    /* Terminate libsting session */
    sting_terminate(stctx); 

    return 0;
}

This simplified example uses a hypothetical motor control API, and leaves out a lot of detail.