Control program for a four-legged 12 axis robot.

Dependencies:   CircularBuffer Servo Terminal mbed Radio

Revision:
19:efba54b23912
Parent:
18:8806d24809c2
Child:
20:bf46c0400b10
--- a/main.cpp	Mon May 27 20:08:03 2013 +0000
+++ b/main.cpp	Mon May 27 23:20:14 2013 +0000
@@ -83,42 +83,43 @@
 
 
 void setupLegs();
+void resetLegs();
 float calcStability(vector3 p1, vector3 p2);
 
-int counter; //debug
+
 
 int main()
 {
     Timer deltaTimer;
-    float xaxis, yaxis, turnaxis, angle;
-    float deltaTime;
-    vector3 v;
-    matrix4 T;
-    matrix4 PA, QA;
-    matrix4 PB, QB; 
-    matrix4 PC, QC; 
-    matrix4 PD, QD;
     Terminal terminal;
     
     terminal.addCommand("log", &log);
     terminal.addCommand("leg", &legpos);
     
     radio.reset();
+    setupLegs();
     
-    setupLegs();
+    // Wrap legs up in an array for convenience
+    RobotLeg* leg[4] = { &legA, &legB, &legC, &legD };
     
     // Create matrices to change base from robot coordinates to leg coordinates
-    QA.translate(vector3(0.0508f, 0.0508f, 0.0f));
-    PA = QA.inverse();
-    QB.translate(vector3(-0.0508f, -0.0508f, 0.0f));
-    QB.a11 = -1.0f; QB.a22 = -1.0f;
-    PB = QB.inverse();
-    QC.translate(vector3(-0.0508f, 0.0508f, 0.0f));
-    QC.a11 = -1.0f;
-    PC = QC.inverse();
-    QD.translate(vector3(0.0508f, -0.0508f, 0.0f));
-    QD.a22 = -1.0f;
-    PD = QD.inverse();
+    matrix4 QMat[4];
+    matrix4 PMat[4];
+    
+    QMat[0].translate(vector3(0.0508f, 0.0508f, 0.0f));
+    QMat[1].translate(vector3(-0.0508f, -0.0508f, 0.0f));
+    QMat[1].a11 = -1.0f; QMat[1].a22 = -1.0f;
+    QMat[2].translate(vector3(-0.0508f, 0.0508f, 0.0f));
+    QMat[2].a11 = -1.0f;
+    QMat[3].translate(vector3(0.0508f, -0.0508f, 0.0f));
+    QMat[3].a22 = -1.0f;
+    
+    PMat[0] = QMat[0].inverse();
+    PMat[1] = QMat[1].inverse();
+    PMat[2] = QMat[2].inverse();
+    PMat[3] = QMat[3].inverse();
+    
+    matrix4 TMat;
     
     // Start timer
     deltaTimer.start();
@@ -128,161 +129,159 @@
         while (deltaTimer.read() < PERIOD);
         
         // Read controller input
-        xaxis = 0.0078125f * deadzone((int8_t)((radio.rx_controller>>0)&0xff), 8); // Convert to +/-1.0f range
-        yaxis = -0.0078125f * deadzone((int8_t)((radio.rx_controller>>8)&0xff), 8);
-        turnaxis = -0.0078125f * deadzone((int8_t)((radio.rx_controller>>16)&0xff), 8);
+        float xaxis = 0.0078125f * deadzone((int8_t)((radio.rx_controller>>0)&0xff), 8); // Convert to +/-1.0f range
+        float yaxis = -0.0078125f * deadzone((int8_t)((radio.rx_controller>>8)&0xff), 8);
+        float turnaxis = -0.0078125f * deadzone((int8_t)((radio.rx_controller>>16)&0xff), 8);
         
         // Get delta-time
-        deltaTime = deltaTimer.read();
+        float deltaTime = deltaTimer.read();
         
-        if ((radio.rx_controller>>25)&0x1) // reset
-        {
-            legA.reset(-0.6f);
-            while (legA.getStepping()) legA.update(T);
-            legB.reset(-0.1f);
-            while (legB.getStepping()) legB.update(T);
-            legC.reset(0.4f);
-            while (legC.getStepping()) legC.update(T);
-            legD.reset(0.9f);
-            while (legD.getStepping()) legD.update(T);
-        }
+        // Reset legs to sane positions when 'A' button is pressed
+        if ((radio.rx_controller>>25)&0x1) resetLegs();
         
         deltaTimer.reset();
-        //dataLog.push(deltaTime);
+        dataLog.push(deltaTime);
         
         // Compute delta movement vector and delta angle
-        v.x = -xaxis;
-        v.y = -yaxis;
-        v.z = 0.0f;
+        vector3 v(-xaxis, -yaxis, 0.0f);
         v = v * MAXSPEED * deltaTime;
-        angle = -turnaxis * MAXTURN * deltaTime;
+        float angle = -turnaxis * MAXTURN * deltaTime;
         
         // Compute movement transformation in robot coordinates
-        T.identity().rotateZ(angle).translate(v).inverse();
-        
-        bool freeA = legA.update(PA*T*QA);
-        bool freeB = legB.update(PB*T*QB);
-        bool freeC = legC.update(PC*T*QC);
-        bool freeD = legD.update(PD*T*QD);
-        
-        // Predict unstable step events and step early in response
-        float distA = legA.getStepDistance();
-        float distB = legB.getStepDistance();
-        float distC = legC.getStepDistance();
-        float distD = legD.getStepDistance();
-        
-        int leastIndex = least(distA, distB, distC, distD);
-        float stability;
-        vector3 point1, point2;
-        const float margin = 0.015f; // radius of support base in meters
+        TMat.identity().rotateZ(angle).translate(v).inverse();
         
-        switch(leastIndex)
+        // Get points used to calculate stability
+        vector3 point1[4];
+        vector3 point2[4];
+        point1[0] = QMat[2]*leg[2]->getPosition();
+        point1[1] = QMat[3]*leg[3]->getPosition();
+        point1[2] = QMat[1]*leg[1]->getPosition();
+        point1[3] = QMat[0]*leg[0]->getPosition();
+        point2[0] = QMat[3]*leg[3]->getPosition();
+        point2[1] = QMat[2]*leg[2]->getPosition();
+        point2[2] = QMat[0]*leg[0]->getPosition();
+        point2[3] = QMat[1]*leg[1]->getPosition();
+        
+        // Check if each leg can perform this motion, find the next leg to step, and calculate stability of each leg
+        bool legFree[4];
+        float stepDist[4];
+        float stability[4];
+        for (int i = 0; i < 4; ++i)
         {
-        case 0:
-            point1 = QC*legC.getPosition();
-            point2 = QD*legD.getPosition();
-            break;
-        case 1:
-            point1 = QD*legD.getPosition();
-            point2 = QC*legC.getPosition();
-            break;
-        case 2:
-            point1 = QB*legB.getPosition();
-            point2 = QA*legA.getPosition();
-            break;
-        case 3:
-            point1 = QA*legA.getPosition();
-            point2 = QB*legB.getPosition();
-            break;
+            legFree[i] = leg[i]->update(PMat[i]*TMat*QMat[i]);
+            stepDist[i] = leg[i]->getStepDistance();
+            stability[i] = calcStability(point1[i], point2[i]);
         }
         
-        
+        // Check if each leg needs to step, and then check if it's stable before stepping
+        bool stepping = leg[0]->getStepping() || leg[1]->getStepping() || leg[2]->getStepping() || leg[3]->getStepping();
+        bool changedMotion = false;
+        const float borderMax = 0.015f; // radius of support base in meters
+        const float borderMin = 0.007f;
         
-        stability = calcStability(point1, point2);
-        bool stepEarly = stability < margin && stability > 0.0f;
-        
-        // debug stuff
-        if ((counter++%50)==0)
+        for (int i = 0; i < 4; ++i)
         {
-            char buf[256];
-            char vbuf[64];
-            char vbuf2[64];
-            point1.print(vbuf, 64);
-            point2.print(vbuf2, 64);
-            snprintf(buf, 256, "n = %d; p1 = %s; p1 = %s; s = %f\n", leastIndex, vbuf, vbuf2, stability); 
-            terminal.write(buf);
+            if (!legFree[i])
+            {
+                if (stepping)
+                {
+                    TMat.identity();
+                    changedMotion = true;
+                }
+                else 
+                {
+                    if (stability[i] > borderMin)
+                    {
+                        // If stable, step
+                        leg[i]->reset(0.8);
+                        stepping = true;
+                    }
+                    else
+                    {
+                        // If unstable, move towards a stable position
+                        vector3 n;
+                        n.x = point2[i].y - point1[i].y;
+                        n.y = point1[i].x - point2[i].x;
+                        n = n.unit() * MAXSPEED * deltaTime;
+                        TMat.identity().translate(n).inverse();
+                        changedMotion = true;
+                    }
+                }
+            }
         }
         
-        if (stability < 0.0f)
+        if (!changedMotion)
         {
-            // Move towards stable zone
-            vector3 n;
-            n.x = point2.y - point1.y;
-            n.y = point1.x - point2.x;
-            n = n.unit() * MAXSPEED * deltaTime;
-            T.identity().translate(v).inverse();
+            // Check if the next leg to step is stable
+            int next = least(stepDist[0], stepDist[1], stepDist[2], stepDist[3]);
+            if (stepDist[next] > borderMax)
+            {
+                // Continue to carry out step as normal
+            }
+            else if (stepDist[next] > borderMin)
+            {
+                if (stepping)
+                {
+                    TMat.identity();
+                    changedMotion = true;
+                }
+                else 
+                {
+                    leg[next]->reset(0.8);
+                    stepping = true;
+                }
+            }
+            else
+            {
+                // If unstable, move towards a stable position
+                vector3 n;
+                n.x = point2[next].y - point1[next].y;
+                n.y = point1[next].x - point2[next].x;
+                n = n.unit() * MAXSPEED * deltaTime;
+                TMat.identity().translate(n).inverse();
+                changedMotion = true;
+            }
+        }
+        
+        if (changedMotion)
+        {
+            for (int i = 0; i < 4; ++i)
+            {
+                leg[i]->update(PMat[i]*TMat*QMat[i]);
+            }
+        }
+        
+        for (int i = 0; i < 4; ++i)
+        {
+            leg[i]->apply();
         }
         
         // Debug info
-        dataLog.push(stability);
-        led1 = calcStability(QC*legC.getPosition(), QD*legD.getPosition()) > 0.0f;
-        led2 = calcStability(QD*legD.getPosition(), QC*legC.getPosition()) > 0.0f;
-        led3 = calcStability(QB*legB.getPosition(), QA*legA.getPosition()) > 0.0f;
-        led4 = calcStability(QA*legA.getPosition(), QB*legB.getPosition()) > 0.0f;
-        
-        // Prevent multiple legs from stepping at the same time
-        bool stepping = legA.getStepping() || legB.getStepping() || legC.getStepping() || legD.getStepping();
-        bool lockup = false;
+        led1 = stability[0] > borderMin;
+        led2 = stability[1] > borderMin;
+        led3 = stability[2] > borderMin;
+        led4 = stability[3] > borderMin;
         
-        if (!freeA || (0 == leastIndex && stepEarly))
-        {
-            if (stepping) lockup = true;
-            else 
-            {
-                legA.reset(0.8);
-                stepping = true;
-            }
-        }
-        if (!freeB || (1 == leastIndex && stepEarly))
-        {
-            if (stepping) lockup = true;
-            else 
-            {
-                legB.reset(0.8f);
-                stepping = true;
-            }
-        }
-        if (!freeC || (2 == leastIndex && stepEarly))
-        {
-            if (stepping) lockup = true;
-            else 
-            {
-                legC.reset(0.8f);
-                stepping = true;
-            }
-        }
-        if (!freeD || (3 == leastIndex && stepEarly))
-        {
-            if (stepping) lockup = true;
-            else 
-            {
-                legD.reset(0.8f);
-                stepping = true;
-            }
-        }
-        
-        if (!lockup)
-        {
-            legA.apply();
-            legB.apply();
-            legC.apply();
-            legD.apply();
-        }
     } // while (true)
 } // main()
 
 
 
+void resetLegs()
+{
+    matrix4 T;
+    legA.reset(-0.6f);
+    while (legA.getStepping()) legA.update(T);
+    legB.reset(-0.1f);
+    while (legB.getStepping()) legB.update(T);
+    legC.reset(0.4f);
+    while (legC.getStepping()) legC.update(T);
+    legD.reset(0.9f);
+    while (legD.getStepping()) legD.update(T);
+}
+
+
+
 void setupLegs()
 {
     // Set leg parameters
@@ -335,10 +334,7 @@
     legC.psi.enable(); wait(0.1f);
     legD.psi.enable(); wait(0.1f);
     wait(0.4f);
-    legA.reset(-0.6f);
-    legB.reset(-0.1f);
-    legC.reset(0.4f);
-    legD.reset(0.9f);
+    resetLegs();
 }