Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
Plunger/distanceSensor.h
- Committer:
- arnoz
- Date:
- 2021-10-01
- Revision:
- 116:7a67265d7c19
- Parent:
- 113:7330439f2ffc
File content as of revision 116:7a67265d7c19:
// Plunger sensor type for distance sensors. // // This type of sensor measures the distance to a target by sending // optical or sound signals and watching for the reflection. There are // many types of these sensors, including sensors that measure the // intensity of reflected sound or light signals, sensors that measure // the round-trip time of "pings", and sensors that measure optical // parallax. // // The basic installation for this type of sensor involves placing the // sensor itself in a fixed location at one end of the plunger, pointing // down the length of the plunger, and placing a reflective target at // the end of the plunger. The target can simply be an ordinary plunger // tip, if the sensor is at the far end of the plunger facing forward // (facing the front of the cabinet). Alternatively, the target can // be a disk or similar object attached to the end of the plunger, and // the sensor can be placed at the front of the machine facing the target. // In either case, the sensor measures the distance to the target at any // given time, and we interpret that into the plunger position. // // 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 // of light. This sensor has nominal 1mm precision, although its true // precision in testing is closer to 5mm. Sample times are around 16ms. // This makes the sensor acceptable but not great by Pinscape standards; // we generally consider 2.5ms read times and .25mm precision to be the // minimum standards. However, this sensor is inexpensive and easier to // set up than most of the better options, so it might be attractive to // some cab builders despite the quality tradeoffs. // // #ifndef _DISTANCESENSOR_H_ #define _DISTANCESENSOR_H_ #include "plunger.h" #include "VL6180X.h" #include "VCNL4010.h" // Base class for distance sensors class PlungerSensorDistance: public PlungerSensor { public: PlungerSensorDistance(int nativeScale) : PlungerSensor(nativeScale) { totalTime = 0; nRuns = 0; } // get the average scan time virtual uint32_t getAvgScanTime() { return uint32_t(totalTime / nRuns); } protected: // collect scan time statistics void collectScanTimeStats(uint32_t dt) { totalTime += dt; nRuns += 1; } // scan time statistics uint64_t totalTime; // total time consumed by all reads so far uint32_t nRuns; // number of runs so far }; // PlungerSensor interface implementation for VL6180X sensors. // // The VL6180X reports distances in millimeter quanta, so the native // sensor units are millimeters. A physical plunger has about 3" of // total travel, but leave a little extra padding for measurement // inaccuracies and other unusual situations, so'll use an actual // native scale of 150mm. class PlungerSensorVL6180X: public PlungerSensorDistance { public: PlungerSensorVL6180X(PinName sda, PinName scl, PinName gpio0) : PlungerSensorDistance(150), sensor(sda, scl, I2C_ADDRESS, gpio0, true) { } // fixed I2C bus address for the VL6180X static const int I2C_ADDRESS = 0x29; virtual void init() { // initialize the sensor and set the default configuration sensor.init(); sensor.setDefaults(); // start a reading sensor.startRangeReading(); } virtual bool ready() { // make sure a reading has been initiated sensor.startRangeReading(); // check if a reading is ready return sensor.rangeReady(); } virtual bool readRaw(PlungerReading &r) { // if we have a new reading ready, collect it if (sensor.rangeReady()) { // Get the range 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. (The sensor could have timed out on // convergence, but if it did, that's in the past already so // it's not something we have to wait for now.) uint8_t d; uint32_t t, dt; lastErr = sensor.getRange(d, t, dt, 100); // if we got a reading, update the last reading if (lastErr == 0) { // save the new reading last.pos = d; last.t = t; // collect scan time statistics collectScanTimeStats(dt); } // start a new reading sensor.startRangeReading(); } // return the most recent reading r = last; return lastErr == 0; } protected: // underlying sensor interface VL6180X sensor; // last reading and error status PlungerReading last; int lastErr; }; // PlungerSensor interface implementation for VCNL4010 IR proximity sensors // // Our hardware interface for this sensor reports distances in abstract // units that fit a 16-bit int, so the native distance scale is 0..65535. // (The sensor itself doesn't have a native distance scale per se, since // it reports results in terms of the intensity of the reflected light. // This is related to the distance by an inverse square law, so since we // have to do some math on the raw readings anyway to convert them to // distances, we can choose whatever units we want for the conversion. // 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, int iredCurrent) : PlungerSensorDistance(65535), sensor(sda, scl, true, iredCurrent) { } virtual void init() { // initialize the sensor sensor.init(); // start a reading sensor.startProxReading(); } virtual bool ready() { // check if a reading is ready return sensor.proxReady(); } virtual bool readRaw(PlungerReading &r) { // if we have a new reading ready, collect it if (sensor.proxReady()) { // 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(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 = dist; last.t = t; lastFilteredCount = filteredCount; lastRawCount = rawCount; // collect scan time statistics collectScanTimeStats(dt); } } // return the most recent reading r = last; 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; }; #endif