testing

Dependencies:   mbed tinyshell X_NUCLEO_IHM02A1

main.cpp

Committer:
tom_astranis
Date:
2021-04-02
Revision:
31:ebd464b0d0d8
Parent:
30:a23204ee2be2

File content as of revision 31:ebd464b0d0d8:

#include "mbed.h"

/* Helper header files. */
#include "DevSPI.h"

/* Expansion Board specific header files. */
#include "XNucleoIHM02A1.h"

/* Tinyshell: https://os.mbed.com/users/murilopontes/code/tinyshell/ */
#include "tinysh.h"

#include <cstdlib>
#include <string>

/* Definitions ---------------------------------------------------------------*/

/* Motor specs */
#define MOTOR_SUPPLY_VOLTAGE_V      12.0
#define STEPS_PER_REV               200.0
#define MAX_PHASE_CURRENT_A         0.67
#define PHASE_RES_OHMS              12.0
#define MOTOR_INITIAL_SPEED_SPS     1000.0
#define MOTOR_ACCEL_SPS2            1000.0
#define MOTOR_MAX_SPEED_SPS         1000.0
#define FULL_STEP_TH_SPS            602.7
#define DUMMY_KVAL_V                3.06
#define BEMF_ICPT_SPS               61.52
#define START_SLOPE                 392.1569e-6
#define FINAL_SLOPE                 643.1372e-6
#define OCD_TH_MA                   600.0
#define STALL_TH_MA                 1000.0

/* Behavioral stuff */
#define STATUS_LOG_RATE_HZ 1
#define MIN_LOOP_TIME_MS 1
#define HARD_STOP_WAIT_MS 100

/* Variables -----------------------------------------------------------------*/

/* Motor Control Expansion Board. */
XNucleoIHM02A1 *x_nucleo_ihm02a1;

/* Initialization parameters of the motors connected to the expansion board. */
L6470_init_t init[L6470DAISYCHAINSIZE] = {
    /* First Motor. */
    {
        MOTOR_SUPPLY_VOLTAGE_V,                  /* Motor supply voltage in V. */
        STEPS_PER_REV,                           /* Min number of steps per revolution for the motor. */
        MAX_PHASE_CURRENT_A,                     /* Max motor phase voltage in A. */
        MAX_PHASE_CURRENT_A * PHASE_RES_OHMS,    /* Max motor phase voltage in V. (12 ohms per phase) */
        MOTOR_INITIAL_SPEED_SPS,                 /* Motor initial speed [step/s]. */
        MOTOR_ACCEL_SPS2,                        /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */
        MOTOR_ACCEL_SPS2,                        /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */
        MOTOR_MAX_SPEED_SPS,                     /* Motor maximum speed [step/s]. */
        0.0,                                     /* Motor minimum speed [step/s]. */
        FULL_STEP_TH_SPS,                        /* Motor full-step speed threshold [step/s]. */
        DUMMY_KVAL_V,                            /* Holding kval [V]. */
        DUMMY_KVAL_V,                            /* Constant speed kval [V]. */
        DUMMY_KVAL_V,                            /* Acceleration starting kval [V]. */
        DUMMY_KVAL_V,                            /* Deceleration starting kval [V]. */
        BEMF_ICPT_SPS,                           /* Intersect speed for bemf compensation curve slope changing [step/s]. */
        START_SLOPE,                             /* Start slope [s/step]. */
        FINAL_SLOPE,                             /* Acceleration final slope [s/step]. */
        FINAL_SLOPE,                             /* Deceleration final slope [s/step]. */
        0,                                       /* Thermal compensation factor (range [0, 15]). */
        OCD_TH_MA,                               /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */
        STALL_TH_MA,                             /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */
        StepperMotor::STEP_MODE_FULL,            /* Step mode selection. */
        0xFF,                                    /* Alarm conditions enable. */
        0x2E88                                   /* Ic configuration. */
    },

    /* Second Motor. */
    {
        MOTOR_SUPPLY_VOLTAGE_V,                  /* Motor supply voltage in V. */
        STEPS_PER_REV,                           /* Min number of steps per revolution for the motor. */
        MAX_PHASE_CURRENT_A,                     /* Max motor phase voltage in A. */
        MAX_PHASE_CURRENT_A * PHASE_RES_OHMS,    /* Max motor phase voltage in V. (12 ohms per phase) */
        MOTOR_INITIAL_SPEED_SPS,                 /* Motor initial speed [step/s]. */
        MOTOR_ACCEL_SPS2,                        /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */
        MOTOR_ACCEL_SPS2,                        /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */
        MOTOR_MAX_SPEED_SPS,                     /* Motor maximum speed [step/s]. */
        0.0,                                     /* Motor minimum speed [step/s]. */
        FULL_STEP_TH_SPS,                        /* Motor full-step speed threshold [step/s]. */
        DUMMY_KVAL_V,                            /* Holding kval [V]. */
        DUMMY_KVAL_V,                            /* Constant speed kval [V]. */
        DUMMY_KVAL_V,                            /* Acceleration starting kval [V]. */
        DUMMY_KVAL_V,                            /* Deceleration starting kval [V]. */
        BEMF_ICPT_SPS,                           /* Intersect speed for bemf compensation curve slope changing [step/s]. */
        START_SLOPE,                             /* Start slope [s/step]. */
        FINAL_SLOPE,                             /* Acceleration final slope [s/step]. */
        FINAL_SLOPE,                             /* Deceleration final slope [s/step]. */
        0,                                       /* Thermal compensation factor (range [0, 15]). */
        OCD_TH_MA,                               /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */
        STALL_TH_MA,                             /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */
        StepperMotor::STEP_MODE_FULL,            /* Step mode selection. */
        0xFF,                                    /* Alarm conditions enable. */
        0x2E88                                   /* Ic configuration. */
    }
};

/* Serial Port for console */
Serial pc(USBTX, USBRX);

/* Nasty globals haha */
bool limit_flag = false;
bool status_flag = false;
bool run_flag = false;
bool stop_flag = false;
bool cmd_both = false;
int  which_axis = 0;
int  speed_sps = 0;
int  go_steps = 0;
int  dir_fwd = true;

/* Tinyshell command handler functions */
void set_status_flag(int argc, char **argv)
{
    status_flag = true;
}

// gosteps dir steps (axis)
void set_gosteps_flag(int argc, char **argv)
{    
    if (argc < 3 || argc > 4) {
        printf("\r\nIncorrect number of arguments for: gosteps dir steps (axis)\r\n");
        return;
    }
    
    dir_fwd = true;
    if (argv[1] == std::string("bwd")) dir_fwd = false;
    go_steps = atoi(argv[2]);
    
    if (argc == 3) {
        // both axes
        cmd_both = true;
    } else {
        cmd_both = false;
        which_axis = 0;
        if (argv[3] == std::string("y")) which_axis = 1;
    }
}

// run dir speed (axis)
void set_run_flag(int argc, char **argv)
{
    if (argc < 3 || argc > 4) {
        printf("\r\nIncorrect number of arguments for: run dir steps (axis)\r\n");
        return;
    }

    run_flag = true;
    dir_fwd = true;
    if (argv[1] == std::string("bwd")) dir_fwd = false;
    speed_sps = atoi(argv[2]);

    if (argc == 3) {
        cmd_both = true;
    } else {
        cmd_both = false;
        which_axis = 0;
        if (argv[3] == std::string("y")) which_axis = 1;
    }
}

// stop (axis)
void set_stop_flag(int argc, char **argv)
{
    if (argc > 2) {
        printf("\r\nIncorrect number of arguments for: stop (axis)\r\n");
        return;
    }
    
    stop_flag = true;
    
    if (argc == 1) {
        // both axes
        cmd_both = true;
    } else {
        cmd_both = false;
        which_axis = 0;
        if (argv[1] == std::string("y")) which_axis = 1;
    }    
}

// parent cmd (0 for top) cmd input name, help string, usage string, 
//   function to launch, arg when called, next (0 at init), child (0 at init)
tinysh_cmd_t print_status_cmd = {0, "status", 
    "\r\nPrint content of status registers\r\n", 
    "[no args]", set_status_flag,0,0,0};
tinysh_cmd_t go_steps_cmd = {0, "gosteps", 
    "\r\n'Go n steps', dir = 'fwd' for CW or 'bwd' for CCW, steps = n steps, axis = 'x' or 'y' (omit for both)\r\n", 
    "[dir, steps, (axis)]", set_gosteps_flag,0,0,0};
tinysh_cmd_t run_cmd = {0, "run", 
    "\r\nRun motor, dir = 'fwd' for CW or 'bwd' for CCW, speed in steps per second, axis = 'x' or 'y' (omit for both)\r\n", 
    "[dir, speed, (axis)]", set_run_flag,0,0,0};
tinysh_cmd_t stop_cmd = {0, "stop", 
    "\r\nStop motor, optional axis = 'x' or 'y'; both stopped if omitted\r\n", 
    "[(axis)]", set_stop_flag,0,0,0};

/* mandatory tiny shell output function */
void tinysh_char_out(unsigned char c)
{
    pc.putc(c);
}

/* Main ----------------------------------------------------------------------*/

int main()
{
    /*----- Initialization. -----*/
    unsigned int status_bytes[L6470DAISYCHAINSIZE];
    
    /* Set up tinyshell */
    pc.baud(115200);
    pc.printf("\r\nMotor controller ready\r\n");
    tinysh_set_prompt("> ");
    
    // Add all tinyshell commands here
    tinysh_add_command(&print_status_cmd);
    tinysh_add_command(&run_cmd);
    tinysh_add_command(&go_steps_cmd);
    tinysh_add_command(&stop_cmd);

    /* Initializing SPI bus. */
#ifdef TARGET_STM32F429
    DevSPI dev_spi(D11, D12, D13);
#else
    DevSPI dev_spi(D11, D12, D3);
#endif

    /* Initializing Motor Control Expansion Board. */
    x_nucleo_ihm02a1 = new XNucleoIHM02A1(&init[0], &init[1], A4, A5, D4, A2, &dev_spi);

    /* Building a list of motor control components. */
    L6470 **motors = x_nucleo_ihm02a1->get_components();
   
    // Main loop
    while(1) {
        /* 1: Check for hardware flags ---------------------------------------*/
        if (limit_flag) {
            // clear flag
            limit_flag = false;

            // Hard stop 
            for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                motors[m]->prepare_hard_stop();
            }
            x_nucleo_ihm02a1->perform_prepared_actions();
            
            wait_ms(HARD_STOP_WAIT_MS);
            
            // High Z
            for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                motors[m]->prepare_hard_hiz();
            }
            x_nucleo_ihm02a1->perform_prepared_actions();
        
            printf("\r\nReached limit\r\n");
            /* force prompt display by generating empty command */
            tinysh_char_in('\r');
        }
                
        /* 2: Handle Commands ------------------------------------------------*/
        if (go_steps) {
            // Stop first
            if (cmd_both) {
                for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                    motors[m]->prepare_hard_stop();
                }
                x_nucleo_ihm02a1->perform_prepared_actions();
            } else {
                motors[which_axis]->hard_stop();
            }
            wait_ms(HARD_STOP_WAIT_MS);
            
            if (cmd_both) {
                for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                    if (dir_fwd) motors[m]->prepare_move(StepperMotor::FWD, go_steps);
                    else motors[m]->prepare_move(StepperMotor::BWD, go_steps);
                }
                x_nucleo_ihm02a1->perform_prepared_actions();
            } else {
                if (dir_fwd) motors[which_axis]->move(StepperMotor::FWD, go_steps);
                else motors[which_axis]->move(StepperMotor::BWD, go_steps);
            }
 
            printf("\r\nGoing %s %d steps\r\n", dir_fwd ? "Forward" : "Backward", go_steps);
            /* force prompt display by generating empty command */
            tinysh_char_in('\r');
            
            // Clear flags
            go_steps = 0;
            cmd_both = false;
        }
            
        if (run_flag) {
            // Stop first
            if (cmd_both) {
                // stop both at same time
                for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                    motors[m]->prepare_hard_stop();
                }
                x_nucleo_ihm02a1->perform_prepared_actions();
            } else {
                motors[which_axis]->hard_stop();
            }
            wait_ms(HARD_STOP_WAIT_MS);
            
            if (cmd_both) {
                for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                    if (dir_fwd) motors[m]->prepare_run(StepperMotor::FWD, speed_sps);
                    else motors[m]->prepare_run(StepperMotor::BWD, speed_sps);
                }
                x_nucleo_ihm02a1->perform_prepared_actions();
            } else {
                if (dir_fwd) motors[which_axis]->run(StepperMotor::FWD, speed_sps);
                else motors[which_axis]->run(StepperMotor::BWD, speed_sps);
            }

            printf("\r\nRunning\r\n");
            /* force prompt display by generating empty command */
            tinysh_char_in('\r');

            // Clear flags
            run_flag = false;
            cmd_both = false;
        }

        if (stop_flag) {

            printf("\r\nStopping\r\n");
            /* force prompt display by generating empty command */
            tinysh_char_in('\r');

            // Hard stop 
            if (cmd_both) {
                // stop both at same time
                for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                    motors[m]->prepare_hard_stop();
                }
                x_nucleo_ihm02a1->perform_prepared_actions();
            } else {
                motors[which_axis]->hard_stop();
            }
            wait_ms(HARD_STOP_WAIT_MS);
            
            // High Z
            if (cmd_both) {
                for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                    motors[m]->prepare_hard_hiz();
                }
                x_nucleo_ihm02a1->perform_prepared_actions();
            } else {
                motors[which_axis]->hard_hiz();
            }
            
            // clear flags
            stop_flag = false;
            cmd_both = false;
        }
        
    
        if (status_flag) {
            // Fetch and parse the status register for each motor
            for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
                status_bytes[m] = motors[m]->get_status();
                printf("\r\nStatus reg %d: 0x%02X\r\n", m, status_bytes[m]);
                printf("    STEP-CLOCK MODE:       ");
                printf(status_bytes[m] & 0x8000 ? "SET\r\n" : "NOT SET\r\n");
                printf("    STEP_LOSS_B:           ");
                printf(status_bytes[m] & 0x4000 ? "SET\r\n" : "NOT SET\r\n");
                printf("    STEP_LOSS_A:           ");
                printf(status_bytes[m] & 0x2000 ? "SET\r\n" : "NOT SET\r\n");
                printf("    OVERCURRENT DETECT:    ");
                printf(status_bytes[m] & 0x1000 ? "SET\r\n" : "NOT SET\r\n");
                printf("    THERMAL SHUTDOWN:      ");
                printf(status_bytes[m] & 0x0800 ? "SET\r\n" : "NOT SET\r\n");
                printf("    THERMAL WARN:          ");
                printf(status_bytes[m] & 0x0400 ? "SET\r\n" : "NOT SET\r\n");
                printf("    UNDERVOLTAGE LOCKOUT:  ");
                printf(status_bytes[m] & 0x0200 ? "SET\r\n" : "NOT SET\r\n");
                printf("    WRONG_CMD:             ");
                printf(status_bytes[m] & 0x0100 ? "SET\r\n" : "NOT SET\r\n");
                printf("    NOTPERF_CMD:           ");
                printf(status_bytes[m] & 0x0080 ? "SET\r\n" : "NOT SET\r\n");
                printf("    MOTOR_STATUS:          ");
                if ((status_bytes[m] && 0x0060) >> 5 == 0x00) printf("STOPPED\r\n");
                if ((status_bytes[m] && 0x0060) >> 5 == 0x01) printf("ACCELERATING\r\n");
                if ((status_bytes[m] && 0x0060) >> 5 == 0x10) printf("DECELERATING\r\n");
                if ((status_bytes[m] && 0x0060) >> 5 == 0x11) printf("CONSTANT SPEED\r\n");
                printf("    DIRECTION:             ");
                printf(status_bytes[m] & 0x0010 ? "FWD\r\n" : "REV\r\n");
                printf("    SWITCH TURN-ON EVENT:  ");
                printf(status_bytes[m] & 0x0008 ? "SET\r\n" : "NOT SET\r\n");
                printf("    SWITCH STATUS:         ");
                printf(status_bytes[m] & 0x0004 ? "CLOSED\r\n" : "OPEN\r\n");
                printf("    BUSY:                  ");
                printf(status_bytes[m] & 0x0002 ? "SET\r\n" : "NOT SET\r\n");
                printf("    HI_Z:                  ");
                printf(status_bytes[m] & 0x0001 ? "SET\r\n" : "NOT SET\r\n");
            }
            // clear flag
            status_flag = false;
            /* force prompt display by generating empty command */
            tinysh_char_in('\r');
        }
        
        /* 3: Fetch new chars for Tinyshell ----------------------------------*/
        tinysh_char_in(pc.getc());
        
    } // end main loop
}