From 98c65f01a7d2d37ba5a42601dfec6db49dda7f6f Mon Sep 17 00:00:00 2001
From: Jake Read <jake.read@cba.mit.edu>
Date: Thu, 8 Oct 2020 22:37:10 -0400
Subject: [PATCH] fighting the bad interval

---
 .../src/drivers/step_cl.cpp                   | 46 +++++++++++++++----
 log/cl-step-control-log.md                    | 33 ++++++++++++-
 2 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/firmware/cl-step-controller/src/drivers/step_cl.cpp b/firmware/cl-step-controller/src/drivers/step_cl.cpp
index 1424b55..3fd9979 100644
--- a/firmware/cl-step-controller/src/drivers/step_cl.cpp
+++ b/firmware/cl-step-controller/src/drivers/step_cl.cpp
@@ -48,7 +48,7 @@ void Step_CL::init(void){
 boolean Step_CL::calibrate(void){
     // (1) first, build a table for 200 full steps w/ encoder averaged values at each step 
     float phase_angle = 0.0F;
-    for(uint8_t i = 0; i < 200; i ++){
+    for(uint8_t i = 0; i < 200; i ++){ 
         // pt to new angle 
         stepper_hw->point(phase_angle, CALIB_CSCALE);
         // wait to settle / go slowly 
@@ -73,9 +73,8 @@ boolean Step_CL::calibrate(void){
         // rotate 
         phase_angle += 0.25F;
         if(phase_angle >= 1.0F) phase_angle = 0.0F;
-    }
-    // debug print intervals 
-    if(false){
+    } // end measurement taking 
+    if(false){ // debug print intervals 
         for(uint8_t i = 0; i < 199; i ++){
             sysError("int: " + String(i) 
                         + " " + String(calib_readings[i], 4)
@@ -97,10 +96,12 @@ boolean Step_CL::calibrate(void){
     }
     sysError("calib sign: " + String(sign));
 
+    // (2) build the table, walk all encoder counts... 
     // now to build the actual table... 
     // want to start with the 0 indice, 
     for(uint16_t e = 0; e < ENCODER_COUNTS; e ++){
-        // find the interval that spans this sample 
+        // find the interval that spans this sample
+        boolean bi = false; 
         int16_t interval = -1;
         for(uint8_t i = 0; i < 199; i ++){
             if(sign){ // +ve slope readings, left < right 
@@ -126,31 +127,56 @@ boolean Step_CL::calibrate(void){
                 boolean intSign = (calib_readings[i + 1] - calib_readings[i]) > 0 ? true : false;
                 if(intSign != sign){
                     interval = i;
+                    bi = true; // mark the bad interval
                     break;
                 }
             }
+            if(!bi){
+                // truly strange 
+                sysError("missing interval, exiting");
+                return false;
+            }
+            /*
             sysError("bad interval at: " + String(e) 
                     + " " + String(interval)
                     + " " + String(calib_readings[interval]) 
                     + " " + String(calib_readings[interval + 1]));
-            return false;
+            */
         }
         // find anchors 
         float ra0 = 360.0F * ((float)interval / 200);          // real angle at left of interval 
         float ra1 = 360.0F * ((float)(interval + 1) / 200);    // real angle at right of interval 
         // check we are not abt to div / 0: this could happen if motor did not turn during measurement 
         float intSpan = calib_readings[interval - 1] - calib_readings[interval];
+        // invent a span for the bad interval, 
+        if(bi){
+            if(sign){
+                intSpan = calib_readings[interval - 1] - calib_readings[interval] + (float)ENCODER_COUNTS;
+            } else {
+                intSpan = calib_readings[interval - 1] - calib_readings[interval] - (float)ENCODER_COUNTS;
+            }
+        }
         if(intSpan < 0.1F && intSpan > -0.1F){
             sysError("short interval, exiting");
             return false;
         }
         // find pos. inside of interval 
         float offset =  ((float)e - calib_readings[interval]) / intSpan;
-        // find real angle offset at e 
-        float ra = ra0 + (ra1 - ra0) * offset;
+        // find real angle offset at e, modulo for the bad interval 
+        float ra = (ra0 - (ra1 - ra0) * offset);
+        if(ra < 0.0F){
+            ra += 360.0F;
+        } else if (ra > 360.0F){
+            ra -= 360.0F;
+        }
         // log those 
-        sysError("ra: " + String(ra, 4));
-        delay(1);
+        if(bi){
+            sysError("e: " + String(e) + " ra: " + String(ra, 4) + " BI");
+        } else {
+            sysError("e: " + String(e) + " ra: " + String(ra, 4));
+        }
+        delay(10);
     } // end sweep thru 2^14 pts 
+    sysError("calib complete");
     return true; // went OK 
 }
\ No newline at end of file
diff --git a/log/cl-step-control-log.md b/log/cl-step-control-log.md
index f865fcc..a5c2b52 100644
--- a/log/cl-step-control-log.md
+++ b/log/cl-step-control-log.md
@@ -516,4 +516,35 @@ The maths-ey way to do this is to convert to cartesian coordinates, given the th
 
 I guess doing this like that isn't too aweful, tho it's expensive. It would be awesome to have a faster method later on, but there probably better filters (like a kalman) make more sense than just a big ol' average. 
 
-I can imagine taking the measurement spreads: if any were larger than 20 ticks, I could sweep through that set and add the enc_count to the lo vals, then average. Or I could just do this for any reading < 31 ticks, as these are the small ones in *this particular window* but then I have that crawling window issue for measurements really ~ around 31 ticks. Might just be prettier to take a real circular average. 
\ No newline at end of file
+I can imagine taking the measurement spreads: if any were larger than 20 ticks, I could sweep through that set and add the enc_count to the lo vals, then average. Or I could just do this for any reading < 31 ticks, as these are the small ones in *this particular window* but then I have that crawling window issue for measurements really ~ around 31 ticks. Might just be prettier to take a real circular average. 
+
+Here's the circular average:
+
+```cpp
+float x = 0.0F;
+float y = 0.0F;
+for(uint8_t s = 0; s < CALIB_SAMPLE_PER_TICK; s ++){
+    enc_as5047->trigger_read();
+    while(!enc_as5047->is_read_complete()); // do this synchronously 
+    float reading = enc_as5047->get_reading();
+    x += cos((reading / (float)(ENCODER_COUNTS)) * 2 * PI);
+    y += sin((reading / (float)(ENCODER_COUNTS)) * 2 * PI);
+    // this is odd, I know, but it allows a new measurement to settle
+    // so we get a real average 
+    delay(1); 
+}
+// push reading, average removes the wraps added to readings. 
+calib_readings[i] = atan2(y, x);//(reading / (float)CALIB_SAMPLE_PER_TICK) - ENCODER_COUNTS;
+if(calib_readings[i] < 0) calib_readings[i] = 2 * PI + calib_readings[i]; // wrap the circle 
+calib_readings[i] = (calib_readings[i] * ENCODER_COUNTS) / (2 * PI);
+```
+
+I'm getting some strange intervals back, seems like the 'bad interval' is showing up in three chunks, though it should be one span of angles. I think the best way to debug this would be to plot the whole thing out... or I *could* try straight printing it all back on the serport... maybe I'll try that before building a whole packet-transmission-of-hella-floats thing. 
+
+Yeah this looks all kinds of wrong. 
+
+Borked, indeed. Will check tomorrow. Errors just before the BI (nan, so our of index somewhere?) and the BI looks close but not quite there. 
+
+## 2020 10 08 
+
+... 
\ No newline at end of file
-- 
GitLab