synch the camera trigger with the signal in phase and quadrature (every frame or every N frames). We can also simulate the product by the in-phase signal (with a small arbitrary phase difference)
Flipper.h@0:4b5874bff9bb, 2014-07-14 (annotated)
- Committer:
- mbedalvaro
- Date:
- Mon Jul 14 09:35:12 2014 +0000
- Revision:
- 0:4b5874bff9bb
- Child:
- 1:4284f27d638d
this works very well. A VERY small jitter remains... no idea why. Also, not very happy with all the static member variables... looks like they just needed to be globals...
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mbedalvaro | 0:4b5874bff9bb | 1 | #ifndef Flipper_h |
mbedalvaro | 0:4b5874bff9bb | 2 | #define Flipper_h |
mbedalvaro | 0:4b5874bff9bb | 3 | |
mbedalvaro | 0:4b5874bff9bb | 4 | #include "mbed.h" |
mbedalvaro | 0:4b5874bff9bb | 5 | |
mbedalvaro | 0:4b5874bff9bb | 6 | #define shutterPin p21 // for tests |
mbedalvaro | 0:4b5874bff9bb | 7 | #define ledPin p22 // the actual modulation of the LED source (equal to PHASE or QUAD signal every N frames) |
mbedalvaro | 0:4b5874bff9bb | 8 | #define cameraTriggerPin p23 |
mbedalvaro | 0:4b5874bff9bb | 9 | |
mbedalvaro | 0:4b5874bff9bb | 10 | // A class for flip()-ing a DigitalOut using a timer |
mbedalvaro | 0:4b5874bff9bb | 11 | |
mbedalvaro | 0:4b5874bff9bb | 12 | //1) Class for toggling the LED (in phase or quadrature, with a multiplier) |
mbedalvaro | 0:4b5874bff9bb | 13 | class Flipper { |
mbedalvaro | 0:4b5874bff9bb | 14 | public: |
mbedalvaro | 0:4b5874bff9bb | 15 | static DigitalOut _pin; |
mbedalvaro | 0:4b5874bff9bb | 16 | static bool state; |
mbedalvaro | 0:4b5874bff9bb | 17 | static bool multiplier;//=true; // this is for simulating the deconvolution |
mbedalvaro | 0:4b5874bff9bb | 18 | // NOTE initialization needs to be in the cpp file, unless it's a const |
mbedalvaro | 0:4b5874bff9bb | 19 | |
mbedalvaro | 0:4b5874bff9bb | 20 | static void delay90() {state = !state; _pin=state;} |
mbedalvaro | 0:4b5874bff9bb | 21 | static void multImmediate() { _pin=state&&multiplier;} |
mbedalvaro | 0:4b5874bff9bb | 22 | |
mbedalvaro | 0:4b5874bff9bb | 23 | |
mbedalvaro | 0:4b5874bff9bb | 24 | Flipper(PinName pin, unsigned int interval): us_interval(interval) { |
mbedalvaro | 0:4b5874bff9bb | 25 | Flipper::_pin=pin; |
mbedalvaro | 0:4b5874bff9bb | 26 | state=true; |
mbedalvaro | 0:4b5874bff9bb | 27 | _pin=state; |
mbedalvaro | 0:4b5874bff9bb | 28 | } |
mbedalvaro | 0:4b5874bff9bb | 29 | |
mbedalvaro | 0:4b5874bff9bb | 30 | void start() { |
mbedalvaro | 0:4b5874bff9bb | 31 | myTicker.attach_us(this, &Flipper::flip, us_interval); // the address of the object, member function, and interval |
mbedalvaro | 0:4b5874bff9bb | 32 | } |
mbedalvaro | 0:4b5874bff9bb | 33 | |
mbedalvaro | 0:4b5874bff9bb | 34 | void stop() { |
mbedalvaro | 0:4b5874bff9bb | 35 | myTicker.detach(); |
mbedalvaro | 0:4b5874bff9bb | 36 | } |
mbedalvaro | 0:4b5874bff9bb | 37 | |
mbedalvaro | 0:4b5874bff9bb | 38 | void flip() { |
mbedalvaro | 0:4b5874bff9bb | 39 | state = !state; |
mbedalvaro | 0:4b5874bff9bb | 40 | _pin=state&&multiplier; |
mbedalvaro | 0:4b5874bff9bb | 41 | } |
mbedalvaro | 0:4b5874bff9bb | 42 | |
mbedalvaro | 0:4b5874bff9bb | 43 | private: |
mbedalvaro | 0:4b5874bff9bb | 44 | unsigned int us_interval; |
mbedalvaro | 0:4b5874bff9bb | 45 | Ticker myTicker; |
mbedalvaro | 0:4b5874bff9bb | 46 | }; |
mbedalvaro | 0:4b5874bff9bb | 47 | |
mbedalvaro | 0:4b5874bff9bb | 48 | // 2) Camera trigger class (NOTE: we are using MODE 2 of Point gray, meaning we control the exposure) |
mbedalvaro | 0:4b5874bff9bb | 49 | class Trigger { |
mbedalvaro | 0:4b5874bff9bb | 50 | |
mbedalvaro | 0:4b5874bff9bb | 51 | friend class Flipper; // because we will call delay90() method |
mbedalvaro | 0:4b5874bff9bb | 52 | |
mbedalvaro | 0:4b5874bff9bb | 53 | public: |
mbedalvaro | 0:4b5874bff9bb | 54 | |
mbedalvaro | 0:4b5874bff9bb | 55 | enum triggerState { |
mbedalvaro | 0:4b5874bff9bb | 56 | WAITING=0, |
mbedalvaro | 0:4b5874bff9bb | 57 | EXPOSE, |
mbedalvaro | 0:4b5874bff9bb | 58 | NUM_STATES |
mbedalvaro | 0:4b5874bff9bb | 59 | }; |
mbedalvaro | 0:4b5874bff9bb | 60 | |
mbedalvaro | 0:4b5874bff9bb | 61 | Trigger(PinName pin, float fps, unsigned int exposure) : _pin(pin) { |
mbedalvaro | 0:4b5874bff9bb | 62 | _pin=1; |
mbedalvaro | 0:4b5874bff9bb | 63 | us_exposureTime=exposure; |
mbedalvaro | 0:4b5874bff9bb | 64 | us_waitingTime=(unsigned int)(1000000.0/fps-us_exposureTime); |
mbedalvaro | 0:4b5874bff9bb | 65 | framesQPToggle=2; // default number of frames before toggling between Q and P signals (delaying the Flipper signal by 90 deg). |
mbedalvaro | 0:4b5874bff9bb | 66 | QP_Mode=true; |
mbedalvaro | 0:4b5874bff9bb | 67 | } |
mbedalvaro | 0:4b5874bff9bb | 68 | |
mbedalvaro | 0:4b5874bff9bb | 69 | void setQPToggleFrames(unsigned int numToggleQPFrames) { |
mbedalvaro | 0:4b5874bff9bb | 70 | framesQPToggle=numToggleQPFrames; |
mbedalvaro | 0:4b5874bff9bb | 71 | } |
mbedalvaro | 0:4b5874bff9bb | 72 | |
mbedalvaro | 0:4b5874bff9bb | 73 | void setFrameRate(float fps) { |
mbedalvaro | 0:4b5874bff9bb | 74 | us_waitingTime=(unsigned int)(1000000.0/fps-us_exposureTime); |
mbedalvaro | 0:4b5874bff9bb | 75 | } |
mbedalvaro | 0:4b5874bff9bb | 76 | |
mbedalvaro | 0:4b5874bff9bb | 77 | void setExposure(unsigned int exposure) { |
mbedalvaro | 0:4b5874bff9bb | 78 | us_exposureTime=exposure; |
mbedalvaro | 0:4b5874bff9bb | 79 | } |
mbedalvaro | 0:4b5874bff9bb | 80 | |
mbedalvaro | 0:4b5874bff9bb | 81 | void start() { |
mbedalvaro | 0:4b5874bff9bb | 82 | // We start in WAITING and go to EXPOSE |
mbedalvaro | 0:4b5874bff9bb | 83 | myTimer.attach_us(this, &Trigger::trigger, us_waitingTime); // the address of the object, member function, and interval |
mbedalvaro | 0:4b5874bff9bb | 84 | myTriggerState=WAITING; |
mbedalvaro | 0:4b5874bff9bb | 85 | frameCounter=0; |
mbedalvaro | 0:4b5874bff9bb | 86 | } |
mbedalvaro | 0:4b5874bff9bb | 87 | |
mbedalvaro | 0:4b5874bff9bb | 88 | void toggleQP(bool mode) { |
mbedalvaro | 0:4b5874bff9bb | 89 | QP_Mode=mode; |
mbedalvaro | 0:4b5874bff9bb | 90 | } |
mbedalvaro | 0:4b5874bff9bb | 91 | |
mbedalvaro | 0:4b5874bff9bb | 92 | void stop() { |
mbedalvaro | 0:4b5874bff9bb | 93 | myTimer.detach(); |
mbedalvaro | 0:4b5874bff9bb | 94 | } |
mbedalvaro | 0:4b5874bff9bb | 95 | |
mbedalvaro | 0:4b5874bff9bb | 96 | void trigger() { |
mbedalvaro | 0:4b5874bff9bb | 97 | switch(myTriggerState) { |
mbedalvaro | 0:4b5874bff9bb | 98 | case WAITING: // if the state was "wait" and we got here, we need to start exposing: |
mbedalvaro | 0:4b5874bff9bb | 99 | _pin=0; // a high-low change triggers the camera |
mbedalvaro | 0:4b5874bff9bb | 100 | // now we need to reset the timeout and give it another value: |
mbedalvaro | 0:4b5874bff9bb | 101 | myTimer.attach_us(this, &Trigger::trigger, us_exposureTime); |
mbedalvaro | 0:4b5874bff9bb | 102 | myTriggerState=EXPOSE; |
mbedalvaro | 0:4b5874bff9bb | 103 | break; |
mbedalvaro | 0:4b5874bff9bb | 104 | case EXPOSE: // if the state was EXPOSE, we need to stop exposing and go to wait: |
mbedalvaro | 0:4b5874bff9bb | 105 | _pin=1; // a low-high stop exposing |
mbedalvaro | 0:4b5874bff9bb | 106 | // now we need to reset the timeout and give it another value: |
mbedalvaro | 0:4b5874bff9bb | 107 | myTimer.attach_us(this, &Trigger::trigger, us_waitingTime); |
mbedalvaro | 0:4b5874bff9bb | 108 | myTriggerState=WAITING; |
mbedalvaro | 0:4b5874bff9bb | 109 | |
mbedalvaro | 0:4b5874bff9bb | 110 | // Also, this means we acquired ONE frame... |
mbedalvaro | 0:4b5874bff9bb | 111 | // Switch the from phase to quadrature int the friend class Flipper, every N frames (if we want): |
mbedalvaro | 0:4b5874bff9bb | 112 | frameCounter=(frameCounter+1)%framesQPToggle; |
mbedalvaro | 0:4b5874bff9bb | 113 | if (QP_Mode&&frameCounter==0) { |
mbedalvaro | 0:4b5874bff9bb | 114 | //Flipper::state = ! Flipper::state ; // this correspond to calling the flip function (but without multiplier) |
mbedalvaro | 0:4b5874bff9bb | 115 | Flipper::delay90(); |
mbedalvaro | 0:4b5874bff9bb | 116 | } |
mbedalvaro | 0:4b5874bff9bb | 117 | break; |
mbedalvaro | 0:4b5874bff9bb | 118 | default: |
mbedalvaro | 0:4b5874bff9bb | 119 | break; |
mbedalvaro | 0:4b5874bff9bb | 120 | } |
mbedalvaro | 0:4b5874bff9bb | 121 | } |
mbedalvaro | 0:4b5874bff9bb | 122 | |
mbedalvaro | 0:4b5874bff9bb | 123 | private: |
mbedalvaro | 0:4b5874bff9bb | 124 | DigitalOut _pin; |
mbedalvaro | 0:4b5874bff9bb | 125 | bool QP_Mode; // this is to select toggling or not |
mbedalvaro | 0:4b5874bff9bb | 126 | triggerState myTriggerState; |
mbedalvaro | 0:4b5874bff9bb | 127 | unsigned int frameCounter; |
mbedalvaro | 0:4b5874bff9bb | 128 | unsigned int framesQPToggle; |
mbedalvaro | 0:4b5874bff9bb | 129 | unsigned int us_exposureTime, us_waitingTime; |
mbedalvaro | 0:4b5874bff9bb | 130 | Timeout myTimer; // I need to use a timeout, and not a ticker because the intervals are different for the trigger period and exposure time |
mbedalvaro | 0:4b5874bff9bb | 131 | }; |
mbedalvaro | 0:4b5874bff9bb | 132 | |
mbedalvaro | 0:4b5874bff9bb | 133 | // 3) The simulation of the LCD shutter: |
mbedalvaro | 0:4b5874bff9bb | 134 | class Shutter{ |
mbedalvaro | 0:4b5874bff9bb | 135 | friend class Flipper; // because we will modify the Flipper variable "multiplier" |
mbedalvaro | 0:4b5874bff9bb | 136 | |
mbedalvaro | 0:4b5874bff9bb | 137 | public: |
mbedalvaro | 0:4b5874bff9bb | 138 | // Note: we don't really need a toggling pin for this, but it can be good to see it on the oscilloscope |
mbedalvaro | 0:4b5874bff9bb | 139 | Shutter(PinName pin, unsigned int interval) : _pin(pin), us_interval(interval) { |
mbedalvaro | 0:4b5874bff9bb | 140 | state=true; |
mbedalvaro | 0:4b5874bff9bb | 141 | _pin=state; |
mbedalvaro | 0:4b5874bff9bb | 142 | mix=true; |
mbedalvaro | 0:4b5874bff9bb | 143 | } |
mbedalvaro | 0:4b5874bff9bb | 144 | |
mbedalvaro | 0:4b5874bff9bb | 145 | void start() { |
mbedalvaro | 0:4b5874bff9bb | 146 | myTicker.attach_us(this, &Shutter::flip, us_interval); // the address of the object, member function, and interval |
mbedalvaro | 0:4b5874bff9bb | 147 | } |
mbedalvaro | 0:4b5874bff9bb | 148 | |
mbedalvaro | 0:4b5874bff9bb | 149 | void mixSignal(bool mode) { |
mbedalvaro | 0:4b5874bff9bb | 150 | mix=mode; |
mbedalvaro | 0:4b5874bff9bb | 151 | } |
mbedalvaro | 0:4b5874bff9bb | 152 | |
mbedalvaro | 0:4b5874bff9bb | 153 | void stop() { |
mbedalvaro | 0:4b5874bff9bb | 154 | myTicker.detach(); |
mbedalvaro | 0:4b5874bff9bb | 155 | } |
mbedalvaro | 0:4b5874bff9bb | 156 | |
mbedalvaro | 0:4b5874bff9bb | 157 | // the shutter "flip" function also affect the friend variable "multiplier": |
mbedalvaro | 0:4b5874bff9bb | 158 | void flip() { |
mbedalvaro | 0:4b5874bff9bb | 159 | state = !state; |
mbedalvaro | 0:4b5874bff9bb | 160 | _pin=state; |
mbedalvaro | 0:4b5874bff9bb | 161 | if (mix) { |
mbedalvaro | 0:4b5874bff9bb | 162 | Flipper::multiplier=state; |
mbedalvaro | 0:4b5874bff9bb | 163 | } |
mbedalvaro | 0:4b5874bff9bb | 164 | else { |
mbedalvaro | 0:4b5874bff9bb | 165 | Flipper::multiplier=true; |
mbedalvaro | 0:4b5874bff9bb | 166 | } |
mbedalvaro | 0:4b5874bff9bb | 167 | Flipper::multImmediate(); |
mbedalvaro | 0:4b5874bff9bb | 168 | } |
mbedalvaro | 0:4b5874bff9bb | 169 | |
mbedalvaro | 0:4b5874bff9bb | 170 | private: |
mbedalvaro | 0:4b5874bff9bb | 171 | bool mix; // this is for mixing this signal with the led (ie, product) |
mbedalvaro | 0:4b5874bff9bb | 172 | bool state; |
mbedalvaro | 0:4b5874bff9bb | 173 | DigitalOut _pin; |
mbedalvaro | 0:4b5874bff9bb | 174 | unsigned int us_interval; |
mbedalvaro | 0:4b5874bff9bb | 175 | Ticker myTicker; |
mbedalvaro | 0:4b5874bff9bb | 176 | }; |
mbedalvaro | 0:4b5874bff9bb | 177 | |
mbedalvaro | 0:4b5874bff9bb | 178 | #endif |