An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.
Dependencies: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
distanceSensor.h
00001 // Plunger sensor type for distance sensors. 00002 // 00003 // This type of sensor measures the distance to a target by sending 00004 // optical or sound signals and watching for the reflection. There are 00005 // many types of these sensors, including sensors that measure the 00006 // intensity of reflected sound or light signals, sensors that measure 00007 // the round-trip time of "pings", and sensors that measure optical 00008 // parallax. 00009 // 00010 // The basic installation for this type of sensor involves placing the 00011 // sensor itself in a fixed location at one end of the plunger, pointing 00012 // down the length of the plunger, and placing a reflective target at 00013 // the end of the plunger. The target can simply be an ordinary plunger 00014 // tip, if the sensor is at the far end of the plunger facing forward 00015 // (facing the front of the cabinet). Alternatively, the target can 00016 // be a disk or similar object attached to the end of the plunger, and 00017 // the sensor can be placed at the front of the machine facing the target. 00018 // In either case, the sensor measures the distance to the target at any 00019 // given time, and we interpret that into the plunger position. 00020 // 00021 // Here are the specific sensor types we currently support: 00022 // 00023 // VCNL4010: An IR proximity sensor. This sensor shines an IR light at a 00024 // target and measures the intensity of the reflected light. This doesn't 00025 // measure distance per se, but since the intensity of a light source 00026 // falls off as the square of the distance, we can use the reflected 00027 // intensity as a proxy for the distance by calculating 1/sqrt(intensity). 00028 // The main reason to support this type of sensor is that it's used in the 00029 // VirtuaPin v3 plunger kit, and several people have requested support so 00030 // that they can move re-flash that kit using the Pinscape software and 00031 // continue using their existing plunger sensor. Many people might also 00032 // consider this sensor for new DIY builds, since it produces pretty good 00033 // results. It's not as accurate as a potentiometer or quadrature sensor, 00034 // but it yields low-noise results with good enough precision for smooth 00035 // on-screen animation (maybe around 1mm precision). Its main drawback 00036 // is that it's relatively slow (250 Hz maximum sampling rate), but it's 00037 // still fast enough to be usable. It has several virtues that might more 00038 // than orffset its technical limitations for many paople: it's easy to 00039 // set up physically, it's completely non-contact, and it's cheap (under 00040 // $10 for the Adafruit breakout board). 00041 // 00042 // VL6180X: This is an optical (IR) "time of flight" sensor that measures 00043 // the distance to the target by sending optical pings and timing the 00044 // return signal, converting the result to distance via the known speed 00045 // of light. This sensor has nominal 1mm precision, although its true 00046 // precision in testing is closer to 5mm. Sample times are around 16ms. 00047 // This makes the sensor acceptable but not great by Pinscape standards; 00048 // we generally consider 2.5ms read times and .25mm precision to be the 00049 // minimum standards. However, this sensor is inexpensive and easier to 00050 // set up than most of the better options, so it might be attractive to 00051 // some cab builders despite the quality tradeoffs. 00052 // 00053 // 00054 00055 #ifndef _DISTANCESENSOR_H_ 00056 #define _DISTANCESENSOR_H_ 00057 00058 #include "plunger.h" 00059 #include "VL6180X.h" 00060 #include "VCNL4010.h" 00061 00062 00063 // Base class for distance sensors 00064 class PlungerSensorDistance: public PlungerSensor 00065 { 00066 public: 00067 PlungerSensorDistance(int nativeScale) : PlungerSensor(nativeScale) 00068 { 00069 totalTime = 0; 00070 nRuns = 0; 00071 } 00072 00073 // get the average scan time 00074 virtual uint32_t getAvgScanTime() { return uint32_t(totalTime / nRuns); } 00075 00076 protected: 00077 // collect scan time statistics 00078 void collectScanTimeStats(uint32_t dt) 00079 { 00080 totalTime += dt; 00081 nRuns += 1; 00082 } 00083 00084 // scan time statistics 00085 uint64_t totalTime; // total time consumed by all reads so far 00086 uint32_t nRuns; // number of runs so far 00087 }; 00088 00089 // PlungerSensor interface implementation for VL6180X sensors. 00090 // 00091 // The VL6180X reports distances in millimeter quanta, so the native 00092 // sensor units are millimeters. A physical plunger has about 3" of 00093 // total travel, but leave a little extra padding for measurement 00094 // inaccuracies and other unusual situations, so'll use an actual 00095 // native scale of 150mm. 00096 class PlungerSensorVL6180X: public PlungerSensorDistance 00097 { 00098 public: 00099 PlungerSensorVL6180X(PinName sda, PinName scl, PinName gpio0) 00100 : PlungerSensorDistance(150), 00101 sensor(sda, scl, I2C_ADDRESS, gpio0, true) 00102 { 00103 } 00104 00105 // fixed I2C bus address for the VL6180X 00106 static const int I2C_ADDRESS = 0x29; 00107 00108 virtual void init() 00109 { 00110 // initialize the sensor and set the default configuration 00111 sensor.init(); 00112 sensor.setDefaults(); 00113 00114 // start a reading 00115 sensor.startRangeReading(); 00116 } 00117 00118 virtual bool ready() 00119 { 00120 // make sure a reading has been initiated 00121 sensor.startRangeReading(); 00122 00123 // check if a reading is ready 00124 return sensor.rangeReady(); 00125 } 00126 00127 virtual bool readRaw(PlungerReading &r) 00128 { 00129 // if we have a new reading ready, collect it 00130 if (sensor.rangeReady()) 00131 { 00132 // Get the range reading. Note that we already know that the 00133 // sensor has a reading ready, so it shouldn't be possible to 00134 // time out on the read. (The sensor could have timed out on 00135 // convergence, but if it did, that's in the past already so 00136 // it's not something we have to wait for now.) 00137 uint8_t d; 00138 uint32_t t, dt; 00139 lastErr = sensor.getRange(d, t, dt, 100); 00140 00141 // if we got a reading, update the last reading 00142 if (lastErr == 0) 00143 { 00144 // save the new reading 00145 last.pos = d; 00146 last.t = t; 00147 00148 // collect scan time statistics 00149 collectScanTimeStats(dt); 00150 } 00151 00152 // start a new reading 00153 sensor.startRangeReading(); 00154 } 00155 00156 // return the most recent reading 00157 r = last; 00158 return lastErr == 0; 00159 } 00160 00161 protected: 00162 // underlying sensor interface 00163 VL6180X sensor; 00164 00165 // last reading and error status 00166 PlungerReading last; 00167 int lastErr; 00168 }; 00169 00170 00171 // PlungerSensor interface implementation for VCNL4010 IR proximity sensors 00172 // 00173 // Our hardware interface for this sensor reports distances in abstract 00174 // units that fit a 16-bit int, so the native distance scale is 0..65535. 00175 // (The sensor itself doesn't have a native distance scale per se, since 00176 // it reports results in terms of the intensity of the reflected light. 00177 // This is related to the distance by an inverse square law, so since we 00178 // have to do some math on the raw readings anyway to convert them to 00179 // distances, we can choose whatever units we want for the conversion. 00180 // We choose units that are convenient for our purposes at the joystick 00181 // layer, given the 16-bit field we use to report the position back to 00182 // the PC.) 00183 // 00184 // The iredCurrent parameter sets the brightness of the sensor's IR LED, 00185 // which serves as the light source for the reflected light intensity 00186 // readings used for proximity measurements. This is given in units of 00187 // 10mA, so 1 means 10mA, 2 means 20mA, etc. Valid values are from 1 00188 // (10mA) to 20 (200mA). 00189 // 00190 class PlungerSensorVCNL4010: public PlungerSensorDistance 00191 { 00192 public: 00193 PlungerSensorVCNL4010(PinName sda, PinName scl, int iredCurrent) 00194 : PlungerSensorDistance(65535), 00195 sensor(sda, scl, true, iredCurrent) 00196 { 00197 } 00198 00199 virtual void init() 00200 { 00201 // initialize the sensor 00202 sensor.init(); 00203 00204 // start a reading 00205 sensor.startProxReading(); 00206 } 00207 00208 virtual bool ready() 00209 { 00210 // check if a reading is ready 00211 return sensor.proxReady(); 00212 } 00213 00214 virtual bool readRaw(PlungerReading &r) 00215 { 00216 // if we have a new reading ready, collect it 00217 if (sensor.proxReady()) 00218 { 00219 // Get the proximity count reading. Note that we already know 00220 // that the sensor has a reading ready, so it shouldn't be 00221 // possible to time out on the read. 00222 int rawCount; 00223 uint32_t t, dt; 00224 lastErr = sensor.getProx(rawCount, t, dt, 100); 00225 00226 // if we got a reading, update the last reading 00227 if (lastErr == 0) 00228 { 00229 // run the proximity count through the jitter filter 00230 int filteredCount = jitterFilter(rawCount); 00231 00232 // convert the count to a distance, using the filtered count 00233 int dist = sensor.countToDistance(filteredCount); 00234 00235 // save the new reading 00236 last.pos = dist; 00237 last.t = t; 00238 lastFilteredCount = filteredCount; 00239 lastRawCount = rawCount; 00240 00241 // collect scan time statistics 00242 collectScanTimeStats(dt); 00243 } 00244 } 00245 00246 // return the most recent reading 00247 r = last; 00248 return lastErr == 0; 00249 } 00250 00251 // The VCNL4010 applies jitter filtering to the physical sensor reading 00252 // instead of to the distance reading. This produces much better results 00253 // for this sensor because the sensor's distance resolution gets lower 00254 // at longer distances, so the conversion to distance tends to amplify 00255 // noise quite a bit at the distant end. It's therefore important to 00256 // do the noise reduction in the brightness domain, before that 00257 // amplification takes place. 00258 virtual int postJitterFilter(int pos) { return pos; } 00259 00260 // Send a status report for the config tool sensor viewer 00261 virtual void sendStatusReport(class USBJoystick &js, uint8_t flags) 00262 { 00263 // send the common status report 00264 PlungerSensor::sendStatusReport(js, flags); 00265 00266 // send the extra VCNL4010 sensor status report 00267 js.sendPlungerStatusVCNL4010(lastFilteredCount, lastRawCount); 00268 } 00269 00270 // Restore the saved calibration data from the configuration. The 00271 // main loop calls this at initialization time to pass us saved 00272 // private configuration data. The VCNL4010 uses this to store the 00273 // minimum proximity count reading observed during calibration, which 00274 // it uses to figure the scaling factor for the 1/sqrt(intensity) 00275 // distance calculation. 00276 virtual void restoreCalibration(Config &config) 00277 { 00278 // restore the saved minimum count reading 00279 sensor.restoreCalibration(config); 00280 } 00281 00282 // Begin calibration. The main loop calls this when the user 00283 // initiates a calibration cycle. The VCNL4010 code uses this to 00284 // reset its internal record of the proximity minimum. 00285 virtual void beginCalibration(Config &) 00286 { 00287 sensor.beginCalibration(); 00288 } 00289 00290 // End calibration. The main loop calls this when a calibration 00291 // cycle finishes. The VCNL4010 code uses this to save the minimum 00292 // count value observed during the calibration interval, and to 00293 // calculate the new scaling factor for the 1/sqrt(intensity) 00294 // distance calculation. 00295 virtual void endCalibration(Config &config) 00296 { 00297 // let the sensor figure the new scaling factor 00298 sensor.endCalibration(config); 00299 } 00300 00301 00302 protected: 00303 // underlying sensor interface 00304 VCNL4010 sensor; 00305 00306 // last reading and error status 00307 PlungerReading last; 00308 int lastFilteredCount; 00309 int lastRawCount; 00310 int lastErr; 00311 }; 00312 00313 #endif
Generated on Wed Jul 13 2022 03:30:10 by 1.7.2