demo project

Dependencies:   AX-12A Dynamixel mbed iothub_client EthernetInterface NTPClient ConfigFile SDFileSystem iothub_amqp_transport mbed-rtos proton-c-mbed wolfSSL

ArmController.cpp

Committer:
henryrawas
Date:
2016-01-06
Revision:
11:3a2e6eb9fbb8
Parent:
10:9b21566a5ddb
Child:
13:ffeff9b5e513

File content as of revision 11:3a2e6eb9fbb8:

#include "mbed.h"
#include "rtos.h"

#include "EthernetInterface.h"
#include "mbed/logging.h"
#include "mbed/mbedtime.h"
#include <NTPClient.h>
#include <DynamixelBus.h>
#include <AX12.h>
#include <Terminal.h>
#include <vector>
#include <RobotArm.h>
#include <MeasureBuf.h>
#include <IothubRobotArm.h>
#include <ActionBuf.h>
#include <Sequences.h>
#include <ControllerIo.h>

using namespace std;


vector<float> initPositions;


enum MainStates
{
    MS_Idle           = 0x0,
    MS_Running        = 0x1,
    MS_Paused         = 0x2,
    MS_Stopping       = 0x3,
    MS_Error          = 0x4,
    MS_CancelOne      = 0x5,
    MS_CancelAll      = 0x6,
    MS_CancelToM      = 0x7
};

// try to send some status every minute
#define IDLESTATUSTO        60000
Timer IdleTimer;
int LastSendMs = 0;

Queue<vector<ActionSequence>, 16> SequenceQ;
MainStates MainState;
bool ErrorReset;
bool RunInSequence;
bool RunInMoveStep;
bool RunInDelay;
void* CancelToMatch;

osThreadId mainTid;


void DispMeasure(char* label, int partSize, vector<float>& vals)
{
    printf("%s: ", label);
    for (int ix = 0; ix < partSize; ix++)
    {
        printf("%d:%f ", ix, vals[ix]); 
    }
    printf("\r\n");

}


void PushAlert(int severity, char* msg, char* atype)
{
    Alert alert;
    time_t seconds = time(NULL);
    
    alert.SetAlert(severity, seconds, msg, atype);
    AlertBuf.push(alert);
    SendIothubData();
}

void PushPositionAlert(int severity, int partIx, float pos)
{
    Alert alert;
    time_t seconds = time(NULL);
    
    ShowLedRed();
    alert.SetPositionAlert(severity, seconds, partIx, pos);
    AlertBuf.push(alert);
    SendIothubData();
}

void PushHardwareAlert(int severity, int partIx, int code)
{
    Alert alert;
    time_t seconds = time(NULL);
    
    ShowLedRed();
    alert.SetHardwareAlert(severity, seconds, partIx, code);
    AlertBuf.push(alert);
    SendIothubData();
}

void PushTemperatureAlert(int severity, int partIx, float temp)
{
    Alert alert;
    time_t seconds = time(NULL);
    
    ShowLedRed();
    alert.SetTemperatureAlert(severity, seconds, partIx, temp);
    AlertBuf.push(alert);
    SendIothubData();
}

// send alert if temperature is above 69C and return true
#define MaxTemp     69
bool TestTemperature(vector<float>& vals)
{
    bool err = false;

    for (int ix = 0; ix < vals.size(); ix++)
    {
        if (vals[ix] > MaxTemp)
        {
            printf("Temperature threshold exceeded for part %d, temp %f \r\n", ix, vals[ix]); 
            PushTemperatureAlert(AS_Error, ix, vals[ix]);
            MainState = MS_Error;
            err = true;
        }
    }
    return err;
}


void PushMeasurements(MeasureGroup measureGroup, int partSize, RobotArm robotArm)
{
    vector<float> lastVals;
    time_t seconds = time(NULL);
    LastSendMs = (int)IdleTimer.read_ms();
    
    bool ok = true;
    
    ok = robotArm.GetArmMeasure(NM_Temperature, lastVals);
    DispMeasure("Temperatures", partSize, lastVals);
    measureGroup.SetMeasure(NM_Temperature, seconds, lastVals);
    MeasureBuf.push(measureGroup);
    
    if (ok)
    {
        ok = robotArm.GetArmMeasure(NM_Voltage, lastVals);
        DispMeasure("Voltage", partSize, lastVals);
        measureGroup.SetMeasure(NM_Voltage, seconds, lastVals);
        MeasureBuf.push(measureGroup);
    }
    
    if (ok)
    {
        ok = robotArm.GetArmMeasure(NM_Degrees, lastVals);
        DispMeasure("Rotation", partSize, lastVals);
        measureGroup.SetMeasure(NM_Degrees, seconds, lastVals);
        MeasureBuf.push(measureGroup);
    }
    
//    robotArm.GetArmMeasure(NM_Load, lastVals);
//    DispMeasure("Load", partSize, lastVals);
//    measureGroup.SetMeasure(NM_Load, seconds, lastVals);
//    MeasureBuf.push(measureGroup);

    SendIothubData();
    
    if (!ok)
    {
        // report HW error
        int partix = robotArm.GetLastErrorPart();
        int errCode = robotArm.GetLastError();
        printf("Hardware error detected part %d, code %d \r\n", partix, errCode); 
        PushHardwareAlert(AS_Error, partix, errCode);
        MainState = MS_Error;
    }
}



void ControlArm(const char* cmd)
{
    if (MainState == MS_Error)
    {
        ErrorReset = true;
    }
    
    if (strncmp(cmd, "pause", 5) == 0)
    {
        ShowLedBlue();
        MainState = MS_Paused;
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "resume", 6) == 0)
    {
        ShowLedGreen();
        MainState = MS_Running;
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "cancel", 6) == 0)
    {
        ShowLedGreen();
        MainState = MS_CancelOne;
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "runupdown", 9) == 0)
    {
        ShowLedGreen();
        MainState = MS_CancelOne;
        SequenceQ.put(&UpDownSeq);
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "runuptwist", 10) == 0)
    {
        ShowLedGreen();
        MainState = MS_CancelOne;
        SequenceQ.put(&UpTwistSeq);
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "runhome", 10) == 0)
    {
        ShowLedGreen();
        MainState = MS_CancelOne;
        SequenceQ.put(&StartSeq);
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "runwave", 10) == 0)
    {
        ShowLedGreen();
        MainState = MS_CancelOne;
        SequenceQ.put(&WaveSeq);
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "runtaps1", 10) == 0)
    {
        ShowLedGreen();
        MainState = MS_CancelOne;
        SequenceQ.put(&TapsSeq);
        osSignalSet(mainTid, AS_Action);
    }
    else if (strncmp(cmd, "fastwave", 8) == 0)
    {
        ShowLedGreen();
        MainState = MS_CancelOne;
        SequenceQ.put(&FastWaveSeq);
        osSignalSet(mainTid, AS_Action);
    }
}

// run sequence thread timer routine
void NextSeq(void const * tid)
{
    RunInDelay = false;
    osSignalSet((osThreadId)tid, AS_Action);
}

// periodic timer routine
void PeriodicStatus(void const * tid)
{
    // make sure we run controller even if idle
    osSignalSet((osThreadId)tid, AS_Action);
}

void RunController()
{
    // init robot arm
    RobotArm robotArm;
    
    int partSize = robotArm.GetNumParts();

    IdleTimer.start();
    LastSendMs = (int)IdleTimer.read_ms();
    
    // set running state
    MainState = MS_Idle;
    RunInSequence = false;
    RunInMoveStep = false;
    RunInDelay = false;
    ErrorReset = false;
    
    // get initial positions
    MeasureGroup measureGroup;
    robotArm.GetArmPositions(initPositions);
    
    vector<float> lastVals;
    
    // do inital status report
    PushMeasurements(measureGroup, partSize, robotArm);
 
    // Prepare main thread
    mainTid = osThreadGetId();
    int32_t signals = AS_Action;
    
    // create sequences
    MakeSequences(partSize, initPositions);
  
    // add to queue
    SequenceQ.put(&StartSeq);
    
    // state for sequence
    vector<ActionSequence> *curseq = NULL;
    int curseqIx = 0;
    int loopSeqIx = 0;
    int loopCounter = 0;
    
    // signal to run the default action for demo
    osSignalSet(mainTid, AS_Action);
    
    RtosTimer delayTimer(NextSeq, osTimerOnce, (void *)osThreadGetId());    
    RtosTimer statusTimer(PeriodicStatus, osTimerPeriodic, (void *)osThreadGetId());    
    statusTimer.start(IDLESTATUSTO);
    
    MainState = MS_Running;
    
    while( true )
    {
        osEvent mainEvent = osSignalWait(signals, osWaitForever);
        
        if (ErrorReset)
        {
            ErrorReset = false;
            robotArm.ClearErrorState();
        }
        
        switch (MainState)
        {
            case MS_Idle:
                break;
                
            case MS_Paused:
                printf("Paused\r\n"); 
                break;
                
            case MS_Stopping:
                printf("Stopping\r\n"); 
                break;
                
            case MS_Error:
                printf("Error\r\n"); 
                break;
                
            case MS_CancelOne:
                printf("Cancel sequence\r\n"); 
                RunInSequence = false;
                RunInMoveStep = false;
                if (RunInDelay)
                {
                    RunInDelay = false;
                    delayTimer.stop();
                }
                MainState = MS_Running;
                osSignalSet(mainTid, AS_Action);
                break;
                
            case MS_CancelAll:
                printf("Cancel all\r\n"); 
                RunInSequence = false;
                RunInMoveStep = false;
                if (RunInDelay)
                {
                    RunInDelay = false;
                    delayTimer.stop();
                }
                while (1) {
                    osEvent evt = SequenceQ.get(0);
                    if (evt.status != osEventMessage)
                        break;
                }
                MainState = MS_Running;
                break;
                
            case MS_CancelToM:
                printf("Cancel until latest\r\n"); 
                RunInSequence = false;
                RunInMoveStep = false;
                if (RunInDelay)
                {
                    RunInDelay = false;
                    delayTimer.stop();
                }
                while (1) {
                    osEvent evt = SequenceQ.get(0);
                    if (evt.status != osEventMessage)
                        break;
                    else if (evt.value.p == CancelToMatch)
                    {
                        curseq = (vector<ActionSequence> *)evt.value.p;
                        curseqIx = 0;
                        RunInSequence = true;
                    }
                }
                MainState = MS_Running;
                osSignalSet(mainTid, AS_Action);
                break;
                
            case MS_Running:
                if (RunInDelay)
                {
                    // waiting for timer to fire. do nothing
                    printf("Should be delaying. Skip action\r\n");
                    break;
                }
                if (!RunInSequence)
                {
                    osEvent evt = SequenceQ.get(0);
                    if (evt.status == osEventMessage)
                    {
                        printf("New Seq \r\n"); 
                        curseq = (vector<ActionSequence> *)evt.value.p;
                        curseqIx = 0;
                        RunInSequence = true;
                        RunInMoveStep = false;
                    }
                }
                
                if (RunInSequence)
                {
                    if (RunInMoveStep)
                    {
                        if (!robotArm.MoveArmPositionTest())
                        {
                            // report position error
                            int ix = robotArm.GetLastErrorPart();
                            float diff = robotArm.GetLastPosDiff();
                            printf("Position error detected part %d, diff %f \r\n", ix, diff); 
                            PushPositionAlert(AS_Error, ix, diff);
                            MainState = MS_Error;
                            break;
                        }
                        if (robotArm.MoveArmPositionsHasNext())
                        {
                            int delaystep = 0;
                            bool ok = robotArm.MoveArmPositionsNext();
                            if (ok)
                            {
                                robotArm.MoveArmPositionsDelay(delaystep);
                                if (delaystep > 0)
                                {
                                    RunInDelay = true;
                                    delayTimer.start(delaystep);
                                }
                                else
                                {
                                    osSignalSet(mainTid, AS_Action);
                                }
                            }
                            else
                            {
                                // report HW error
                                int partix = robotArm.GetLastErrorPart();
                                int errCode = robotArm.GetLastError();
                                printf("Hardware error detected part %d, code %d \r\n", partix, errCode); 
                                PushHardwareAlert(AS_Error, partix, errCode);
                                MainState = MS_Error;
                                break;
                            }
                        }
                        else
                        {
                            printf("No more Step\r\n");
                            RunInMoveStep = false;
                        }
                    }
                    if (!RunInMoveStep)
                    {
                        printf("Next Seq %d\r\n", curseqIx); 
                        
                        if (curseq != NULL)
                        {
                            if (curseqIx >= curseq->size())
                            {
                                printf("sequence completed. Stopping\r\n");
                                RunInSequence = false;
                                break;
                            }

                            ActionSequence aseq = (*curseq)[curseqIx];
                            curseqIx++;
                            
                            switch (aseq.ActionType)
                            {
                                case SA_SetGoal:
                                    printf(" - Move arm start\r\n"); 
                                    robotArm.MoveArmPositionsStart(aseq.GoalVals, aseq.Param);
                                    RunInMoveStep = true;
                                    osSignalSet(mainTid, AS_Action);
                                    break;
                                case SA_Delay:
                                    printf(" - Delay\r\n");
                                    RunInDelay = true;
                                    delayTimer.start(aseq.Param);
                                    break;
                                case SA_Status:
                                    printf(" - Status\r\n"); 

                                    PushMeasurements(measureGroup, partSize, robotArm);

                                    robotArm.GetArmLastMeasure(NM_Temperature, lastVals);
                                    TestTemperature(lastVals);
                                    
                                    osSignalSet(mainTid, AS_Action);
                                    break;
                                case SA_LoopBegin:
                                    printf(" - LoopBegin\r\n");
                                    loopSeqIx = curseqIx;
                                    loopCounter = aseq.Param;
                                    osSignalSet(mainTid, AS_Action);
                                    break;
                                case SA_LoopEnd:
                                    printf(" - LoopEnd\r\n");
                                    loopCounter--;
                                    if (loopCounter > 0 && loopSeqIx > 0)
                                        curseqIx = loopSeqIx;
                                    osSignalSet(mainTid, AS_Action);
                                    break;
                            }
                        }
                    }
 
                }
                break;
        }

        int now = (int)IdleTimer.read_ms();
        if (now - LastSendMs > (IDLESTATUSTO - 1000))
        {
            PushMeasurements(measureGroup, partSize, robotArm);
        }
    }
}