Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

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?

UserRevisionLine numberNew 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 */