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-15
- Revision:
- 13:ffeff9b5e513
- Parent:
- 11:3a2e6eb9fbb8
- Child:
- 14:570c8071f577
File content as of revision 13:ffeff9b5e513:
#include "mbed.h" #include "rtos.h" #include "threadapi.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; enum MainStates { MS_Idle = 0x0, MS_Running = 0x1, MS_Paused = 0x2, MS_Error = 0x3, MS_CancelOne = 0x4, MS_CancelAll = 0x5, MS_Resuming = 0x6 }; // controller thread runs every 25ms #define CONTROLLER_POLL 25 // try to send some status every few seconds #define SEND_STATUS_TO 500 // use slower send rate if paused #define SEND_STATUS_PAUSED_TO 20000 // controller polling timer Timer IdleTimer; int NextSendMs = 0; int NextStepMs = 0; int NextPollMs = 0; // action sequences Queue<vector<ActionSequence*>, 8> SequenceQ; // controller state MainStates MainState; bool RunInSequence; bool RunInMoveStep; bool NeedHwReset; // utility method void DispMeasure(char* label, int partSize, float vals[]) { // printf("%s: ", label); // for (int ix = 0; ix < partSize; ix++) // { // printf("%d:%f ", ix, vals[ix]); // } // printf("\r\n"); } // send alert message void PushAlert(char* msg, char* atype) { Alert alert; time_t seconds = time(NULL); alert.SetAlert(seconds, msg, atype); AlertBuf.push(alert); } // send position alert void PushPositionAlert(RobotArm& robotArm) { // stop trying to move float diff = robotArm.GetLastPosDiff(); int ix = robotArm.GetLastErrorPart(); robotArm.MoveArmPositionsStop(); // report load error printf("Position error detected joint %d, value diff %f\r\n", ix, diff); Alert alert; time_t seconds = time(NULL); ShowLedRed(); alert.SetPositionAlert(seconds, ix, diff); AlertBuf.push(alert); BuzzerStartMs((int)IdleTimer.read_ms(), 500); } // send load alert void PushLoadAlert(RobotArm& robotArm) { float lastVals[NUMJOINTS]; // stop trying to move robotArm.GetArmLastMeasure(NM_Load, lastVals); int ix = robotArm.GetLastErrorPart(); robotArm.MoveArmPositionsStop(); // report load error printf("Load error detected joint %d, value %f\r\n", ix, lastVals[ix]); Alert alert; time_t seconds = time(NULL); ShowLedRed(); alert.SetLoadAlert(seconds, ix, lastVals[ix]); AlertBuf.push(alert); BuzzerStartMs((int)IdleTimer.read_ms(), 500); } // send hardware error alert void PushHardwareAlert(int partIx, int code) { Alert alert; time_t seconds = time(NULL); ShowLedRed(); alert.SetHardwareAlert(seconds, partIx, code); AlertBuf.push(alert); NeedHwReset = true; BuzzerStartMs((int)IdleTimer.read_ms(), 500); } // send temperature alert void PushTemperatureAlert(RobotArm& robotArm) { float lastVals[NUMJOINTS]; // stop trying to move robotArm.GetArmLastMeasure(NM_Temperature, lastVals); int ix = robotArm.GetLastErrorPart(); robotArm.MoveArmPositionsStop(); // report load error printf("Temperature error detected joint %d, value %f\r\n", ix, lastVals[ix]); Alert alert; time_t seconds = time(NULL); ShowLedRed(); alert.SetTemperatureAlert(seconds, ix, lastVals[ix]); AlertBuf.push(alert); BuzzerStartMs((int)IdleTimer.read_ms(), 500); } // send temperature alert void PushVoltageAlert(RobotArm& robotArm) { float lastVals[NUMJOINTS]; // stop trying to move robotArm.GetArmLastMeasure(NM_Voltage, lastVals); int ix = robotArm.GetLastErrorPart(); robotArm.MoveArmPositionsStop(); // report load error printf("Voltage error detected joint %d, value %f\r\n", ix, lastVals[ix]); Alert alert; time_t seconds = time(NULL); ShowLedRed(); alert.SetVoltageAlert(seconds, ix, lastVals[ix]); AlertBuf.push(alert); BuzzerStartMs((int)IdleTimer.read_ms(), 500); } void PushMeasurements(int partSize, RobotArm& robotArm) { // space for getting measurements from arm MeasureGroup measureGroup; float lastVals[NUMJOINTS]; time_t seconds = time(NULL); bool ok = true; ok = robotArm.GetArmLastMeasure(NM_Temperature, lastVals); DispMeasure("Temperatures", partSize, lastVals); measureGroup.SetMeasure(NM_Temperature, seconds, partSize, lastVals); MeasureBuf.push(measureGroup); if (ok) { ok = robotArm.GetArmLastMeasure(NM_Voltage, lastVals); DispMeasure("Voltage", partSize, lastVals); measureGroup.SetMeasure(NM_Voltage, seconds, partSize, lastVals); MeasureBuf.push(measureGroup); } if (ok) { ok = robotArm.GetArmLastMeasure(NM_Degrees, lastVals); DispMeasure("Rotation", partSize, lastVals); measureGroup.SetMeasure(NM_Degrees, seconds, partSize, lastVals); MeasureBuf.push(measureGroup); } if (ok) { robotArm.GetArmLastMeasure(NM_Load, lastVals); DispMeasure("Load", partSize, lastVals); measureGroup.SetMeasure(NM_Load, seconds, partSize, lastVals); MeasureBuf.push(measureGroup); } if (!ok) { // report HW error int partix = robotArm.GetLastErrorPart(); int errCode = robotArm.GetLastError(); printf("Hardware error detected joint %d, code %d \r\n", partix, errCode); PushHardwareAlert(partix, errCode); MainState = MS_Error; } } void ControlArm(const char* cmd) { if (strncmp(cmd, "pause", 5) == 0) { ShowLedBlue(); MainState = MS_Paused; } else if (strncmp(cmd, "resume", 6) == 0) { ShowLedGreen(); MainState = MS_Resuming; } else if (strncmp(cmd, "cancel", 6) == 0) { ShowLedGreen(); MainState = MS_CancelOne; } else if (strncmp(cmd, "runupdown", 9) == 0) { ShowLedGreen(); if (MainState == MS_Idle || MainState == MS_Paused) MainState = MS_Running; SequenceQ.put(&UpDownSeq); } else if (strncmp(cmd, "runuptwist", 10) == 0) { ShowLedGreen(); if (MainState == MS_Idle || MainState == MS_Paused) MainState = MS_Running; SequenceQ.put(&UpTwistSeq); } else if (strncmp(cmd, "runhome", 10) == 0) { ShowLedGreen(); if (MainState == MS_Idle || MainState == MS_Paused) MainState = MS_Running; SequenceQ.put(&StartSeq); } else if (strncmp(cmd, "runwave", 10) == 0) { ShowLedGreen(); MainState = MS_Running; SequenceQ.put(&WaveSeq); } else if (strncmp(cmd, "runtaps1", 10) == 0) { ShowLedGreen(); if (MainState == MS_Idle || MainState == MS_Paused) MainState = MS_Running; SequenceQ.put(&TapsSeq); } else if (strncmp(cmd, "fastwave", 8) == 0) { ShowLedGreen(); MainState = MS_Running; SequenceQ.put(&BigWaveSeq); } else if (strncmp(cmd, "beep", 9) == 0) { BuzzerStartMs((int)IdleTimer.read_ms(), 500); } } // things to initialize early void PrepareController() { MakeSequences(NUMJOINTS); } // Run the controller thread loop void RunController() { printf("RunController start"); // init robot arm RobotArm robotArm; robotArm.SetStepMs(CONTROLLER_POLL); int partSize = robotArm.GetNumParts(); IdleTimer.start(); // set running state MainState = MS_Idle; RunInSequence = false; RunInMoveStep = false; NeedHwReset = false; // set first sequence to run SequenceQ.put(&StartSeq); // state for sequence vector<ActionSequence*> *curseq = NULL; int curseqIx = 0; int loopSeqIx = 0; int loopCounter = 0; // init time outs NextStepMs = 0; NextPollMs = (int)IdleTimer.read_ms(); NextSendMs = (int)IdleTimer.read_ms() + SEND_STATUS_TO; MainState = MS_Running; NodeMeasure nextMetric = NM_Temperature; while( true ) { int now = (int)IdleTimer.read_ms(); // Sleep until next controller poll time if (NextPollMs > now) { ThreadAPI_Sleep(NextPollMs - now); now = (int)IdleTimer.read_ms(); } else { printf("too slow %d\r\n", now - NextPollMs); } // set next poll time NextPollMs = now + CONTROLLER_POLL; // if had HW error, reset error state if (MainState != MS_Error) { if (NeedHwReset) { robotArm.ClearErrorState(); NeedHwReset = false; } } switch (MainState) { case MS_Idle: break; case MS_Paused: break; case MS_Error: break; case MS_CancelOne: RunInSequence = false; RunInMoveStep = false; robotArm.MoveArmPositionsEnd(); MainState = MS_Running; // avoid next poll delay NextPollMs = now; break; case MS_CancelAll: RunInSequence = false; RunInMoveStep = false; robotArm.MoveArmPositionsEnd(); while (1) { osEvent evt = SequenceQ.get(0); if (evt.status != osEventMessage) break; } // avoid next poll delay NextPollMs = now; MainState = MS_Running; break; case MS_Resuming: robotArm.MoveArmPositionsResume(); // avoid next poll delay NextPollMs = now; MainState = MS_Running; break; case MS_Running: if (!RunInSequence) { // start new sequence of actions 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; } else { MainState = MS_Idle; } } if (RunInSequence) { if (RunInMoveStep) { // check if delaying next move if (NextStepMs > now) break; if (robotArm.MoveArmPositionsHasNext()) { bool ok = robotArm.MoveArmPositionsNext(); if (!ok) { // report HW error int partix = robotArm.GetLastErrorPart(); int errCode = robotArm.GetLastError(); printf("Hardware error detected joint %d, code %d \r\n", partix, errCode); PushHardwareAlert(partix, errCode); MainState = MS_Error; break; } } else { printf("No more Step\r\n"); RunInMoveStep = false; } } if (!RunInMoveStep) { 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; break; case SA_Delay: printf(" - Delay\r\n"); NextStepMs = aseq->Param + now; break; case SA_LoopBegin: printf(" - LoopBegin\r\n"); loopSeqIx = curseqIx; loopCounter = aseq->Param; break; case SA_LoopEnd: printf(" - LoopEnd\r\n"); loopCounter--; if (loopCounter > 0 && loopSeqIx > 0) curseqIx = loopSeqIx; break; } } } } break; } bool sendAlert = MainState != MS_Error; // get measurements and test thresholds // Reading all values takes too long, // so we read the load and 1 other value each time int rc = 0; rc = robotArm.ArmMeasuresTest(NM_Load); if (rc < 0 && sendAlert) { PushLoadAlert(robotArm); MainState = MS_Error; } switch (nextMetric) { case NM_Temperature: rc = robotArm.ArmMeasuresTest(NM_Temperature); if (rc < 0 && sendAlert) { PushTemperatureAlert(robotArm); MainState = MS_Error; } nextMetric = NM_Voltage; break; case NM_Voltage: rc = robotArm.ArmMeasuresTest(NM_Voltage); if (rc < 0 && sendAlert) { PushVoltageAlert(robotArm); MainState = MS_Error; } nextMetric = NM_Degrees; break; case NM_Degrees: rc = robotArm.ArmMeasuresTest(NM_Degrees); if (rc < 0 && sendAlert) { PushPositionAlert(robotArm); MainState = MS_Error; } nextMetric = NM_Temperature; break; default: nextMetric = NM_Temperature; break; } if (rc == -2) { int partix = robotArm.GetLastErrorPart(); int errCode = robotArm.GetLastError(); printf("Hardware error detected joint %d, code %d \r\n", partix, errCode); PushHardwareAlert(partix, errCode); MainState = MS_Error; } // check if buzzer needs to be turned off BuzzerPoll(now); // check if time to send status if (now >= NextSendMs) { // if paused, use longer time out for sending data if (MainState != MS_Paused || now > NextSendMs + SEND_STATUS_PAUSED_TO) { NextSendMs = now + SEND_STATUS_TO; PushMeasurements(partSize, robotArm); } } } }