Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
Plunger/plunger.h@82:4f6209cb5c33, 2017-04-13 (annotated)
- Committer:
- mjr
- Date:
- Thu Apr 13 23:20:28 2017 +0000
- Revision:
- 82:4f6209cb5c33
- Child:
- 86:e30a1f60f783
Plunger refactoring; AEDR-8300 added; TSL1401CL in progress; VL6180X added
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 82:4f6209cb5c33 | 1 | // Plunger Sensor Interface |
mjr | 82:4f6209cb5c33 | 2 | // |
mjr | 82:4f6209cb5c33 | 3 | // This module defines the abstract interface to the plunger sensors. |
mjr | 82:4f6209cb5c33 | 4 | // We support several different physical sensor types, so we need a |
mjr | 82:4f6209cb5c33 | 5 | // common interface for use in the main code. |
mjr | 82:4f6209cb5c33 | 6 | // |
mjr | 82:4f6209cb5c33 | 7 | // In case it's helpful in developing code for new sensor types, I've |
mjr | 82:4f6209cb5c33 | 8 | // measured the maximum instantaneous speed of a plunger at .175 inches |
mjr | 82:4f6209cb5c33 | 9 | // per millisecond, or 4.46 mm/ms. (I measured that with an AEDR-8300; |
mjr | 82:4f6209cb5c33 | 10 | // see that code for more details.) |
mjr | 82:4f6209cb5c33 | 11 | // |
mjr | 82:4f6209cb5c33 | 12 | |
mjr | 82:4f6209cb5c33 | 13 | #ifndef PLUNGER_H |
mjr | 82:4f6209cb5c33 | 14 | #define PLUNGER_H |
mjr | 82:4f6209cb5c33 | 15 | |
mjr | 82:4f6209cb5c33 | 16 | // Plunger reading with timestamp |
mjr | 82:4f6209cb5c33 | 17 | struct PlungerReading |
mjr | 82:4f6209cb5c33 | 18 | { |
mjr | 82:4f6209cb5c33 | 19 | // Raw sensor reading, normalied to 0x0000..0xFFFF range |
mjr | 82:4f6209cb5c33 | 20 | int pos; |
mjr | 82:4f6209cb5c33 | 21 | |
mjr | 82:4f6209cb5c33 | 22 | // Rimestamp of reading, in microseconds, relative to an arbitrary |
mjr | 82:4f6209cb5c33 | 23 | // zero point. Note that a 32-bit int can only represent about 71.5 |
mjr | 82:4f6209cb5c33 | 24 | // minutes worth of microseconds, so this value is only meaningful |
mjr | 82:4f6209cb5c33 | 25 | // to compute a delta from other recent readings. As long as two |
mjr | 82:4f6209cb5c33 | 26 | // readings are within 71.5 minutes of each other, the time difference |
mjr | 82:4f6209cb5c33 | 27 | // calculated from the timestamps using 32-bit math will be correct |
mjr | 82:4f6209cb5c33 | 28 | // *even if a rollover occurs* between the two readings, since the |
mjr | 82:4f6209cb5c33 | 29 | // calculation is done mod 2^32-1. |
mjr | 82:4f6209cb5c33 | 30 | uint32_t t; |
mjr | 82:4f6209cb5c33 | 31 | }; |
mjr | 82:4f6209cb5c33 | 32 | |
mjr | 82:4f6209cb5c33 | 33 | class PlungerSensor |
mjr | 82:4f6209cb5c33 | 34 | { |
mjr | 82:4f6209cb5c33 | 35 | public: |
mjr | 82:4f6209cb5c33 | 36 | PlungerSensor() { } |
mjr | 82:4f6209cb5c33 | 37 | |
mjr | 82:4f6209cb5c33 | 38 | // ---------- Abstract sensor interface ---------- |
mjr | 82:4f6209cb5c33 | 39 | |
mjr | 82:4f6209cb5c33 | 40 | // Initialize the physical sensor device. This is called at startup |
mjr | 82:4f6209cb5c33 | 41 | // to set up the device for first use. |
mjr | 82:4f6209cb5c33 | 42 | virtual void init() { } |
mjr | 82:4f6209cb5c33 | 43 | |
mjr | 82:4f6209cb5c33 | 44 | // Auto-zero the plunger. Relative sensor types, such as quadrature |
mjr | 82:4f6209cb5c33 | 45 | // sensors, can lose sync with the absolute position over time if they |
mjr | 82:4f6209cb5c33 | 46 | // ever miss any motion. We can automatically correct for this by |
mjr | 82:4f6209cb5c33 | 47 | // resetting to the park position after periods of inactivity. It's |
mjr | 82:4f6209cb5c33 | 48 | // usually safe to assume that the plunger is at the park position if it |
mjr | 82:4f6209cb5c33 | 49 | // hasn't moved in a long time, since the spring always returns it to |
mjr | 82:4f6209cb5c33 | 50 | // that position when it isn't being manipulated. The main loop monitors |
mjr | 82:4f6209cb5c33 | 51 | // for motion, and calls this after a long enough time goes by without |
mjr | 82:4f6209cb5c33 | 52 | // seeing any movement. Sensor types that are inherently absolute |
mjr | 82:4f6209cb5c33 | 53 | // (TSL1410, potentiometers) shouldn't do anything here. |
mjr | 82:4f6209cb5c33 | 54 | virtual void autoZero() { } |
mjr | 82:4f6209cb5c33 | 55 | |
mjr | 82:4f6209cb5c33 | 56 | // Is the sensor ready to take a reading? The optical sensor requires |
mjr | 82:4f6209cb5c33 | 57 | // a fairly long time (2.5ms) to transfer the data for each reading, but |
mjr | 82:4f6209cb5c33 | 58 | // this is done via DMA, so we can carry on other work while the transfer |
mjr | 82:4f6209cb5c33 | 59 | // takes place. This lets us poll the sensor to see if it's still busy |
mjr | 82:4f6209cb5c33 | 60 | // working on the current reading's data transfer. |
mjr | 82:4f6209cb5c33 | 61 | virtual bool ready() { return true; } |
mjr | 82:4f6209cb5c33 | 62 | |
mjr | 82:4f6209cb5c33 | 63 | // Read the sensor position, if possible. Returns true on success, |
mjr | 82:4f6209cb5c33 | 64 | // false if it wasn't possible to take a reading. On success, fills |
mjr | 82:4f6209cb5c33 | 65 | // in 'r' with the current reading. |
mjr | 82:4f6209cb5c33 | 66 | // |
mjr | 82:4f6209cb5c33 | 67 | // r.pos is set to the current raw sensor reading, normalized to the |
mjr | 82:4f6209cb5c33 | 68 | // range 0x0000..0xFFFF. r.t is set to the timestamp of the reading, |
mjr | 82:4f6209cb5c33 | 69 | // in microseconds. |
mjr | 82:4f6209cb5c33 | 70 | // |
mjr | 82:4f6209cb5c33 | 71 | // Also sets r.t to the microsecond timestamp of the reading, if a |
mjr | 82:4f6209cb5c33 | 72 | // reading was successfully taken. This timestamp is relative to an |
mjr | 82:4f6209cb5c33 | 73 | // arbitrary zero point and rolls over when it overflows its 32-bit |
mjr | 82:4f6209cb5c33 | 74 | // container (every 71.58 minutes). Callers can use this to calculate |
mjr | 82:4f6209cb5c33 | 75 | // the interval between two readings (e.g., to figure the average |
mjr | 82:4f6209cb5c33 | 76 | // velocity of the plunger between readings). |
mjr | 82:4f6209cb5c33 | 77 | // |
mjr | 82:4f6209cb5c33 | 78 | // Timing requirements: for best results, readings should be taken |
mjr | 82:4f6209cb5c33 | 79 | // in well under 5ms. There are two factors that go into this limit. |
mjr | 82:4f6209cb5c33 | 80 | // The first is the joystick report rate in the main loop. We want |
mjr | 82:4f6209cb5c33 | 81 | // to send those as fast as possible to avoid any perceptible control |
mjr | 82:4f6209cb5c33 | 82 | // input lag in the pinball emulation. "As fast as possible" is about |
mjr | 82:4f6209cb5c33 | 83 | // every 10ms - that's VP's approximate sampling rate, so any faster |
mjr | 82:4f6209cb5c33 | 84 | // wouldn't do any good, and could even slow things down by adding CPU |
mjr | 82:4f6209cb5c33 | 85 | // load in the Windows drivers handling the extra messages. The second |
mjr | 82:4f6209cb5c33 | 86 | // is the speed of the plunger motion. During release events, the |
mjr | 82:4f6209cb5c33 | 87 | // plunger moves in a sinusoidal pattern (back and forth) as it reaches |
mjr | 82:4f6209cb5c33 | 88 | // the extreme of its travel and bounces back off the spring. To |
mjr | 82:4f6209cb5c33 | 89 | // resolve this kind of cyclical motion accurately, we have to take |
mjr | 82:4f6209cb5c33 | 90 | // samples much faster than the cycle period - otherwise we encounter |
mjr | 82:4f6209cb5c33 | 91 | // an effect known as aliasing, where we mistake a bounce for a small |
mjr | 82:4f6209cb5c33 | 92 | // forward motion. Tests with real plungers indicate that the bounce |
mjr | 82:4f6209cb5c33 | 93 | // period is on the order of 10ms, so ideally we'd like to take |
mjr | 82:4f6209cb5c33 | 94 | // samples much faster than that. |
mjr | 82:4f6209cb5c33 | 95 | // |
mjr | 82:4f6209cb5c33 | 96 | // Returns true on success, false on failure. Returning false means |
mjr | 82:4f6209cb5c33 | 97 | // that it wasn't possible to take a valid reading. |
mjr | 82:4f6209cb5c33 | 98 | virtual bool read(PlungerReading &r) = 0; |
mjr | 82:4f6209cb5c33 | 99 | |
mjr | 82:4f6209cb5c33 | 100 | // Begin calibration. The main loop calls this when the user activates |
mjr | 82:4f6209cb5c33 | 101 | // calibration mode. Sensors that work in terms of relative positions, |
mjr | 82:4f6209cb5c33 | 102 | // such as quadrature-based sensors, can use this to set the reference |
mjr | 82:4f6209cb5c33 | 103 | // point for the park position internally. |
mjr | 82:4f6209cb5c33 | 104 | virtual void beginCalibration() { } |
mjr | 82:4f6209cb5c33 | 105 | |
mjr | 82:4f6209cb5c33 | 106 | // Send a sensor status report to the host, via the joystick interface. |
mjr | 82:4f6209cb5c33 | 107 | // This provides some common information for all sensor types, and also |
mjr | 82:4f6209cb5c33 | 108 | // includes a full image snapshot of the current sensor pixels for |
mjr | 82:4f6209cb5c33 | 109 | // imaging sensor types. |
mjr | 82:4f6209cb5c33 | 110 | // |
mjr | 82:4f6209cb5c33 | 111 | // The default implementation here sends the common information |
mjr | 82:4f6209cb5c33 | 112 | // packet, with the pixel size set to 0. |
mjr | 82:4f6209cb5c33 | 113 | // |
mjr | 82:4f6209cb5c33 | 114 | // 'flags' is a combination of bit flags: |
mjr | 82:4f6209cb5c33 | 115 | // 0x01 -> low-res scan (default is high res scan) |
mjr | 82:4f6209cb5c33 | 116 | // |
mjr | 82:4f6209cb5c33 | 117 | // Low-res scan mode means that the sensor should send a scaled-down |
mjr | 82:4f6209cb5c33 | 118 | // image, at a reduced size determined by the sensor subtype. The |
mjr | 82:4f6209cb5c33 | 119 | // default if this flag isn't set is to send the full image, at the |
mjr | 82:4f6209cb5c33 | 120 | // sensor's native pixel size. The low-res version is a reduced size |
mjr | 82:4f6209cb5c33 | 121 | // image in the normal sense of scaling down a photo image, keeping the |
mjr | 82:4f6209cb5c33 | 122 | // image intact but at reduced resolution. Note that low-res mode |
mjr | 82:4f6209cb5c33 | 123 | // doesn't affect the ongoing sensor operation at all. It only applies |
mjr | 82:4f6209cb5c33 | 124 | // to this single pixel report. The purpose is simply to reduce the USB |
mjr | 82:4f6209cb5c33 | 125 | // transmission time for the image, to allow for a faster frame rate for |
mjr | 82:4f6209cb5c33 | 126 | // displaying the sensor image in real time on the PC. For a high-res |
mjr | 82:4f6209cb5c33 | 127 | // sensor like the TSL1410R, sending the full pixel array by USB takes |
mjr | 82:4f6209cb5c33 | 128 | // so long that the frame rate is way below regular video rates. |
mjr | 82:4f6209cb5c33 | 129 | // |
mjr | 82:4f6209cb5c33 | 130 | // 'exposureTime' is the amount of extra time to add to the exposure, |
mjr | 82:4f6209cb5c33 | 131 | // in 100us (.1ms) increments. For imaging sensors, the frame we report |
mjr | 82:4f6209cb5c33 | 132 | // is exposed for the minimum exposure time plus this added time. This |
mjr | 82:4f6209cb5c33 | 133 | // allows the host to take readings at different exposure levels for |
mjr | 82:4f6209cb5c33 | 134 | // calibration purposes. Non-imaging sensors ignore this. |
mjr | 82:4f6209cb5c33 | 135 | virtual void sendStatusReport( |
mjr | 82:4f6209cb5c33 | 136 | class USBJoystick &js, uint8_t flags, uint8_t exposureTime) |
mjr | 82:4f6209cb5c33 | 137 | { |
mjr | 82:4f6209cb5c33 | 138 | // read the current position |
mjr | 82:4f6209cb5c33 | 139 | int pos = 0xFFFF; |
mjr | 82:4f6209cb5c33 | 140 | PlungerReading r; |
mjr | 82:4f6209cb5c33 | 141 | if (read(r)) |
mjr | 82:4f6209cb5c33 | 142 | { |
mjr | 82:4f6209cb5c33 | 143 | // success - scale it to 0..4095 (the generic scale used |
mjr | 82:4f6209cb5c33 | 144 | // for non-imaging sensors) |
mjr | 82:4f6209cb5c33 | 145 | pos = int(r.pos*4095L / 65535L); |
mjr | 82:4f6209cb5c33 | 146 | } |
mjr | 82:4f6209cb5c33 | 147 | |
mjr | 82:4f6209cb5c33 | 148 | // Send the common status information, indicating 0 pixels, standard |
mjr | 82:4f6209cb5c33 | 149 | // sensor orientation, and zero processing time. Non-imaging sensors |
mjr | 82:4f6209cb5c33 | 150 | // usually don't have any way to detect the orientation, so they have |
mjr | 82:4f6209cb5c33 | 151 | // to rely on being installed in a pre-determined direction. Non- |
mjr | 82:4f6209cb5c33 | 152 | // imaging sensors usually have negligible analysis time (the only |
mjr | 82:4f6209cb5c33 | 153 | // "analysis" is usually nothing more than a multiply to rescale an |
mjr | 82:4f6209cb5c33 | 154 | // ADC sample), so there's no point in collecting actual timing data; |
mjr | 82:4f6209cb5c33 | 155 | // just report zero. |
mjr | 82:4f6209cb5c33 | 156 | js.sendPlungerStatus(0, pos, 1, getAvgScanTime(), 0); |
mjr | 82:4f6209cb5c33 | 157 | } |
mjr | 82:4f6209cb5c33 | 158 | |
mjr | 82:4f6209cb5c33 | 159 | // Get the average sensor scan time in microseconds |
mjr | 82:4f6209cb5c33 | 160 | virtual uint32_t getAvgScanTime() = 0; |
mjr | 82:4f6209cb5c33 | 161 | |
mjr | 82:4f6209cb5c33 | 162 | protected: |
mjr | 82:4f6209cb5c33 | 163 | }; |
mjr | 82:4f6209cb5c33 | 164 | |
mjr | 82:4f6209cb5c33 | 165 | #endif /* PLUNGER_H */ |