Arnaud VALLEY / Mbed 2 deprecated Pinscape_Controller_V2_arnoz

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
mjr
Date:
Fri Dec 27 20:14:23 2019 +0000
Revision:
104:6e06e0f4b476
Parent:
101:755f44622abc
Child:
106:e9e3b46132c1
AEAT-6012, TCD1103 updates

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 100:1ff35c07217c 1 // Toshiba TCD1103 linear image sensors
mjr 100:1ff35c07217c 2 //
mjr 100:1ff35c07217c 3 // This sensor is similar to the original TSL1410R in both its electronic
mjr 100:1ff35c07217c 4 // interface and the theory of operation. The details of the electronics
mjr 100:1ff35c07217c 5 // are different enough that we can't reuse the same code at the hardware
mjr 100:1ff35c07217c 6 // interface level, but the principle of operation is similar: the sensor
mjr 100:1ff35c07217c 7 // provides a serial interface to a file of pixels transferred as analog
mjr 100:1ff35c07217c 8 // voltage levels representing the charge collected.
mjr 100:1ff35c07217c 9 //
mjr 100:1ff35c07217c 10 // As with the TSL1410R, we position the sensor so that the pixel row is
mjr 104:6e06e0f4b476 11 // aligned with the plunger axis, and we detect the plunger position by
mjr 104:6e06e0f4b476 12 // looking for a dark/light edge at the end of the plunger. However,
mjr 104:6e06e0f4b476 13 // the optics for this sensor are very different because of the sensor's
mjr 104:6e06e0f4b476 14 // size. The TSL1410R is by some magical coincidence the same size as
mjr 104:6e06e0f4b476 15 // the plunger travel range, so we set that sensor up so that the plunger
mjr 104:6e06e0f4b476 16 // is backlit with respect to the sensor, and simply casts a shadow on
mjr 104:6e06e0f4b476 17 // the sensor. The TCD1103, in contrast, has a pixel array that's only
mjr 104:6e06e0f4b476 18 // 8mm long, so we can't use the direct shadow approach. Instead, we
mjr 104:6e06e0f4b476 19 // have to use a lens to focus an image of the plunger on the sensor.
mjr 104:6e06e0f4b476 20 // With a focused image, we can front-light the plunger and take a picture
mjr 104:6e06e0f4b476 21 // of the plunger itself rather than of an occluded back-light.
mjr 100:1ff35c07217c 22 //
mjr 104:6e06e0f4b476 23 // Even though we use "edge sensing", this class isn't based on the
mjr 104:6e06e0f4b476 24 // PlungerSensorEdgePos class. Our sensing algorithm is a little different,
mjr 104:6e06e0f4b476 25 // and much simpler, because we're working with a proper image of the
mjr 104:6e06e0f4b476 26 // plunger, rather than an image of its shadow. The shadow tends to be
mjr 104:6e06e0f4b476 27 // rather fuzzy, and the TSL14xx sensors were pretty noisy, so we had to
mjr 104:6e06e0f4b476 28 // work fairly hard to distinguish an edge in the image from a noise spike.
mjr 104:6e06e0f4b476 29 // This sensor has very low noise, and the focused image produces a sharp
mjr 104:6e06e0f4b476 30 // edge, so we can use a more straightforward algorithm that just looks
mjr 104:6e06e0f4b476 31 // for the first bright spot.
mjr 104:6e06e0f4b476 32 //
mjr 104:6e06e0f4b476 33 // The TCD1103 uses a negative image: brighter pixels are represented by
mjr 104:6e06e0f4b476 34 // lower numbers. The electronics of the sensor are such that the dynamic
mjr 104:6e06e0f4b476 35 // range for the pixel analag voltage signal (which is what our pixel
mjr 104:6e06e0f4b476 36 // elements represent) is only about 1V, or about 30% of the 3.3V range of
mjr 104:6e06e0f4b476 37 // the ADC. Dark pixels read at about 2V (about 167 after 8-bit ADC
mjr 104:6e06e0f4b476 38 // quantization), and saturated pixels read at 1V (78 on the ADC). So our
mjr 104:6e06e0f4b476 39 // effective dynamic range after quantization is about 100 steps. That
mjr 104:6e06e0f4b476 40 // would be pretty terrible if the goal were to take pictures for an art
mjr 104:6e06e0f4b476 41 // gallery, and there are things we could do in the electronic interface
mjr 104:6e06e0f4b476 42 // to improve it; in particular, we could use an op-amp to expand the
mjr 104:6e06e0f4b476 43 // voltage range on the ADC input and remove the DC offset, so that the
mjr 104:6e06e0f4b476 44 // signal going into the ADC covers the ADC's full 0V - 3.3V range. But
mjr 104:6e06e0f4b476 45 // there's need for that for our purposes here; 100 steps is perfectly
mjr 104:6e06e0f4b476 46 // adequate for our edge sensing, especially given the sensor's low
mjr 104:6e06e0f4b476 47 // noise level.
mjr 100:1ff35c07217c 48
mjr 104:6e06e0f4b476 49
mjr 104:6e06e0f4b476 50 #include "plunger.h"
mjr 100:1ff35c07217c 51 #include "TCD1103.h"
mjr 100:1ff35c07217c 52
mjr 100:1ff35c07217c 53 template <bool invertedLogicGates>
mjr 100:1ff35c07217c 54 class PlungerSensorImageInterfaceTCD1103: public PlungerSensorImageInterface
mjr 100:1ff35c07217c 55 {
mjr 100:1ff35c07217c 56 public:
mjr 100:1ff35c07217c 57 PlungerSensorImageInterfaceTCD1103(PinName fm, PinName os, PinName icg, PinName sh)
mjr 104:6e06e0f4b476 58 : PlungerSensorImageInterface(1500), sensor(fm, os, icg, sh)
mjr 100:1ff35c07217c 59 {
mjr 100:1ff35c07217c 60 }
mjr 100:1ff35c07217c 61
mjr 100:1ff35c07217c 62 // is the sensor ready?
mjr 100:1ff35c07217c 63 virtual bool ready() { return sensor.ready(); }
mjr 100:1ff35c07217c 64
mjr 101:755f44622abc 65 virtual void init() { }
mjr 100:1ff35c07217c 66
mjr 100:1ff35c07217c 67 // get the average sensor scan time
mjr 100:1ff35c07217c 68 virtual uint32_t getAvgScanTime() { return sensor.getAvgScanTime(); }
mjr 100:1ff35c07217c 69
mjr 101:755f44622abc 70 virtual void readPix(uint8_t* &pix, uint32_t &t)
mjr 100:1ff35c07217c 71 {
mjr 100:1ff35c07217c 72 // get the image array from the last capture
mjr 104:6e06e0f4b476 73 sensor.getPix(pix, t);
mjr 100:1ff35c07217c 74 }
mjr 100:1ff35c07217c 75
mjr 101:755f44622abc 76 virtual void releasePix() { sensor.releasePix(); }
mjr 101:755f44622abc 77
mjr 101:755f44622abc 78 virtual void setMinIntTime(uint32_t us) { sensor.setMinIntTime(us); }
mjr 100:1ff35c07217c 79
mjr 100:1ff35c07217c 80 // the low-level interface to the TSL14xx sensor
mjr 100:1ff35c07217c 81 TCD1103<invertedLogicGates> sensor;
mjr 100:1ff35c07217c 82 };
mjr 100:1ff35c07217c 83
mjr 100:1ff35c07217c 84 template<bool invertedLogicGates>
mjr 104:6e06e0f4b476 85 class PlungerSensorTCD1103: public PlungerSensorImage<int>
mjr 100:1ff35c07217c 86 {
mjr 100:1ff35c07217c 87 public:
mjr 100:1ff35c07217c 88 PlungerSensorTCD1103(PinName fm, PinName os, PinName icg, PinName sh)
mjr 104:6e06e0f4b476 89 : PlungerSensorImage(sensor, 1500, 1499, true), sensor(fm, os, icg, sh)
mjr 100:1ff35c07217c 90 {
mjr 100:1ff35c07217c 91 }
mjr 100:1ff35c07217c 92
mjr 100:1ff35c07217c 93 protected:
mjr 104:6e06e0f4b476 94 // Process an image. This seeks the first dark-to-light edge in the image.
mjr 104:6e06e0f4b476 95 // We assume that the background (open space behind the plunger) has a
mjr 104:6e06e0f4b476 96 // dark (minimally reflective) backdrop, and that the tip of the plunger
mjr 104:6e06e0f4b476 97 // has a bright white strip right at the end. So the end of the plunger
mjr 104:6e06e0f4b476 98 // should be easily identifiable in the image as the first bright edge
mjr 104:6e06e0f4b476 99 // we see starting at the "far" end.
mjr 104:6e06e0f4b476 100 virtual bool process(const uint8_t *pix, int n, int &pos, int& /*processResult*/)
mjr 104:6e06e0f4b476 101 {
mjr 104:6e06e0f4b476 102 // Scan the pixel array to determine the actual dynamic range
mjr 104:6e06e0f4b476 103 // of this image. That will let us determine what consistutes
mjr 104:6e06e0f4b476 104 // "bright" when we're looking for the bright spot.
mjr 104:6e06e0f4b476 105 uint8_t pixMin = 255, pixMax = 0;
mjr 104:6e06e0f4b476 106 const uint8_t *p = pix;
mjr 104:6e06e0f4b476 107 for (int i = n; i != 0; --i)
mjr 104:6e06e0f4b476 108 {
mjr 104:6e06e0f4b476 109 uint8_t c = *p++;
mjr 104:6e06e0f4b476 110 if (c < pixMin) pixMin = c;
mjr 104:6e06e0f4b476 111 if (c > pixMax) pixMax = c;
mjr 104:6e06e0f4b476 112 }
mjr 104:6e06e0f4b476 113
mjr 104:6e06e0f4b476 114 // Figure the threshold brightness for the bright spot as halfway
mjr 104:6e06e0f4b476 115 // between the min and max.
mjr 104:6e06e0f4b476 116 uint8_t threshold = (pixMin + pixMax)/2;
mjr 104:6e06e0f4b476 117
mjr 104:6e06e0f4b476 118 // Scan for the first bright-enough pixel. Remember that we're
mjr 104:6e06e0f4b476 119 // working with a negative image, so "brighter" is "less than".
mjr 104:6e06e0f4b476 120 p = pix;
mjr 104:6e06e0f4b476 121 for (int i = n; i != 0; --i, ++p)
mjr 104:6e06e0f4b476 122 {
mjr 104:6e06e0f4b476 123 if (*p < threshold)
mjr 104:6e06e0f4b476 124 {
mjr 104:6e06e0f4b476 125 // got it - report this position
mjr 104:6e06e0f4b476 126 pos = p - pix;
mjr 104:6e06e0f4b476 127 return true;
mjr 104:6e06e0f4b476 128 }
mjr 104:6e06e0f4b476 129 }
mjr 104:6e06e0f4b476 130
mjr 104:6e06e0f4b476 131 // no edge found - report failure
mjr 104:6e06e0f4b476 132 return false;
mjr 104:6e06e0f4b476 133 }
mjr 104:6e06e0f4b476 134
mjr 104:6e06e0f4b476 135 // Use a fixed orientation for this sensor. The shadow-edge sensors
mjr 104:6e06e0f4b476 136 // try to infer the direction by checking which end of the image is
mjr 104:6e06e0f4b476 137 // brighter, which works well for the shadow sensors because the back
mjr 104:6e06e0f4b476 138 // end of the image will always be in shadow. But for this sensor,
mjr 104:6e06e0f4b476 139 // we're taking an image of the plunger (not its shadow), and the
mjr 104:6e06e0f4b476 140 // back end of the plunger is the part with the spring, which has a
mjr 104:6e06e0f4b476 141 // fuzzy and complex reflectivity pattern because of the spring.
mjr 104:6e06e0f4b476 142 // So for this sensor, it's better to insist that the user sets it
mjr 104:6e06e0f4b476 143 // up in a canonical orientation. That's a reasaonble expectation
mjr 104:6e06e0f4b476 144 // for this sensor anyway, because the physical installation won't
mjr 104:6e06e0f4b476 145 // be as ad hoc as the TSL1410R setup, which only required that you
mjr 104:6e06e0f4b476 146 // mounted the sensor itself. In this case, you have to build a
mjr 104:6e06e0f4b476 147 // circuit board and mount a lens on it, so it's reasonable to
mjr 104:6e06e0f4b476 148 // expect that everyone will be using the mounting apparatus plans
mjr 104:6e06e0f4b476 149 // that we'll detail in the build guide. In any case, we'll just
mjr 104:6e06e0f4b476 150 // make it clear in the instructions that you have to mount the
mjr 104:6e06e0f4b476 151 // sensor in a certain orientation.
mjr 104:6e06e0f4b476 152 virtual int getOrientation() const { return 1; }
mjr 104:6e06e0f4b476 153
mjr 104:6e06e0f4b476 154 // the hardware sensor interface
mjr 100:1ff35c07217c 155 PlungerSensorImageInterfaceTCD1103<invertedLogicGates> sensor;
mjr 100:1ff35c07217c 156 };