Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: Motor.cpp
- Revision:
- 0:18e417fff669
- Child:
- 1:041f0a1fc2e5
- Child:
- 2:3bf51023ea23
diff -r 000000000000 -r 18e417fff669 Motor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Motor.cpp Fri Mar 13 08:18:24 2015 +0000 @@ -0,0 +1,114 @@ + #include "Motor.h" + +/* Theory of operation of the tachometer reading system + + The interrupt is Tach, an InterruptIn object. + + To filter out the horrible transients, some debounce and stuff is being done. This function, tach_mark(), is called + on a rising edge. It checks whether the risen edge is still there 10us later. (Using a blocking wait_us() call, + which is bad practice, but not that bad considering how short 10 us is. I don't think it would be that difficult to instead have it \ + set up a 10us delay and nonblockingly interrupt-call a function using a Timeout. + + Anyway, if it is still there, it then records the read from TachTimer and resets the TachTimer, and adds the read value to + the ring buffer and to the delta_t global. + + It *also* disables the Tach rising edge interrupt. (i.e disables itself) and enables a ~~falling~~ edge interrupt on Tach. This + falling edge interupt then does mostly the same thing w/r/t filtering, and enables the rising edge after a confirmed falling edge. + +*/ +void addToRingBuf(int val, volatile int *ringBuf, volatile int *ringBufIdx) //Is called in ISR. Adds stuff to ring buffer, obviously. +{ + ringBuf[*ringBufIdx] = val; + *ringBufIdx = (*ringBufIdx + 1) % RING_BUF_SZ; +} + + +void tach_mark(volatile int *ringBuf, + volatile int *ringBufIdx, + InterruptIn *Tach, + Timer *TachTimer, + volatile bool *new_tach_flag, + void (*tach_antimark_handler)(void)) //PRIMARY ISR called on rising edge of encoder. +{ + int dt = TachTimer->read_us(); + + wait_us(10); + if(Tach->read()) { + TachTimer->reset(); + *new_tach_flag = 1; + addToRingBuf(dt, ringBuf, ringBufIdx); + Tach->rise(NULL); + Tach->fall(tach_antimark_handler); // Reset after a falling edge. //set to handler for antimark + } +} + + +void tach_antimark(InterruptIn *Tach, void (*tach_mark_handler)(void)) +{ + wait_us(10); // This can surely be done better with a Timeout. Medium priority. Highest is getting it in a + //library/object and to work with two encoders at once. + if(!Tach->read()) { + Tach->fall(NULL); + Tach->rise(tach_mark_handler); //set to handler function for mark + } +} + + +float get_speed(volatile bool *new_tach_flag, + Timer *TachTimer, + volatile int *ringBuf, + volatile int *ringBufIdx) +{ + if(new_tach_flag) { + new_tach_flag = 0; + } + + // if no pulse in 400ms, motor is probably stopped + // 3% duty cycle is lowest the motor will run with, has <400ms period + if(TachTimer->read_ms() > 400) { + addToRingBuf(INT_MAX, ringBuf, ringBufIdx); + TachTimer->reset(); + } + + int avg = 0; + for (int i = 0; i < RING_BUF_SZ; i++) { + if (ringBuf[i] == INT_MAX) { + avg = INT_MAX; + break; + } + avg += ringBuf[i]; + } + + if (avg == INT_MAX) { + return 0; + } else { + avg = avg / RING_BUF_SZ; + if (avg > 400000) { //400 ms + return 0; + } else { + return WHEEL_CIRCUM / ((2.0 * (float)avg) / 1000.0); + } + } +} + +void speed_control(volatile float target_spd, + float actual_spd, + float *iState, + float iLimit, + volatile float ki, + volatile float kp, + PwmOut *motor) +{ + + float delta_spd = target_spd - actual_spd; + + (*iState) += delta_spd; + if ((*iState)*ki > iLimit) { + (*iState) = iLimit; + } else if ((*iState)*ki < -iLimit) { + (*iState) = -iLimit; + } + + // PI controller! + motor->write(kp * delta_spd + ki * (*iState)); +}