demo project

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

Files at this revision

API Documentation at this revision

Comitter:
henryrawas
Date:
Fri Jan 15 22:02:46 2016 +0000
Parent:
12:ac6c9d7f8c40
Child:
14:570c8071f577
Commit message:
Always test status and send data

Changed in this revision

ActionBuf.cpp Show annotated file Show diff for this revision Revisions of this file
ActionBuf.h Show annotated file Show diff for this revision Revisions of this file
Alert.cpp Show annotated file Show diff for this revision Revisions of this file
Alert.h Show annotated file Show diff for this revision Revisions of this file
ArmController.cpp Show annotated file Show diff for this revision Revisions of this file
ControllerIo.cpp Show annotated file Show diff for this revision Revisions of this file
ControllerIo.h Show annotated file Show diff for this revision Revisions of this file
IothubRobotArm.cpp Show annotated file Show diff for this revision Revisions of this file
IothubRobotArm.h Show annotated file Show diff for this revision Revisions of this file
IothubSerial.cpp Show annotated file Show diff for this revision Revisions of this file
MeasureBuf.cpp Show annotated file Show diff for this revision Revisions of this file
MeasureBuf.h Show annotated file Show diff for this revision Revisions of this file
RobotArm.cpp Show annotated file Show diff for this revision Revisions of this file
RobotArm.h Show annotated file Show diff for this revision Revisions of this file
RobotNode/NodeAX12.cpp Show annotated file Show diff for this revision Revisions of this file
RobotNode/NodeAX12.h Show annotated file Show diff for this revision Revisions of this file
RobotNode/NodeEmul.cpp Show annotated file Show diff for this revision Revisions of this file
RobotNode/NodeEmul.h Show annotated file Show diff for this revision Revisions of this file
RobotNode/RobotNode.h Show annotated file Show diff for this revision Revisions of this file
Sequences.cpp Show annotated file Show diff for this revision Revisions of this file
Sequences.h Show annotated file Show diff for this revision Revisions of this file
iothub_client.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/ActionBuf.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/ActionBuf.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -4,9 +4,6 @@
 #include "ActionBuf.h"
 
 
-
-SafeCircBuf<ActionGroup, ActionBufSize, uint32_t> ActionBuf;
-
 bool ActionGroup::SetAction(ArmAction aId, char* args)
 {
     if (strlen(args) < ActionArgSize)
@@ -29,27 +26,35 @@
 {
     ActionType = aType;
     Param = 0;
+    NumParts = 0;
 };
 
-ActionSequence::ActionSequence(SequenceAction aType, vector<float>& vals, int param)
+ActionSequence::ActionSequence(SequenceAction aType, int parts, const float vals[], int param)
 {
     ActionType = aType;
-    GoalVals = vals;
+
+    if (parts > NUMJOINTS) parts = NUMJOINTS;
+    
+    if (vals != NULL)
+    {
+        for (int i = 0; i < parts; i++)
+            GoalVals[i] = vals[i];
+    }
+    NumParts = parts;
+    
     Param = param;
 }
 
-ActionSequence::ActionSequence(SequenceAction aType, int parts, float vals[], int param)
+void ActionSequence::SetGoal(int parts, const float vals[])
 {
-    ActionType = aType;
-    GoalVals.clear();
-    for (int i = 0; i < parts; i++)
-        GoalVals.push_back(vals[i]);
-    Param = param;
-}
-
-void ActionSequence::SetGoal(vector<float>& vals)
-{
-    GoalVals = vals;
+    if (parts > NUMJOINTS) parts = NUMJOINTS;
+    
+    if (vals != NULL)
+    {
+        for (int i = 0; i < parts; i++)
+            GoalVals[i] = vals[i];
+    }
+    NumParts = parts;
 }
 
 void ActionSequence::SetParam(int param)
--- a/ActionBuf.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/ActionBuf.h	Fri Jan 15 22:02:46 2016 +0000
@@ -10,7 +10,6 @@
 #include "RobotArm.h"
 
 
-#define ActionBufSize  100
 #define ActionArgSize  40
 
 class ActionGroup
@@ -25,16 +24,14 @@
     char ActionArg[ActionArgSize];
 };
 
-extern SafeCircBuf<ActionGroup, ActionBufSize, uint32_t> ActionBuf;
 
 
 enum SequenceAction
 {
     SA_SetGoal          = 0x1,
     SA_Delay            = 0x2,
-    SA_Status           = 0x3,
-    SA_LoopBegin        = 0x4,
-    SA_LoopEnd          = 0x5
+    SA_LoopBegin        = 0x3,
+    SA_LoopEnd          = 0x4
 };
 
 class ActionSequence
@@ -44,11 +41,10 @@
     
     ActionSequence(SequenceAction aType);
     
-    ActionSequence(SequenceAction aType, vector<float>& vals, int param);
+ 
+    ActionSequence(SequenceAction aType, int parts, const float vals[], int param);
     
-    ActionSequence(SequenceAction aType, int parts, float vals[], int param);
-    
-    void SetGoal(vector<float>& vals);
+    void SetGoal(int parts, const float vals[]);
     
     void SetParam(int param);
     
@@ -56,7 +52,9 @@
     
     SequenceAction ActionType;
     
-    vector<float> GoalVals;
+    float GoalVals[NUMJOINTS];
+    
+    int NumParts;
     
     int Param;
     
--- a/Alert.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/Alert.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -7,9 +7,8 @@
 
 SafeCircBuf<Alert, AlertBufSize, uint32_t> AlertBuf;
 
-void Alert::SetAlert(int severity, time_t created, char* msg, char* atype)
+void Alert::SetAlert(time_t created, char* msg, char* atype)
 {
-    Sev = severity;
     Created = created;
     
     if (strlen(atype) >= AlertTypeMaxLen)
@@ -33,32 +32,67 @@
 }
 
 
-void Alert::SetPositionAlert(int severity, time_t created, int partIx, float diff)
+void Alert::SetPositionAlert(time_t created, int partIx, float diff)
 {
-    char* msg = "Arm part failed to move to desired position. Part %d is off by %f";
+    char* msg = "Arm joint failed to move to desired position. Joint %d is off by %f";
     int slen = sprintf_s(Msg, AlertMsgMaxLen, msg, partIx, diff);
-    Sev = severity;
+
     Created = created;
+    strcpy(MeasureName, "rot");
+    Index = partIx;
+    Value = diff;
     
     strcpy(AlertType, "Position");
 }
 
-void Alert::SetHardwareAlert(int severity, time_t created, int partIx, int code)
+void Alert::SetLoadAlert(time_t created, int partIx, float val)
 {
-    char* msg = "Arm part reported an error. Part %d error code %d";
+    char* msg = "Arm joint reported a high load. Joint %d, load %f";
+    int slen = sprintf_s(Msg, AlertMsgMaxLen, msg, partIx, val);
+
+    Created = created;
+    strcpy(MeasureName, "load");
+    Index = partIx;
+    Value = val;
+    
+    strcpy(AlertType, "Load");
+}
+
+void Alert::SetHardwareAlert(time_t created, int partIx, int code)
+{
+    char* msg = "Arm joint reported an error. Joint %d error code %d";
     int slen = sprintf_s(Msg, AlertMsgMaxLen, msg, partIx, code);
-    Sev = severity;
+
     Created = created;
+    strcpy(MeasureName, "error");
+    Index = partIx;
+    Value = (float)code;
     
     strcpy(AlertType, "Hardware");
 }
 
-void Alert::SetTemperatureAlert(int severity, time_t created, int partIx, float temp)
+void Alert::SetTemperatureAlert(time_t created, int partIx, float temp)
 {
-    char* msg = "Arm part reported a high temperature. Part %d temperature %f";
+    char* msg = "Arm joint reported a high temperature. Joint %d temperature %f";
     int slen = sprintf_s(Msg, AlertMsgMaxLen, msg, partIx, temp);
-    Sev = severity;
+
     Created = created;
+    strcpy(MeasureName, "temp");
+    Index = partIx;
+    Value = temp;
     
     strcpy(AlertType, "Temperature");
 }
+
+void Alert::SetVoltageAlert(time_t created, int partIx, float val)
+{
+    char* msg = "Arm joint reported an unexpected voltge. Joint %d volt %f";
+    int slen = sprintf_s(Msg, AlertMsgMaxLen, msg, partIx, val);
+
+    Created = created;
+    strcpy(MeasureName, "volt");
+    Index = partIx;
+    Value = val;
+    
+    strcpy(AlertType, "Voltage");
+}
--- a/Alert.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/Alert.h	Fri Jan 15 22:02:46 2016 +0000
@@ -7,36 +7,39 @@
 #include "mbed.h"
 #include "SafeCircBuf.h"
 
-#define AlertBufSize  20
-#define AlertMsgMaxLen  200
+#define AlertBufSize  8
+#define AlertMsgMaxLen  120
 #define AlertTypeMaxLen  16
+#define MeasureNameMaxLen  16
 
-enum AlertSeverity
-{
-    AS_Info     = 0,
-    AS_Warn     = 1,
-    AS_Error    = 2
-};
 
 class Alert
 {
 public:
     Alert() {};
     
-    void SetAlert(int severity, time_t created, char* msg, char* atype);
+    void SetAlert(time_t created, char* msg, char* atype);
     
-    void SetPositionAlert(int severity, time_t created, int partIx, float diff);
+    void SetPositionAlert(time_t created, int partIx, float diff);
+    
+    void SetLoadAlert(time_t created, int partIx, float val);
     
-    void SetHardwareAlert(int severity, time_t created, int partIx, int code);
+    void SetHardwareAlert(time_t created, int partIx, int code);
     
-    void SetTemperatureAlert(int severity, time_t created, int partIx, float temp);
+    void SetTemperatureAlert(time_t created, int partIx, float temp);
     
-    int Sev;
+    void SetVoltageAlert(time_t created, int partIx, float val);
     
     char AlertType[AlertTypeMaxLen];
     
     char Msg[AlertMsgMaxLen];
     
+    int Index;
+    
+    char MeasureName[MeasureNameMaxLen];
+    
+    float Value;
+    
     time_t Created;
 };
 
--- a/ArmController.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/ArmController.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -1,9 +1,7 @@
 #include "mbed.h"
 #include "rtos.h"
 
-#include "EthernetInterface.h"
-#include "mbed/logging.h"
-#include "mbed/mbedtime.h"
+#include "threadapi.h"
 #include <NTPClient.h>
 #include <DynamixelBus.h>
 #include <AX12.h>
@@ -19,155 +17,213 @@
 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
+    MS_Error          = 0x3,
+    MS_CancelOne      = 0x4,
+    MS_CancelAll      = 0x5,
+    MS_Resuming       = 0x6
 };
 
-// try to send some status every minute
-#define IDLESTATUSTO        60000
+// 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 LastSendMs = 0;
+int NextSendMs = 0;
+int NextStepMs = 0;
+int NextPollMs = 0;
 
-Queue<vector<ActionSequence>, 16> SequenceQ;
+// action sequences
+Queue<vector<ActionSequence*>, 8> SequenceQ;
+
+// controller state
 MainStates MainState;
-bool ErrorReset;
 bool RunInSequence;
 bool RunInMoveStep;
-bool RunInDelay;
-void* CancelToMatch;
+
+bool NeedHwReset;
 
-osThreadId mainTid;
-
-
-void DispMeasure(char* label, int partSize, vector<float>& vals)
+// 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");
-
+//    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)
+// send alert message
+void PushAlert(char* msg, char* atype)
 {
     Alert alert;
     time_t seconds = time(NULL);
     
-    alert.SetAlert(severity, seconds, msg, atype);
+    alert.SetAlert(seconds, msg, atype);
     AlertBuf.push(alert);
-    SendIothubData();
 }
 
-void PushPositionAlert(int severity, int partIx, float pos)
+// 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(severity, seconds, partIx, pos);
+    alert.SetPositionAlert(seconds, ix, diff);
     AlertBuf.push(alert);
-    SendIothubData();
+    
+    BuzzerStartMs((int)IdleTimer.read_ms(), 500);
 }
 
-void PushHardwareAlert(int severity, int partIx, int code)
+// 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(severity, seconds, partIx, code);
+    alert.SetHardwareAlert(seconds, partIx, code);
     AlertBuf.push(alert);
-    SendIothubData();
+    NeedHwReset = true;
+        
+    BuzzerStartMs((int)IdleTimer.read_ms(), 500);
 }
 
-void PushTemperatureAlert(int severity, int partIx, float temp)
+// 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(severity, seconds, partIx, temp);
+    alert.SetTemperatureAlert(seconds, ix, lastVals[ix]);
     AlertBuf.push(alert);
-    SendIothubData();
+    
+    BuzzerStartMs((int)IdleTimer.read_ms(), 500);
 }
 
-// send alert if temperature is above 69C and return true
-#define MaxTemp     69
-bool TestTemperature(vector<float>& vals)
+// send temperature alert
+void PushVoltageAlert(RobotArm& robotArm)
 {
-    bool err = false;
+    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]);
 
-    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;
+    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(MeasureGroup measureGroup, int partSize, RobotArm robotArm)
+void PushMeasurements(int partSize, RobotArm& robotArm)
 {
-    vector<float> lastVals;
-    time_t seconds = time(NULL);
-    LastSendMs = (int)IdleTimer.read_ms();
+    // space for getting measurements from arm
+    MeasureGroup measureGroup;
     
+    float lastVals[NUMJOINTS];
+    time_t seconds = time(NULL);
+   
     bool ok = true;
-    
-    ok = robotArm.GetArmMeasure(NM_Temperature, lastVals);
+
+    ok = robotArm.GetArmLastMeasure(NM_Temperature, lastVals);
     DispMeasure("Temperatures", partSize, lastVals);
-    measureGroup.SetMeasure(NM_Temperature, seconds, lastVals);
+    measureGroup.SetMeasure(NM_Temperature, seconds, partSize, lastVals);
     MeasureBuf.push(measureGroup);
     
     if (ok)
     {
-        ok = robotArm.GetArmMeasure(NM_Voltage, lastVals);
+        ok = robotArm.GetArmLastMeasure(NM_Voltage, lastVals);
         DispMeasure("Voltage", partSize, lastVals);
-        measureGroup.SetMeasure(NM_Voltage, seconds, lastVals);
+        measureGroup.SetMeasure(NM_Voltage, seconds, partSize, lastVals);
         MeasureBuf.push(measureGroup);
     }
     
     if (ok)
     {
-        ok = robotArm.GetArmMeasure(NM_Degrees, lastVals);
+        ok = robotArm.GetArmLastMeasure(NM_Degrees, lastVals);
         DispMeasure("Rotation", partSize, lastVals);
-        measureGroup.SetMeasure(NM_Degrees, seconds, lastVals);
+        measureGroup.SetMeasure(NM_Degrees, seconds, partSize, 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)
+    {
+        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 part %d, code %d \r\n", partix, errCode); 
-        PushHardwareAlert(AS_Error, partix, errCode);
+        printf("Hardware error detected joint %d, code %d \r\n", partix, errCode); 
+        PushHardwareAlert(partix, errCode);
         MainState = MS_Error;
     }
 }
@@ -176,146 +232,136 @@
 
 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);
+        MainState = MS_Resuming;
     }
     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;
+        if (MainState == MS_Idle || MainState == MS_Paused)
+            MainState = MS_Running;
         SequenceQ.put(&UpDownSeq);
-        osSignalSet(mainTid, AS_Action);
     }
     else if (strncmp(cmd, "runuptwist", 10) == 0)
     {
         ShowLedGreen();
-        MainState = MS_CancelOne;
+        if (MainState == MS_Idle || MainState == MS_Paused)
+            MainState = MS_Running;
         SequenceQ.put(&UpTwistSeq);
-        osSignalSet(mainTid, AS_Action);
     }
     else if (strncmp(cmd, "runhome", 10) == 0)
     {
         ShowLedGreen();
-        MainState = MS_CancelOne;
+        if (MainState == MS_Idle || MainState == MS_Paused)
+            MainState = MS_Running;
         SequenceQ.put(&StartSeq);
-        osSignalSet(mainTid, AS_Action);
     }
     else if (strncmp(cmd, "runwave", 10) == 0)
     {
         ShowLedGreen();
-        MainState = MS_CancelOne;
+        MainState = MS_Running;
         SequenceQ.put(&WaveSeq);
-        osSignalSet(mainTid, AS_Action);
     }
     else if (strncmp(cmd, "runtaps1", 10) == 0)
     {
         ShowLedGreen();
-        MainState = MS_CancelOne;
+        if (MainState == MS_Idle || MainState == MS_Paused)
+            MainState = MS_Running;
         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);
+        MainState = MS_Running;
+        SequenceQ.put(&BigWaveSeq);
+    }
+    else if (strncmp(cmd, "beep", 9) == 0)
+    {
+        BuzzerStartMs((int)IdleTimer.read_ms(), 500);
     }
 }
 
-// run sequence thread timer routine
-void NextSeq(void const * tid)
+
+// things to initialize early 
+void PrepareController()
 {
-    RunInDelay = false;
-    osSignalSet((osThreadId)tid, AS_Action);
+    MakeSequences(NUMJOINTS);
 }
 
-// periodic timer routine
-void PeriodicStatus(void const * tid)
-{
-    // make sure we run controller even if idle
-    osSignalSet((osThreadId)tid, AS_Action);
-}
-
+// 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();
-    LastSendMs = (int)IdleTimer.read_ms();
     
-    // set running state
+     // 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;
+    NeedHwReset = false;
     
-    // create sequences
-    MakeSequences(partSize, initPositions);
-  
-    // add to queue
+    // set first sequence to run
     SequenceQ.put(&StartSeq);
     
     // state for sequence
-    vector<ActionSequence> *curseq = NULL;
+    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);
+    // 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 )
     {
-        osEvent mainEvent = osSignalWait(signals, osWaitForever);
+        int now = (int)IdleTimer.read_ms();
         
-        if (ErrorReset)
+        // Sleep until next controller poll time 
+        if (NextPollMs > now)
+        {
+            ThreadAPI_Sleep(NextPollMs - now);
+            now = (int)IdleTimer.read_ms();
+        }
+        else
         {
-            ErrorReset = false;
-            robotArm.ClearErrorState();
+            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)
@@ -324,129 +370,78 @@
                 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();
-                }
+                robotArm.MoveArmPositionsEnd();
                 MainState = MS_Running;
-                osSignalSet(mainTid, AS_Action);
+                // avoid next poll delay
+                NextPollMs = now;
                 break;
                 
             case MS_CancelAll:
-                printf("Cancel all\r\n"); 
                 RunInSequence = false;
                 RunInMoveStep = false;
-                if (RunInDelay)
-                {
-                    RunInDelay = false;
-                    delayTimer.stop();
-                }
+                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_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)
                 {
+                    // 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;
+                        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)
                     {
-                        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;
+                        // check if delaying next move
+                        if (NextStepMs > now)
                             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
+                            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);
+                                printf("Hardware error detected joint %d, code %d \r\n", partix, errCode);
+                                PushHardwareAlert(partix, errCode);
                                 MainState = MS_Error;
                                 break;
                             }
@@ -459,8 +454,6 @@
                     }
                     if (!RunInMoveStep)
                     {
-                        printf("Next Seq %d\r\n", curseqIx); 
-                        
                         if (curseq != NULL)
                         {
                             if (curseqIx >= curseq->size())
@@ -470,44 +463,30 @@
                                 break;
                             }
 
-                            ActionSequence aseq = (*curseq)[curseqIx];
+                            ActionSequence* aseq = (*curseq)[curseqIx];
                             curseqIx++;
                             
-                            switch (aseq.ActionType)
+                            switch (aseq->ActionType)
                             {
                                 case SA_SetGoal:
                                     printf(" - Move arm start\r\n"); 
-                                    robotArm.MoveArmPositionsStart(aseq.GoalVals, aseq.Param);
+                                    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);
+                                    NextStepMs = aseq->Param + now;
                                     break;
                                 case SA_LoopBegin:
                                     printf(" - LoopBegin\r\n");
                                     loopSeqIx = curseqIx;
-                                    loopCounter = aseq.Param;
-                                    osSignalSet(mainTid, AS_Action);
+                                    loopCounter = aseq->Param;
                                     break;
                                 case SA_LoopEnd:
                                     printf(" - LoopEnd\r\n");
                                     loopCounter--;
                                     if (loopCounter > 0 && loopSeqIx > 0)
                                         curseqIx = loopSeqIx;
-                                    osSignalSet(mainTid, AS_Action);
                                     break;
                             }
                         }
@@ -516,11 +495,79 @@
                 }
                 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;
 
-        int now = (int)IdleTimer.read_ms();
-        if (now - LastSendMs > (IDLESTATUSTO - 1000))
+            default:
+                nextMetric = NM_Temperature;
+                break;
+        }
+        if (rc == -2)
         {
-            PushMeasurements(measureGroup, partSize, robotArm);
+            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);
+            }
         }
     }
 }
--- a/ControllerIo.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/ControllerIo.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -5,6 +5,10 @@
 DigitalOut redLed(LED_RED);
 DigitalOut blueLed(LED_BLUE);
 
+DigitalOut buzzer(D2, 1);
+
+
+int BuzzStopMs = 0;
 
 void ShowLedColor(int col)
 {
@@ -29,7 +33,36 @@
 {
     ShowLedColor(2);
 }
+
 void ShowLedBlue()
 {
     ShowLedColor(3);
 }
+
+void BuzzerStart()
+{
+    buzzer = 0;
+}
+
+void BuzzerStop()
+{
+    buzzer = 1;
+}
+
+void BuzzerStartMs(int nowMs, int durationMs)
+{
+    BuzzStopMs = nowMs + durationMs;
+    BuzzerStart();
+}
+
+void BuzzerPoll(int nowMs)
+{
+    if (BuzzStopMs != 0)
+    {
+        if (nowMs >= BuzzStopMs)
+        {
+            BuzzStopMs = 0;
+            BuzzerStop();
+        }
+    }
+}
--- a/ControllerIo.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/ControllerIo.h	Fri Jan 15 22:02:46 2016 +0000
@@ -7,8 +7,15 @@
 
 #include "mbed.h"
 
+// LEDs
 extern void ShowLedGreen();
 extern void ShowLedRed();
 extern void ShowLedBlue();
 
+// buzzer
+extern void BuzzerStart();
+extern void BuzzerStop();
+extern void BuzzerStartMs(int nowMs, int durationMs);
+extern void BuzzerPoll(int nowMs);
+
 #endif
--- a/IothubRobotArm.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/IothubRobotArm.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -11,6 +11,7 @@
 
 #include "iothub_client.h"
 #include "iothub_message.h"
+#include "threadapi.h"
 #include "crt_abstractions.h"
 #include "iothubtransportamqp.h"
 #include "MeasureBuf.h"
@@ -96,13 +97,17 @@
     int messageTrackingId;  // For tracking the messages within the user callback.
 } EVENT_INSTANCE;
 
+
 // message buffers to use
-#define MESSAGE_LEN 1024
+#define MESSAGE_LEN         1024
 static char msgText[MESSAGE_LEN];
-//static char propText[MESSAGE_LEN];
+
+#define MESSAGE_COUNT       2
+EVENT_INSTANCE messages[MESSAGE_COUNT];
 
-#define MESSAGE_COUNT 1
-EVENT_INSTANCE messages[MESSAGE_COUNT];
+// send thread poll ms
+#define SEND_POLL_MS        500
+
 
 // context for send & receive
 static int receiveContext;
@@ -129,12 +134,14 @@
     
     if (IoTHubMessage_GetByteArray(message, (const unsigned char**)&buffer, &size) == IOTHUB_MESSAGE_OK)
     {
-        (void)printf("Received Message handle %x with Data: <%.*s> & Size=%d\r\n", message, (int)size, buffer, (int)size);
         int slen = size;
+
         if (size >= 20)
             slen = 19;
         strncpy(cmdbuf, buffer, slen);
         cmdbuf[slen] = 0;
+        (void)printf(cmdbuf);
+        (void)printf("\r\n");
         ControlArm((const char*)cmdbuf);
     }
 
@@ -150,18 +157,12 @@
         printf("SendConfirmation with NULL context\r\n");
         return;
     }
-    (void)printf("Confirmation[%d] received for tracking id = %d with result = %d\r\n", 
-                eventInstance->messageHandle, eventInstance->messageTrackingId, result);
+
+    (void)printf("Confirmation received\r\n");
 
     confirmTimer->stop();
     callbackCounter++;
     IoTHubMessage_Destroy(eventInstance->messageHandle);
-    
-    if (callbackCounter == msgNumber)
-    {
-        // call SendMeasurements again in case more to send
-        SendIothubData();
-    }
 }
 
 // communication timeout
@@ -173,57 +174,59 @@
 
 
 // IoT Hub thread
-static Thread* IotThread = NULL;
+static THREAD_HANDLE IotThread;
 static bool IotThreadClose;
 
 // entry point for ITHub sending thread
-void IothubThread(void const *args)
+int IothubThread(void *args)
 {
     (void)printf("Iothub thread start\r\n");
     IotThreadClose = false;
     IothubRobotArm iotRobot;
  
     confirmTimer = new RtosTimer(CommunicationTO, osTimerOnce, (void *)osThreadGetId());
-    
-    confirmTimer->start(SEND_CONFIRM_TO);
-    InitEthernet();
-    confirmTimer->stop();
-    
+  
     iotRobot.Init();
+    // wait for connection establishment for SSL
+    ThreadAPI_Sleep(15000);
     
     while (1)
     {
-        osEvent ev = Thread::signal_wait(IS_SendStatus);
         if (IotThreadClose)
         {
-            (void)printf("Iothub thread close signal\r\n");
+            (void)printf("Iothub thread close\r\n");
             iotRobot.Terminate();
             break;
         }
         else
         {
-            iotRobot.SendMeasurements();
+            iotRobot.SendMessage();
         }
+        ThreadAPI_Sleep(SEND_POLL_MS);        
     }
+    
+    return 0;
 }
 
 
 bool StartIothubThread()
 {
-    IotThread = new Thread(IothubThread, NULL, osPriorityLow); 
+    InitEthernet();
+    
+    ThreadAPI_Create(&IotThread, IothubThread, NULL);
+ 
+     //IotThread = new Thread(IothubThread, NULL, osPriorityLow); 
     return true;
 }
 
 bool SendIothubData()
 {
-    IotThread->signal_set(IS_SendStatus);
     return true;
 }
 
 void EndIothubThread()
 {
     IotThreadClose = true;
-    IotThread->signal_set(IS_SendStatus);
 }
 
 
@@ -238,9 +241,6 @@
     callbackCounter = 0;
     msgNumber = 0;
     
-    // in case calling init twice without terminate
-    Terminate();
-    
     (void)printf("Starting the IoTHub RobotArm sample AMQP...\r\n");
 
     if ((iotHubClientHandle = IoTHubClient_CreateFromConnectionString(connectionString, AMQP_Protocol)) == NULL)
@@ -285,7 +285,7 @@
 }
 
 
-void IothubRobotArm::SendMeasurements(void)
+void IothubRobotArm::SendMessage(void)
 {
     // send until circular buf empty or no sending buffers avail
     // may drop message if confirmations are slow
@@ -295,12 +295,11 @@
         int i = msgNumber % MESSAGE_COUNT;
     
         int msglen = 0;
-        bool ismeasure = false;
+
         // get alert if any, otherwise get measure data
         msglen = msgSerialize.AlertBufToString(msgText, MESSAGE_LEN);
         if (msglen == 0)
         {
-            ismeasure = true;
             msglen = msgSerialize.MeasureBufToString(msgText, MESSAGE_LEN);
         }
         
@@ -315,7 +314,6 @@
                 messages[i].messageTrackingId = msgNumber;
                 
                 confirmTimer->stop();
-                
                 if (IoTHubClient_SendEventAsync(iotHubClientHandle, messages[i].messageHandle, SendConfirmationCallback, &messages[i]) != IOTHUB_CLIENT_OK)
                 {
                     (void)printf("ERROR: IoTHubClient_SendEventAsync..........FAILED!\r\n");
@@ -323,17 +321,14 @@
                 else
                 {
                     confirmTimer->start(SEND_CONFIRM_TO);
-                    if (ismeasure)
-                        (void)printf("IoTHubClient_SendEventAsync sending data to IoT Hub. tracking id: %d,  bytes: %d\r\n", msgNumber, msglen);
-                    else
-                        (void)printf("IoTHubClient_SendEventAsync sending alert to IoT Hub. tracking id: %d,  bytes: %d\r\n", msgNumber, msglen);
+                   (void)printf("Send async completed\r\n");
                 }
                 msgNumber++;
             }
         }
         else if (msglen == 0)
         {
-            break;
+           break;
         }
         else if (msglen < 0)
         {
--- a/IothubRobotArm.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/IothubRobotArm.h	Fri Jan 15 22:02:46 2016 +0000
@@ -17,7 +17,7 @@
     
     void Terminate();
     
-    void SendMeasurements(void);
+    void SendMessage(void);
 
 private:
 
--- a/IothubSerial.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/IothubSerial.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -2,10 +2,10 @@
 #include "IothubSerial.h"
 #include "crt_abstractions.h"
 
-char* nametemp = "temp";
-char* namevolt = "volt";
-char* namedeg = "rot";
-char* nameload = "load";
+const char* nametemp = "temp";
+const char* namevolt = "volt";
+const char* namedeg = "rot";
+const char* nameload = "load";
 
 IothubSerial::IothubSerial()
 {
@@ -18,7 +18,7 @@
 //  eg: temp: [22.0, 23.1, 22.3],
 int IothubSerial::MeasureGroupToString(MeasureGroup& mg, char* buf, int bufsize)
 {
-    char* name;
+    const char* name;
     int slen;
     int startlen = bufsize;
     
@@ -44,9 +44,21 @@
             return -1;
     }
     
-    if (bufsize > strlen(name) + 5)
+    slen = sprintf_s(buf, bufsize, "\"%s\": [", name);
+    if (slen > 0)
     {
-        slen = sprintf_s(buf, bufsize, "\"%s\": [", name);
+        bufsize -= slen;
+        buf += slen;
+    }
+    else
+        return -1;
+       
+    for (int i = 0; i < mg.NumVals; i++)
+    {
+        if (i < mg.NumVals - 1)
+            slen = sprintf_s(buf, bufsize, "%.2f, ", mg.MeasVals[i]);
+        else
+            slen = sprintf_s(buf, bufsize, "%.2f ", mg.MeasVals[i]);
         if (slen > 0)
         {
             bufsize -= slen;
@@ -55,43 +67,16 @@
         else
             return -1;
     }
-    else
-        return -1;
-        
-    for (int i = 0; i < mg.NumVals; i++)
+    
+    slen = sprintf_s(buf, bufsize, "],");
+    if (slen > 0)
     {
-        if (bufsize > 9)
-        {
-            if (i < mg.NumVals - 1)
-                slen = sprintf_s(buf, bufsize, "%7.2f, ", mg.MeasVals[i]);
-            else
-                slen = sprintf_s(buf, bufsize, "%7.2f ", mg.MeasVals[i]);
-            if (slen > 0)
-            {
-                bufsize -= slen;
-                buf += slen;
-            }
-            else
-                return -1;
-        }
-        else
-            return -1;
-    }
-    
-    if (bufsize > 2)
-    {
-        slen = sprintf_s(buf, bufsize, "],");
-        if (slen > 0)
-        {
-            bufsize -= slen;
-            buf += slen;
-        }
-        else
-            return -1;
+        bufsize -= slen;
+        buf += slen;
     }
     else
         return -1;
-        
+    
     return startlen - bufsize;
 }
 
@@ -112,9 +97,9 @@
 }
 
 // try to serialize one or more measurements into the buffer
-// return bytes used or -1 if buffer too small or other error. 0 if no data
-// current serialization is a json object with entry per measure
-// eg: { "temp": [1, 2], "volt": [12.1, 12.2] }
+// return bytes used / -1 if buffer too small / 0 if no data
+// current serialization is a json array of objects with time and array per measure
+// eg: [{ "time": "2016-01-23T14:55:02", "temp": [1, 2], "volt": [12.1, 12.2] }]
 int IothubSerial::MeasureBufToString(char* buf, int bufsize)
 {
     int slen;
@@ -125,17 +110,14 @@
     char* lastcomma = NULL;
     
     time_t secs = 0;
+    // reserve 1 space for end
+    bufsize--;
     
-    if (bufsize > 1)
+    slen = sprintf_s(buf, bufsize, "[{");
+    if (slen > 0)
     {
-        slen = sprintf_s(buf, bufsize, "{");
-        if (slen > 0)
-        {
-            bufsize -= slen;
-            buf += slen;
-        }
-        else
-            return -1;
+        bufsize -= slen;
+        buf += slen;
     }
     else
         return -1;
@@ -210,7 +192,7 @@
             copydata = true;
         }
         else
-            break;              // no room to serialize, leave pending for mext message
+            break;              // no room to serialize, leave pending for next message
     }
     
     if (!hasdata)
@@ -221,15 +203,18 @@
 
     // replace final ',' with '}'
     *(lastcomma - 1) = '}';
-
+    // this is the extra space we reserved at the start.
+    *(lastcomma) = ']';
+    lastcomma++;
+    
     return lastcomma - startbuf;
 }
 
 
 // try to serialize one or more alerts into the buffer
 // return bytes used or -1 if buffer too small or other error. 0 if no data
-// current serialization is a json object
-// eg: { "alert": "msg", "sev": n }
+// Serialize to a json object with time, measurename, value, message, and index of joint
+// eg: { "alerttype": "Temperature", "message": "too hot", "measurename", "temp", "index": 2, "value": 79.3, "time": "2016-01-23T14:55:02" }
 int IothubSerial::AlertBufToString(char* buf, int bufsize)
 {
     int slen;
@@ -239,8 +224,11 @@
  
     if (AlertBuf.pop(_pendAlert))
     {
+        char tbuf[32];
+        (void)strftime(tbuf, 32, "%FT%T", localtime(&_pendAlert.Created));
         hasdata = true;
-        slen = sprintf_s(buf, bufsize, "{ \"alerttype\": \"%s\", \"alert\": \"%s\", \"sev\": %d }", _pendAlert.AlertType, _pendAlert.Msg, _pendAlert.Sev);
+        slen = sprintf_s(buf, bufsize, "{ \"alerttype\": \"%s\", \"message\": \"%s\", \"measurename\": \"%s\",  \"index\": %d ,  \"value\": %f, \"time\": \"%s\" }", 
+                                            _pendAlert.AlertType, _pendAlert.Msg, _pendAlert.MeasureName, _pendAlert.Index, _pendAlert.Value, tbuf);
         if (slen > 0)
         {
             bufsize -= slen;
--- a/MeasureBuf.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/MeasureBuf.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -6,12 +6,12 @@
 
 SafeCircBuf<MeasureGroup, MeasureBufSize, uint32_t> MeasureBuf;
 
-void MeasureGroup::SetMeasure(NodeMeasure mId, time_t created, vector<float>& vals)
+void MeasureGroup::SetMeasure(NodeMeasure mId, time_t created, int numParts, float vals[])
 {
     MeasId = mId;
     Created = created;
     
-    NumVals = MAX_PARTS < vals.size() ? MAX_PARTS : vals.size();
+    NumVals = NUMJOINTS < numParts ? NUMJOINTS : numParts;
     
     for (int ix = 0; ix < NumVals; ix++)
     {
@@ -19,3 +19,15 @@
     }
 }
 
+MeasureGroup& MeasureGroup::operator=(const MeasureGroup& rhs)
+{
+    MeasId = rhs.MeasId;
+    Created = rhs.Created;
+    NumVals = rhs.NumVals;
+    for (int ix = 0; ix < NUMJOINTS; ix++)
+    {
+        MeasVals[ix] = rhs.MeasVals[ix];
+    }
+    return *this;
+}
+
--- a/MeasureBuf.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/MeasureBuf.h	Fri Jan 15 22:02:46 2016 +0000
@@ -10,7 +10,7 @@
 #include "RobotArm.h"
 
 
-#define MeasureBufSize  20
+#define MeasureBufSize  10
 
 
 class MeasureGroup
@@ -18,13 +18,15 @@
 public:
     MeasureGroup() {};
     
-    void SetMeasure(NodeMeasure mId, time_t created, vector<float>& vals);
+    MeasureGroup& operator=(const MeasureGroup& rhs);
+    
+    void SetMeasure(NodeMeasure mId, time_t created, int numParts, float vals[]);
     
     NodeMeasure MeasId;
     
     int NumVals;
     
-    float MeasVals[MAX_PARTS];
+    float MeasVals[NUMJOINTS];
     
     time_t Created;
 };
--- a/RobotArm.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/RobotArm.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -3,6 +3,7 @@
 
 #include <DynamixelBus.h>
 #include <NodeAX12.h>
+//#include <NodeEmul.h>
 #include <Terminal.h>
 #include <vector>
 #include <RobotArm.h>
@@ -13,64 +14,77 @@
 
 
 // set the id for each part in the chain, in order
-#define NUMPARTS    5
 int PartIds[] = { 2, 3, 4, 6, 1 };
 
-#define FailMsLimit  200
+// default to move every 25 ms
+#define StepPeriodMs        25
+
+// Thresholds
+// allow 3 degrees plus requested move diff for position error
+#define PositionErrorAllow  3.0f
+// time for continuous position error
+#define FailMsLimit         250
+// load level allowance
+#define MaxLoadLimit        950.0f
+// Temperature limit
+#define MaxTemp             69
+// Voltage limits
+#define MaxVoltLimit        13
+#define MinVoltLimit        10
+
 
 RobotArm::RobotArm()
 {
     // build arm
-    for (int i = 0; i < NUMPARTS; i++)
+    for (int ix = 0; ix < NUMJOINTS; ix++)
     {
-        NodeAX12* servo = new NodeAX12(&dynbus, PartIds[i]);
+        NodeAX12* servo = new NodeAX12(&dynbus, PartIds[ix]);
+        //NodeEmul* servo = new NodeEmul(PartIds[i]);
         servo->DoAction(NA_Init, 0.0f);
-        _armParts[i] = dynamic_cast<RobotNode*>(servo);
+        _armParts[ix] = dynamic_cast<RobotNode*>(servo);
     }
-    _numParts = NUMPARTS;
+    _numParts = NUMJOINTS;
 
     numsteps = 0;
-    _stepms = 20; // move every 20 ms
-    allowance = 2.0f;       // allow 2 degree diff for position error
-    failms = 0;
+    _stepms = StepPeriodMs;             
 }
 
+
 void RobotArm::ClearErrorState()
 {
-    for (int i = 0; i < _numParts; i++)
+    for (int ix = 0; ix < _numParts; ix++)
     {
-        _armParts[i]->DoAction(NA_ClearError, 0.0f);
+        _armParts[ix]->DoAction(NA_ClearError, 0.0f);
+        failms[ix] = 0;
     }
 }
 
 // move all parts to specified postions in ms time
-bool RobotArm::MoveArmPositionsStart(vector<float> positions, int totms)
+bool RobotArm::MoveArmPositionsStart(float positions[], int totms)
 {
     _lastErrorPart = 0;
 
     MoveArmPositionsEnd();
+    
     GetArmPositions(lastpos);
-    lastgoals.clear();
-    endgoals.clear();
     
     numsteps = totms / _stepms;
     if (numsteps == 0) numsteps = 1;
     
-    differentials.clear();
     for (int ix = 0; ix < _numParts; ix++)
     {
         if (positions[ix] > 0.0f)
         {
-            endgoals.push_back(positions[ix]);
+            endgoals[ix] = positions[ix];
             float difference = (positions[ix] - lastpos[ix]) / (float)numsteps;
-            differentials.push_back(difference);
+            differentials[ix] = difference;
         }
         else
         {
             // negative goal. Treat as don't move
-            endgoals.push_back(lastpos[ix]);
-            differentials.push_back(0.0f);
+            differentials[ix] = 0.0f;
         }
+        failms[ix] = 0;
     }
 
     curstep = 1;
@@ -79,7 +93,45 @@
     
     elapseTimer.start();
     expDelay = (int)elapseTimer.read_ms() + delayms;
-    failms = 0;
+    
+    return true;
+}
+
+// continue interrupted action
+bool RobotArm::MoveArmPositionsResume()
+{
+    if (curstep > numsteps)
+    {
+        // no more steps 
+        MoveArmPositionsEnd();
+        return true;
+    }
+    GetArmPositions(lastpos);
+    
+    // reset numsteps to be what was remaining
+    numsteps = numsteps - curstep + 1;
+    
+    for (int ix = 0; ix < _numParts; ix++)
+    {
+        if (endgoals[ix] > 0.0f)
+        {
+            float difference = (endgoals[ix] - lastpos[ix]) / (float)numsteps;
+            differentials[ix] = difference;
+        }
+        else
+        {
+            // negative goal. Treat as don't move
+            differentials[ix] = 0.0f;
+        }
+        failms[ix] = 0;
+    }
+
+    curstep = 1;
+    
+    delayms = _stepms;
+    
+    elapseTimer.start();
+    expDelay = (int)elapseTimer.read_ms() + delayms;
     
     return true;
 }
@@ -102,15 +154,14 @@
     
     bool ok = true;
 
-    lastgoals.clear();
     for (int ix = 0; ix < _numParts; ix++)
     {
         if (_armParts[ix]->HasAction(NA_Rotate))
         {
-            float goal = (curstep == numsteps) ?
+            float goal = (curstep == numsteps || differentials[ix] == 0.0f) ?
                             endgoals[ix] :  // last step - use actual goal
                             (lastpos[ix] + (differentials[ix] * (float)curstep));
-            lastgoals.push_back(goal);
+            lastgoals[ix] = goal;
             if (differentials[ix] != 0.0f)
             {
                 bool ok = _armParts[ix]->DoAction(NA_Rotate, goal);
@@ -170,51 +221,19 @@
     return true;
 }
 
-bool RobotArm::MoveArmPositionTest()
+// set goal to current position
+// prevents jump when obstruction is removed
+void RobotArm::MoveArmPositionsStop()
 {
-    vector<float> curpos;
+    float curpos[NUMJOINTS];
     GetArmPositions(curpos);
+    
     for (int ix = 0; ix < _numParts; ix++)
     {
-        if (curpos[ix] > 0 && lastgoals.size() > ix)
-        {
-            float diff = fabs(curpos[ix]  - lastgoals[ix]);
-            if (diff > (fabs(differentials[ix] * 2.0f) + allowance))
-            {
-                printf("Bad position for %d. Expect %f - got %f\r\n", ix, lastgoals[ix], curpos[ix]);
-                _lastPosDiff = diff;
-                _lastErrorPart = ix;
-                _lastError = 0;
+        (void)_armParts[ix]->DoAction(NA_Rotate, curpos[ix]);
+    }
+}
 
-                int elapsed = (int)elapseTimer.read_ms();
-                if (failms > 0)
-                {
-                    if (elapsed - failms > FailMsLimit)
-                    {
-                        // continuous failure for time period
-                        // return false
-                        lastgoals.clear();
-                        failms = 0;
-                        return false;
-                    }
-                    // within time period. Do not report failure
-                    return true;
-                }
-                else
-                {
-                    // first failure after success
-                    // remember time. Do not report failure
-                    failms = elapsed;
-                    return true;
-                }
-            }
-        }
-    }
-    // success
-    failms = 0;
-    return true;
-}
-    
 bool RobotArm::MoveArmPositionsEnd()
 {
     if (numsteps > 0)
@@ -225,16 +244,114 @@
     return true;
 }
 
+extern Timer IdleTimer;
+int RobotArm::ArmMeasuresTest(int measureId)
+{
+    float curvals[NUMJOINTS];
+    
+    if (!GetArmMeasure(measureId, curvals))
+    {
+        return -2;
+    }
+    
+    int rc = 0;
+    
+    switch (measureId)
+    {
+        case NM_Temperature:
+            for (int ix = 0; ix < _numParts; ix++)
+            {
+                float val = curvals[ix];
+                if (val > MaxTemp)
+                {
+                    _lastErrorPart = ix;
+                    rc = -1;
+                    break;
+                }
+            }
+            break;
+            
+        case NM_Degrees:
+            for (int ix = 0; ix < _numParts; ix++)
+            {
+                float val = curvals[ix];
+                if (val > 0.0f)
+                {
+                    float diff = fabs(val  - lastgoals[ix]);
+                    if (diff > (fabs(differentials[ix] * 2.0f) + PositionErrorAllow))
+                    {
+                        int elapsed = (int)elapseTimer.read_ms();
+                        if (failms[ix] > 0)
+                        {
+                            if (elapsed - failms[ix] > FailMsLimit)
+                            {
+                                // continuous failure for time period
+                                // report failure
+                                _lastPosDiff = diff;
+                                _lastErrorPart = ix;
+        
+                                failms[ix] = 0;
+                                rc = -1;
+                            }
+                        }
+                        else
+                        {
+                            // first failure after success
+                            // remember first fail time.
+                            failms[ix] = elapsed;
+                        }
+                    }
+                    else
+                    {
+                        // within allowable range - clear time
+                        failms[ix] = 0;
+                    }
+                }
+            }
+            break;
+        
+        case NM_Voltage:
+            for (int ix = 0; ix < _numParts; ix++)
+            {
+                float val = curvals[ix];
+                if (val > MaxVoltLimit || val < MinVoltLimit)
+                {
+                    _lastErrorPart = ix;
+                    rc = -1;
+                    break;
+                }
+            }
+            break;
+            
+        case NM_Load:
+            for (int ix = 0; ix < _numParts; ix++)
+            {
+                float val = curvals[ix];
+                if (val > MaxLoadLimit)
+                {
+                    _lastErrorPart = ix;
+                    rc = -1;
+                    break;
+                }
+            }
+            break;
+
+            
+        default:
+            break;
+    }
+
+    return rc;
+}
 
 // get all parts positions
-bool RobotArm::GetArmPositions(vector<float>& outPos)
+bool RobotArm::GetArmPositions(float outPos[])
 {
     bool ok = true;
-    outPos.clear();
     for (int ix = 0; ix < _numParts; ix++)
     {
         float pos = _armParts[ix]->GetMeasure(NM_Degrees);
-        outPos.push_back(pos);
+        outPos[ix] = pos;
         if (_armParts[ix]->HasError())
         {
             _lastErrorPart = ix;
@@ -246,14 +363,13 @@
 }
 
 // get all parts last measured positions
-bool RobotArm::GetArmLastPositions(vector<float>& outPos)
+bool RobotArm::GetArmLastPositions(float outPos[])
 {
     bool ok = true;
-    outPos.clear();
     for (int ix = 0; ix < _numParts; ix++)
     {
         float pos = _armParts[ix]->GetLastMeasure(NM_Degrees);
-        outPos.push_back(pos);
+        outPos[ix] = pos;
         if (_armParts[ix]->HasError())
         {
             _lastErrorPart = ix;
@@ -265,14 +381,13 @@
 }
 
 // get all parts measurements
-bool RobotArm::GetArmMeasure(int measureId, vector<float>& outVals)
+bool RobotArm::GetArmMeasure(int measureId, float outVals[])
 {
     bool ok = true;
-    outVals.clear();
     for (int ix = 0; ix < _numParts; ix++)
     {
         float val = _armParts[ix]->GetMeasure(measureId);
-        outVals.push_back(val);
+        outVals[ix] = val;
         if (_armParts[ix]->HasError())
         {
             _lastErrorPart = ix;
@@ -284,14 +399,13 @@
 }
 
 // get all parts last measurements
-bool RobotArm::GetArmLastMeasure(int measureId, vector<float>& outVals)
+bool RobotArm::GetArmLastMeasure(int measureId, float outVals[])
 {
     bool ok = true;
-    outVals.clear();
     for (int ix = 0; ix < _numParts; ix++)
     {
         float val = _armParts[ix]->GetLastMeasure(measureId);
-        outVals.push_back(val);
+        outVals[ix] = val;
         if (_armParts[ix]->HasError())
         {
             _lastErrorPart = ix;
@@ -339,7 +453,3 @@
     return _lastErrorPart;
 }
 
-void RobotArm::SetAllowance(float allow)
-{
-    allowance = allow;
-}
--- a/RobotArm.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/RobotArm.h	Fri Jan 15 22:02:46 2016 +0000
@@ -11,7 +11,8 @@
 #include "DynamixelBus.h"
 #include "NodeAX12.h"
 
-#define MAX_PARTS   8
+// define number of joints for this arm
+#define NUMJOINTS   5
 
 
 enum ArmAction
@@ -43,38 +44,44 @@
     
     RobotArm();
     
-    // start - move all parts to specified postions in ms time
-    bool MoveArmPositionsStart(vector<float> positions, int ms);
+    // move all parts to specified postions in ms time - start
+    bool MoveArmPositionsStart(float positions[], int ms);
+    
+    // move all parts to specified postions - resume after pause
+    bool MoveArmPositionsResume();
 
-    // start - move all parts to specified postions - test if done
+    // move all parts to specified postions - test if done
     bool MoveArmPositionsHasNext();
     
-    // start - move all parts to specified postions - next step
+    // move all parts to specified postions - next step
     bool MoveArmPositionsNext();
 
-    // start - move all parts to specified postions - next delay
+    // move all parts to specified postions - next step delay
     bool MoveArmPositionsDelay(int& nextdelay);
 
-    // start - move all parts to specified postions - finish
+    // move all parts to specified postions - finish
     bool MoveArmPositionsEnd();
     
-    // start - test if positions are close to expected
-    bool MoveArmPositionTest();
+    // reset goal to the current position ie.  stop trying to move
+    void MoveArmPositionsStop();
     
     // clear part error state
     void ClearErrorState();
     
     // get all parts positions
-    bool GetArmPositions(vector<float>& outPos);
+    bool GetArmPositions(float outVals[]);
     
     // get all parts last positions
-    bool GetArmLastPositions(vector<float>& outPos);
+    bool GetArmLastPositions(float outVals[]);
+    
+    // test if measurements are in expected range
+    int ArmMeasuresTest(int measureId);
     
     // get all parts for a measurement
-    bool GetArmMeasure(int measureId, vector<float>& outPos);
+    bool GetArmMeasure(int measureId, float outVals[]);
     
     // get all parts last measurement
-    bool GetArmLastMeasure(int measureId, vector<float>& outPos);
+    bool GetArmLastMeasure(int measureId, float outVals[]);
    
     int GetNumParts();
     
@@ -96,12 +103,9 @@
     // get size of position diff (valid if error)
     float GetLastPosDiff();
     
-    // set allwable position diff
-    void SetAllowance(float allow);
-    
 private:
     // sensors and actuators
-    RobotNode* _armParts[MAX_PARTS];
+    RobotNode* _armParts[NUMJOINTS];
     
     int _numParts;
     
@@ -119,15 +123,15 @@
     float _lastPosDiff;
     
     // step-wise position moves
-    vector<float> endgoals;
-    vector<float> differentials;
-    vector<float> lastpos;
-    vector<float> lastgoals;
+    float endgoals[NUMJOINTS];
+    float differentials[NUMJOINTS];
+    float lastpos[NUMJOINTS];
+    float lastgoals[NUMJOINTS];
     
     // allowance for difference between expected pos and actual pos
     float allowance;
     // keep track of time period when position is off
-    int failms;
+    int failms[NUMJOINTS];
     
     int numsteps;
     int curstep;
--- a/RobotNode/NodeAX12.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/RobotNode/NodeAX12.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -6,7 +6,7 @@
 NodeAX12::NodeAX12(DynamixelBus* pbus, ServoId ID) :
                 _Servo(pbus, ID)
 {
-    _LastPosition= 0.0f;
+    _LastPosition= 0;
     _LastTemperature = 0;
     _LastVoltage = 0;
     _LastLoad = 0;
@@ -60,8 +60,11 @@
         case NM_Load:
             val = (float)_Servo.GetLoad();
             if (val != 0.0f)
+            {
                 _LastLoad = val;
+            }
             return val;
+
             
         default:
             return 0.0f;
@@ -83,8 +86,8 @@
             
         case NM_Load:
             return _LastLoad;
-
-        default:
+ 
+         default:
             return 0.0f;
     }
 }
--- a/RobotNode/NodeAX12.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/RobotNode/NodeAX12.h	Fri Jan 15 22:02:46 2016 +0000
@@ -44,6 +44,7 @@
     
     // last read load
     float _LastLoad;
+
 };
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RobotNode/NodeEmul.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -0,0 +1,121 @@
+
+#include "mbed.h"
+#include "NodeEmul.h"
+#include "threadapi.h"
+
+// emulated device that does nothing
+
+NodeEmul::NodeEmul(int id)
+{
+    _LastPosition= 20.0f + id;
+    _LastTemperature = 30 + id;
+    _LastVoltage = 12 + ((float)id * 0.1f);
+    _LastLoad = 9 + id;
+}
+
+
+bool NodeEmul::HasMeasure(int measureId)
+{
+    switch (measureId)
+    {
+        case NM_Temperature:
+            return true;
+            
+        case NM_Degrees:
+            return true;
+        
+        case NM_Voltage:
+            return true;
+            
+        case NM_Load:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
+float NodeEmul::GetMeasure(int measureId)
+{
+    return GetLastMeasure(measureId);
+}
+
+float NodeEmul::GetLastMeasure(int measureId)
+{
+    switch (measureId)
+    {
+        case NM_Temperature:
+            return (float)_LastTemperature;
+            
+        case NM_Degrees:
+            return _LastPosition;
+        
+        case NM_Voltage:
+            return _LastVoltage;
+            
+        case NM_Load:
+            return _LastLoad;
+
+        default:
+            return 0.0f;
+    }
+}
+
+bool NodeEmul::HasAction(int actionId)
+{
+    switch (actionId)
+    {
+        case NA_Ping:
+            return true;
+            
+        case NA_Init:
+            return true;
+            
+        case NA_Rotate:
+            return true;
+
+        case NA_ClearError:
+            return true;
+            
+        default:
+            return false;
+    }
+}
+
+
+bool NodeEmul::DoAction(int actionId, float actionValue)
+{
+    switch (actionId)
+    {
+        case NA_Ping:
+            return true;
+            
+        case NA_Init:
+            return true;
+
+        case NA_Rotate:
+            _LastPosition = actionValue;
+            return true;
+
+        case NA_ClearError:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
+NodePartType NodeEmul::GetNodeType()
+{
+    return NT_Emul;
+}
+
+int NodeEmul::GetLastError()
+{
+    return 0;
+}
+
+bool NodeEmul::HasError()
+{
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RobotNode/NodeEmul.h	Fri Jan 15 22:02:46 2016 +0000
@@ -0,0 +1,48 @@
+/* 
+Copyright (c) 2015 Jonathan Pickett & Microsoft. Some appropriate open source license.
+*/
+
+#ifndef __NODE_Emul_H__
+#define __NODE_Emul_H__
+
+#include "RobotNode.h"
+
+
+
+class NodeEmul : public RobotNode
+{
+public:
+    NodeEmul(int id);
+    
+    virtual bool HasMeasure(int measureId);
+    
+    virtual float GetMeasure(int measureId);
+    
+    virtual float GetLastMeasure(int measureId);
+    
+    virtual bool HasAction(int actionId);
+    
+    virtual bool DoAction(int actionId, float actionValue);
+    
+    virtual int GetLastError();
+    
+    virtual bool HasError();
+    
+    virtual NodePartType GetNodeType();
+    
+private:
+    
+    // last read temperature
+    int _LastTemperature;
+    
+    // last read position
+    float _LastPosition;
+    
+    // last read voltage
+    float _LastVoltage;
+    
+    // last read load
+    float _LastLoad;
+};
+
+#endif
--- a/RobotNode/RobotNode.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/RobotNode/RobotNode.h	Fri Jan 15 22:02:46 2016 +0000
@@ -23,7 +23,8 @@
 
 enum NodePartType
 {
-    NT_AX12             = 0x1
+    NT_AX12             = 0x1,
+    NT_Emul             = 0x7f
 };
 
 
--- a/Sequences.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/Sequences.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -6,101 +6,85 @@
 const float RightPos = 90.0f;
 const float NoMove = -1.0f;
 
-// this must have same value as in RobotArm
-#define NUMPARTS    5
+
+vector<ActionSequence*> UpDownSeq;
+vector<ActionSequence*> UpTwistSeq;
+vector<ActionSequence*> StartSeq;
+vector<ActionSequence*> WaveSeq;
+vector<ActionSequence*> TapsSeq;
+vector<ActionSequence*> BigWaveSeq;
 
-vector<ActionSequence> UpDownSeq;
-vector<ActionSequence> UpTwistSeq;
-vector<ActionSequence> StartSeq;
-vector<ActionSequence> WaveSeq;
-vector<ActionSequence> TapsSeq;
-vector<ActionSequence> FastWaveSeq;
+const float upPositions[] = { UpPos, UpPos, UpPos, UpPos, UpPos };
+const float downPositions[] = { RightPos, 120.0f, 240.0f, 150.0f, 240.0f };
+const float homePositions[] = { RightPos, 225.0f, 270.0f, 135.0f, UpPos };
+const float waveUpPositions[] = { NoMove, NoMove, NoMove, NoMove, 135.0f };
+const float waveDownPositions[] = { NoMove, NoMove, NoMove, NoMove, 225.0f };
+const float waveMiddlePositions[] = { NoMove, NoMove, NoMove, NoMove, 180.0f };
+const float bigwaveUpPositions[] = { NoMove, 135.0f, NoMove, NoMove, NoMove };
+const float bigwaveDownPositions[] = { NoMove, 225.0f, NoMove, NoMove, NoMove };
+    
+const float tapStartPositions[] = { RightPos, 180.0f, 270.0f, 180.0f, 180.0f };
+const float tap1Positions[] = { 60.2f, NoMove, NoMove, NoMove, NoMove };
+const float tap2Positions[] = { 68.7f, NoMove, NoMove, NoMove, NoMove };
+const float tap3Positions[] = { 77.2f, NoMove, NoMove, NoMove, NoMove };
+const float tap4Positions[] = { 85.7f, NoMove, NoMove, NoMove, NoMove };
+const float tap5Positions[] = { 94.2f, NoMove, NoMove, NoMove, NoMove };
+const float tap6Positions[] = { 102.7f, NoMove, NoMove, NoMove, NoMove };
+const float tap7Positions[] = { 111.2f, NoMove, NoMove, NoMove, NoMove };
+const float tap8Positions[] = { 119.7f, NoMove, NoMove, NoMove, NoMove };
+    
 
-void MakeSequences(int partSize, vector<float>& startPositions)
+void MakeSequences(int partSize)
 {
-    float upPositions[] = { UpPos, UpPos, UpPos, UpPos, UpPos };
-    float downPositions[] = { RightPos, 120.0f, 240.0f, 150.0f, 240.0f };
-    float homePositions[] = { RightPos, 225.0f, 270.0f, 135.0f, UpPos };
-    float rightPositions[] = { UpPos, UpPos, UpPos, UpPos, UpPos };
-    float waveUpPositions[] = { NoMove, NoMove, NoMove, NoMove, 135.0f };
-    float waveDownPositions[] = { NoMove, NoMove, NoMove, NoMove, 225.0f };
-    float waveMiddlePositions[] = { NoMove, NoMove, NoMove, NoMove, 180.0f };
-    float fastwaveUpPositions[] = { NoMove, 135.0f, NoMove, NoMove, NoMove };
-    float fastwaveDownPositions[] = { NoMove, 225.0f, NoMove, NoMove, NoMove };
-    
-    float tapStartPositions[] = { RightPos, 180.0f, 270.0f, 180.0f, 180.0f };
-    float tap1Positions[] = { 60.2f, NoMove, NoMove, NoMove, NoMove };
-    float tap2Positions[] = { 68.7f, NoMove, NoMove, NoMove, NoMove };
-    float tap3Positions[] = { 77.2f, NoMove, NoMove, NoMove, NoMove };
-    float tap4Positions[] = { 85.7f, NoMove, NoMove, NoMove, NoMove };
-    float tap5Positions[] = { 94.2f, NoMove, NoMove, NoMove, NoMove };
-    float tap6Positions[] = { 102.7f, NoMove, NoMove, NoMove, NoMove };
-    float tap7Positions[] = { 111.2f, NoMove, NoMove, NoMove, NoMove };
-    float tap8Positions[] = { 119.7f, NoMove, NoMove, NoMove, NoMove };
-    
     // define actions
-    ActionSequence moveStart(SA_SetGoal, partSize, homePositions, 1500);
-    ActionSequence moveUp(SA_SetGoal, partSize, upPositions, 1000);
-    ActionSequence moveDown(SA_SetGoal, partSize, downPositions, 1000);
-    ActionSequence waveUp(SA_SetGoal, partSize, waveUpPositions, 1000);
-    ActionSequence waveDown(SA_SetGoal, partSize, waveDownPositions, 1000);
-    ActionSequence fastwaveUp(SA_SetGoal, partSize, fastwaveUpPositions, 400);
-    ActionSequence fastwaveDown(SA_SetGoal, partSize, fastwaveDownPositions, 400);
-    ActionSequence tapsStart(SA_SetGoal, partSize, tapStartPositions, 1000);
-    ActionSequence taps1(SA_SetGoal, partSize, tap1Positions, 200);
-    ActionSequence taps2(SA_SetGoal, partSize, tap2Positions, 200);
-    ActionSequence taps3(SA_SetGoal, partSize, tap3Positions, 200);
-    ActionSequence taps4(SA_SetGoal, partSize, tap4Positions, 200);
-    ActionSequence taps5(SA_SetGoal, partSize, tap5Positions, 200);
-    ActionSequence taps6(SA_SetGoal, partSize, tap6Positions, 200);
-    ActionSequence taps7(SA_SetGoal, partSize, tap7Positions, 200);
-    ActionSequence taps8(SA_SetGoal, partSize, tap8Positions, 200);
-    ActionSequence tapDown(SA_SetGoal, partSize, waveDownPositions, 80);
-    ActionSequence tapUp(SA_SetGoal, partSize, waveMiddlePositions, 80);
+    ActionSequence* moveStart = new ActionSequence(SA_SetGoal, partSize, homePositions, 1500);
+    ActionSequence* moveUp = new ActionSequence(SA_SetGoal, partSize, upPositions, 1500);
+    ActionSequence* moveDown = new ActionSequence(SA_SetGoal, partSize, downPositions, 1000);
+    ActionSequence* waveUp = new ActionSequence(SA_SetGoal, partSize, waveUpPositions, 1000);
+    ActionSequence* waveDown = new ActionSequence(SA_SetGoal, partSize, waveDownPositions, 1000);
+    ActionSequence* bigwaveUp = new ActionSequence(SA_SetGoal, partSize, bigwaveUpPositions, 1000);
+    ActionSequence* bigwaveDown = new ActionSequence(SA_SetGoal, partSize, bigwaveDownPositions, 1000);
+    ActionSequence* tapsStart = new ActionSequence(SA_SetGoal, partSize, tapStartPositions, 1000);
+    ActionSequence* taps1 = new ActionSequence(SA_SetGoal, partSize, tap1Positions, 300);
+    ActionSequence* taps2 = new ActionSequence(SA_SetGoal, partSize, tap2Positions, 300);
+    ActionSequence* taps3 = new ActionSequence(SA_SetGoal, partSize, tap3Positions, 300);
+    ActionSequence* taps4 = new ActionSequence(SA_SetGoal, partSize, tap4Positions, 300);
+    ActionSequence* taps5 = new ActionSequence(SA_SetGoal, partSize, tap5Positions, 300);
+    ActionSequence* taps6 = new ActionSequence(SA_SetGoal, partSize, tap6Positions, 300);
+    ActionSequence* taps7 = new ActionSequence(SA_SetGoal, partSize, tap7Positions, 300);
+    ActionSequence* taps8 = new ActionSequence(SA_SetGoal, partSize, tap8Positions, 300);
+    ActionSequence* tapDown = new ActionSequence(SA_SetGoal, partSize, waveDownPositions, 500);
+    ActionSequence* tapUp = new ActionSequence(SA_SetGoal, partSize, waveMiddlePositions, 500);
     
-    ActionSequence report(SA_Status);
-    ActionSequence pause2(SA_Delay);
-    pause2.SetParam(2000);
-    ActionSequence loop20(SA_LoopBegin);  
-    loop20.SetParam(20);
-    ActionSequence loop2(SA_LoopBegin);  
-    loop2.SetParam(2);
-    ActionSequence loopEnd(SA_LoopEnd);  
-    ActionSequence pause100ms(SA_Delay);
-    pause100ms.SetParam(100);
-    ActionSequence pause200ms(SA_Delay);
-    pause200ms.SetParam(200);
-    ActionSequence pause500ms(SA_Delay);
-    pause500ms.SetParam(500);
-    ActionSequence pause1(SA_Delay);
-    pause1.SetParam(1000);
+    ActionSequence* pause2 = new ActionSequence(SA_Delay, 0 , NULL, 2000);
+    ActionSequence* loop20 = new ActionSequence(SA_LoopBegin, 0 , NULL, 20);  
+    ActionSequence* loop2 = new ActionSequence(SA_LoopBegin, 0 , NULL, 2);  
+    ActionSequence* loopEnd = new ActionSequence(SA_LoopEnd);
+    ActionSequence* pause100ms = new ActionSequence(SA_Delay, 0 , NULL, 100);
+    ActionSequence* pause200ms = new ActionSequence(SA_Delay, 0 , NULL, 200);
+    ActionSequence* pause500ms = new ActionSequence(SA_Delay, 0 , NULL, 500);
+    ActionSequence* pause1 = new ActionSequence(SA_Delay, 0 , NULL, 1000);
     
     // add actions into StartSeq
     StartSeq.clear();
     StartSeq.push_back(moveUp);
-    StartSeq.push_back(report);
     
     // add actions into WaveSeq
     WaveSeq.clear();
     WaveSeq.push_back(moveStart);
     WaveSeq.push_back(loop2);
     WaveSeq.push_back(waveUp);
-    WaveSeq.push_back(report);
     WaveSeq.push_back(waveDown);
-    WaveSeq.push_back(report);
     WaveSeq.push_back(loopEnd);
     WaveSeq.push_back(moveUp);
     
     // add actions into UpDownSeq
     UpDownSeq.clear();
     UpDownSeq.push_back(moveUp);
-    UpDownSeq.push_back(report);
     UpDownSeq.push_back(pause1);
     UpDownSeq.push_back(moveDown);
-    UpDownSeq.push_back(report);
+    UpDownSeq.push_back(pause1);
     UpDownSeq.push_back(moveUp);
-    UpDownSeq.push_back(pause1);
-    UpDownSeq.push_back(report);
     
     // add actions into RightStepsSeq
     // move to vertical, then move each part one at a time, then return to home
@@ -109,21 +93,20 @@
     
     for (int partIx = 0; partIx < partSize; partIx++)
     {
+        float pos[NUMJOINTS];
         for (int partIy = 0; partIy < partSize; partIy++)
         {
             if (partIx == partIy)
-                rightPositions[partIy] = RightPos;
+                pos[partIy] = RightPos;
             else
-                rightPositions[partIy] = UpPos;
+                pos[partIy] = UpPos;
         }
 
-        ActionSequence* seq = new ActionSequence(SA_SetGoal, partSize, rightPositions, 1000);
-        UpTwistSeq.push_back(*seq);
+        ActionSequence* seq = new ActionSequence(SA_SetGoal, partSize, pos, 1000);
+        UpTwistSeq.push_back(seq);
         UpTwistSeq.push_back(pause1);
-        UpTwistSeq.push_back(report);
     }
     UpTwistSeq.push_back(moveUp);
-    UpTwistSeq.push_back(report);
     
     // add actions to tap sequence
     TapsSeq.clear();
@@ -156,18 +139,16 @@
     TapsSeq.push_back(taps7);
     TapsSeq.push_back(tapDown);
     TapsSeq.push_back(tapUp);
-    TapsSeq.push_back(report);
     TapsSeq.push_back(moveUp);
 
-    // add actions into FastWaveSeq
-    FastWaveSeq.clear();
-    FastWaveSeq.push_back(moveUp);
-    FastWaveSeq.push_back(loop20);
-    FastWaveSeq.push_back(fastwaveUp);
-    FastWaveSeq.push_back(pause100ms);
-    FastWaveSeq.push_back(fastwaveDown);
-    FastWaveSeq.push_back(pause100ms);
-    FastWaveSeq.push_back(loopEnd);
-    FastWaveSeq.push_back(report);
-
+    // add actions into BigWaveSeq
+    BigWaveSeq.clear();
+    BigWaveSeq.push_back(moveUp);
+    BigWaveSeq.push_back(loop20);
+    BigWaveSeq.push_back(bigwaveUp);
+    BigWaveSeq.push_back(pause100ms);
+    BigWaveSeq.push_back(bigwaveDown);
+    BigWaveSeq.push_back(pause100ms);
+    BigWaveSeq.push_back(loopEnd);
+    
 }
--- a/Sequences.h	Thu Jan 07 17:31:23 2016 +0000
+++ b/Sequences.h	Fri Jan 15 22:02:46 2016 +0000
@@ -5,13 +5,13 @@
 #ifndef __SEQUENCES_H__
 #define __SEQUENCES_H__
 
-extern vector<ActionSequence> UpDownSeq;
-extern vector<ActionSequence> UpTwistSeq;
-extern vector<ActionSequence> StartSeq;
-extern vector<ActionSequence> WaveSeq;
-extern vector<ActionSequence> TapsSeq;
-extern vector<ActionSequence> FastWaveSeq;
+extern vector<ActionSequence*> UpDownSeq;
+extern vector<ActionSequence*> UpTwistSeq;
+extern vector<ActionSequence*> StartSeq;
+extern vector<ActionSequence*> WaveSeq;
+extern vector<ActionSequence*> TapsSeq;
+extern vector<ActionSequence*> BigWaveSeq;
 
-void MakeSequences(int partSize, vector<float>& homePositions);
+void MakeSequences(int partSize);
 
 #endif
--- a/iothub_client.lib	Thu Jan 07 17:31:23 2016 +0000
+++ b/iothub_client.lib	Fri Jan 15 22:02:46 2016 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/AzureIoTClient/code/iothub_client/#02a02ab6402f
+http://mbed.org/users/AzureIoTClient/code/iothub_client/#8bc251cad5f6
--- a/main.cpp	Thu Jan 07 17:31:23 2016 +0000
+++ b/main.cpp	Fri Jan 15 22:02:46 2016 +0000
@@ -9,7 +9,7 @@
 
 Terminal pc(USBTX, USBRX);
 
-
+extern void PrepareController();
 extern void RunController();
 extern bool StartIothubThread();
 
@@ -32,6 +32,9 @@
 
     ShowLedGreen();
     
+    // prepare the motion sequences
+    PrepareController();
+    
     // start IotHub connection
     StartIothubThread();
     
@@ -41,7 +44,9 @@
     
     pc.printf("Initialization done. Ready to run. \r\n");
 
-
+    // try running this thread at a higher priority
+    osThreadId maintid = osThreadGetId();
+    osThreadSetPriority(maintid, osPriorityHigh);
+    
     RunController(); 
-
 }