Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Revision:
113:7330439f2ffc
Parent:
111:42dc75fbe623
--- a/Plunger/distanceSensor.h	Thu Apr 29 19:56:49 2021 +0000
+++ b/Plunger/distanceSensor.h	Wed Jun 02 02:14:27 2021 +0000
@@ -20,6 +20,25 @@
 //
 // Here are the specific sensor types we currently support:
 //
+// VCNL4010: An IR proximity sensor.  This sensor shines an IR light at a
+// target and measures the intensity of the reflected light.  This doesn't
+// measure distance per se, but since the intensity of a light source
+// falls off as the square of the distance, we can use the reflected
+// intensity as a proxy for the distance by calculating 1/sqrt(intensity).
+// The main reason to support this type of sensor is that it's used in the
+// VirtuaPin v3 plunger kit, and several people have requested support so
+// that they can move re-flash that kit using the Pinscape software and
+// continue using their existing plunger sensor.  Many people might also
+// consider this sensor for new DIY builds, since it produces pretty good
+// results.  It's not as accurate as a potentiometer or quadrature sensor,
+// but it yields low-noise results with good enough precision for smooth
+// on-screen animation (maybe around 1mm precision).  Its main drawback
+// is that it's relatively slow (250 Hz maximum sampling rate), but it's
+// still fast enough to be usable.  It has several virtues that might more
+// than orffset its technical limitations for many paople: it's easy to
+// set up physically, it's completely non-contact, and it's cheap (under
+// $10 for the Adafruit breakout board).
+// 
 // VL6180X: This is an optical (IR) "time of flight" sensor that measures
 // the distance to the target by sending optical pings and timing the 
 // return signal, converting the result to distance via the known speed 
@@ -31,22 +50,6 @@
 // set up than most of the better options, so it might be attractive to
 // some cab builders despite the quality tradeoffs.
 //
-// VCNL4010: An IR proximity sensor.  This sensor shines an IR light at a
-// target and measures the intensity of the reflected light.  This doesn't
-// measure distance per se, but since the intensity of a light source
-// falls off as the square of the distance, we can use the reflected
-// intensity as a proxy for the distance by calculating 1/sqrt(intensity).
-// The main reason to support this type of sensor is that it's used in the
-// VirtuaPin v3 plunger kit, and several people have requested support so
-// that they can move re-flash that kit using the Pinscape software and
-// continue using their existing plunger sensor.  IR proximity sensors
-// aren't very accurate, and they're also kind of slow (this one can take
-// readings at a maximum rate of 250/s, or 4ms), so I don't recommend
-// this sensor for new builds.  However, it does have a couple of virtues:
-// it's really easy to set up physically, and it's a non-contact sensor.
-// But really, the main reason to support it is for the sake of the
-// VirtuaPin legacy users, to allow migration without hardware changes.
-// 
 //
 
 #ifndef _DISTANCESENSOR_H_
@@ -177,12 +180,19 @@
 // We choose units that are convenient for our purposes at the joystick
 // layer, given the 16-bit field we use to report the position back to
 // the PC.)
+//
+// The iredCurrent parameter sets the brightness of the sensor's IR LED,
+// which serves as the light source for the reflected light intensity
+// readings used for proximity measurements.  This is given in units of
+// 10mA, so 1 means 10mA, 2 means 20mA, etc.  Valid values are from 1
+// (10mA) to 20 (200mA).
+//
 class PlungerSensorVCNL4010: public PlungerSensorDistance
 {
 public:
-    PlungerSensorVCNL4010(PinName sda, PinName scl)
+    PlungerSensorVCNL4010(PinName sda, PinName scl, int iredCurrent)
         : PlungerSensorDistance(65535),
-          sensor(sda, scl, true)
+          sensor(sda, scl, true, iredCurrent)
     {
     }
     
@@ -206,19 +216,27 @@
         // if we have a new reading ready, collect it
         if (sensor.proxReady())
         {
-            // Get the distance reading.  Note that we already know that the
-            // sensor has a reading ready, so it shouldn't be possible to 
-            // time out on the read.
-            uint8_t d;
+            // Get the proximity count reading.  Note that we already know 
+            // that the sensor has a reading ready, so it shouldn't be
+            // possible to time out on the read.
+            int rawCount;
             uint32_t t, dt;
-            lastErr = sensor.getProx(d, t, dt, 100);
+            lastErr = sensor.getProx(rawCount, t, dt, 100);
             
             // if we got a reading, update the last reading
             if (lastErr == 0)
             {
+                // run the proximity count through the jitter filter
+                int filteredCount = jitterFilter(rawCount);
+                
+                // convert the count to a distance, using the filtered count
+                int dist = sensor.countToDistance(filteredCount);
+            
                 // save the new reading
-                last.pos = d;
+                last.pos = dist;
                 last.t = t;
+                lastFilteredCount = filteredCount;
+                lastRawCount = rawCount;
             
                 // collect scan time statistics
                 collectScanTimeStats(dt);
@@ -230,12 +248,65 @@
         return lastErr == 0;
     }
     
+    // The VCNL4010 applies jitter filtering to the physical sensor reading
+    // instead of to the distance reading.  This produces much better results
+    // for this sensor because the sensor's distance resolution gets lower
+    // at longer distances, so the conversion to distance tends to amplify
+    // noise quite a bit at the distant end.  It's therefore important to
+    // do the noise reduction in the brightness domain, before that
+    // amplification takes place.
+    virtual int postJitterFilter(int pos) { return pos; }
+    
+    // Send a status report for the config tool sensor viewer
+    virtual void sendStatusReport(class USBJoystick &js, uint8_t flags)
+    {
+        // send the common status report
+        PlungerSensor::sendStatusReport(js, flags);
+
+        // send the extra VCNL4010 sensor status report
+        js.sendPlungerStatusVCNL4010(lastFilteredCount, lastRawCount);
+    }
+
+    // Restore the saved calibration data from the configuration.  The
+    // main loop calls this at initialization time to pass us saved
+    // private configuration data.  The VCNL4010 uses this to store the
+    // minimum proximity count reading observed during calibration, which
+    // it uses to figure the scaling factor for the 1/sqrt(intensity)
+    // distance calculation.
+    virtual void restoreCalibration(Config &config) 
+    {
+        // restore the saved minimum count reading
+        sensor.restoreCalibration(config);
+    }
+    
+    // Begin calibration.  The main loop calls this when the user
+    // initiates a calibration cycle.  The VCNL4010 code uses this to
+    // reset its internal record of the proximity minimum.
+    virtual void beginCalibration(Config &)
+    {
+        sensor.beginCalibration();
+    }
+    
+    // End calibration.  The main loop calls this when a calibration
+    // cycle finishes.  The VCNL4010 code uses this to save the minimum
+    // count value observed during the calibration interval, and to
+    // calculate the new scaling factor for the 1/sqrt(intensity)
+    // distance calculation.
+    virtual void endCalibration(Config &config)
+    {
+        // let the sensor figure the new scaling factor
+        sensor.endCalibration(config);
+    }
+  
+        
 protected:
     // underlying sensor interface
     VCNL4010 sensor;
     
     // last reading and error status
     PlungerReading last;
+    int lastFilteredCount;
+    int lastRawCount;
     int lastErr;
 };