The iPod controller that I submitted for the mbed challenge

Dependencies:   mbed Motordriver PID

fader.cpp

Committer:
networker
Date:
2011-05-04
Revision:
0:371773dd3dd1

File content as of revision 0:371773dd3dd1:

#include "fader.h"
#define MUSTSTOP    //some motordrivers will not change direction without a stop
//#define GETSTAT

int n =0;
float sumprod = 0.0, sum = 0;;

DigitalOut track(LED2); //debug only

#ifdef USESUPPLY
AnalogIn Vmotor(p17);
float getVmotor() {
    return Vmotor*13.3;    //for 3.3V referemce and 100k,33k divider
}
#else
float getVmotor() {
    return 6.0;    //assume 6V supply
}
#endif


servo::servo(PinName p, PinName f, PinName r, PinName a): Motor(p, f, r, 0) {
    const float Ts = 0.001;//sample period in seconds, 1kHz
    deadband = 0.001; // +/- 0.5mm, noise???
    _pwm.period_us(100); //10kHz otherwise very annoying sound
    fb = new AnalogIn(a);
    flt = new medianFilter(7);
    float voltage = getVmotor(); //make the gain dependent on the supply voltage
    float Kp = 9.0 - 0.5*voltage; //gain=6 @6V
    pid = new PID(Kp , 0.05, 0.000002, Ts);//work well @6V motor supply
    pid->setInputLimits(0, 1.0);
    pid->setOutputLimits(-1.0, 1.0);
    pid->setBias(0.0);//just to set internal feedforward variable
    _setPoint = 0.0;
    pid->setSetPoint(_setPoint);
    tick.attach(this,&servo::process, Ts);
}

void servo::process() {
    update();
    float p = pos();//(filtered) value of the potentiometer as a value between 0.0 and 1.0
    pid->setProcessValue(p); //set it as the value to control (Ist-wert)
    float out = pid->compute(); //compute the motor speed
#ifdef MUSTSTOP
    if ((out > 0 && _out < 0) || (out < 0 && _out > 0))
        _out = 0.0;//stop first
    else
        _out = out;
#else
    _out = out;
#endif
    if (fabs(p - _setPoint) < deadband) {
        coast(); //near setpoint so disconnect motor to allow manual movement
        coasting = true;
    } else {
        speed(_out);
        coasting = false;
    }
}

fader::fader(PinName p, PinName f, PinName r, PinName a, PinName t): servo(p,f,r,a) {
    thres = 0.01;
    thres2 = 0.001;
    count = 0;
    command = 0;
    state = tracking;
    if (t != NC)
        touch = new AnalogIn(t);
    else
        touch = 0;
}

void fader::process() { //called by the ticker every 1 ms
    float p;
    switch (state) { //make sure that each branch calls either servo::process or servo::update for proper filtering
        case tracking:
            servo::process();
            p = pos();
            if (isCoasting()) { //servo is near it's setpoint, motor is off
                state = holding;
                lastpos = p; //save the position that was reached
                track = 1; //debug
            }
            break;
        case holding:
            update();
            p = pos();
            if (fabs(lastpos - p) > thres) { //apparently position has changed (manual move)
                state = moving;
                printf("moving from %f to %f\n", lastpos, p);
                lastpos = p;
                count = 0;
            }//if not, stay in 'holding' until next 'set' command, do not update lastpos
            break;
        case moving:
            //not tracking but coasting
            update();
            p = pos();
            if (fabs(lastpos - p) < thres2) {
                count++;
            } else {
                count = 0;
            }
            if (count > 100) { //apparently movement has stopped, movement less then thres2 for 100ms
                printf("movement stopped at %f\n", p);
                servo::set(p); //update the servo setpoint (has no effect because state is not tracking)
                if (command)
                    command(p); //invoke the OnMove handler
                state = holding; //go back to holding state to allow a new fader::set and return to tracking
            }
            lastpos = p;
            break;
        default: //cannot happen
            update();
            p = pos();
    }
    if (touch && *touch > thres) { //stub: if input fullfills some condition (touch sense on fader)
        if (command)
            command(p);
    }
#ifdef GETSTAT
    sum += p;
    sumprod += p*p;
    n++;
    if (n == 1000) {
        float mean = sum/n;
        float var = sumprod/n - mean*mean;
        printf("n=%d, E=%f, Var = %f, sDev=%f\n", n, mean, var, sqrt(var));
        n=0;
        sum=0;
        sumprod=0;
    }
#endif
}