Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
Diff: Plunger/distanceSensor.h
- 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; };