most functionality to splashdwon, find neutral and start mission. short timeouts still in code for testing, will adjust to go directly to sit_idle after splashdown

Dependencies:   mbed MODSERIAL FATFileSystem

LinearActuator/LinearActuator.cpp

Committer:
mkelly10
Date:
2017-10-20
Revision:
9:d5fcdcb3c89d
Child:
10:085ab7328054

File content as of revision 9:d5fcdcb3c89d:

#include "mbed.h"
#include "LinearActuator.hpp"
#include "StaticDefs.hpp"
#include "ConfigFile.h"
 
LinearActuator::LinearActuator(float interval, PinName pwm, PinName dir, PinName reset, PinName limit, int adc_ch):
    _motor(pwm, dir, reset),
    _filter(),
    _pid(),
    //_time(),
    _pulse(),
    _limitSwitch(limit)
{
    _limitSwitch.fall(callback(this, &LinearActuator::_switchPressed));
    // this is where the variables that can be set are set when the object is created
    _Pgain = 0.10;
    _Igain = 0.0;
    _Dgain = 0.0;
    
    _filterFrequency = 1.0;
 
    _adc_channel = adc_ch;
 
    _dt = interval;
 
    _init = true;
    _paused = false;
    _limit = false;
    _slope = 498.729/4096;  //this value should be correct for our current string pots using .625" diameter and 12 bit ADC
    _deadband = 0.5;
 
}
 
void LinearActuator::init()
{
    // initialize and start all of the member objects.
    // The pos-velocity filter for this item needs to be allowed to converge
    // Before turning over control to the motor
    // make sure that adc().init is called in mainline code before calling this function
 
    //load gains into pid controller this should eventually be in a config file
    setFilterFrequency(_filterFrequency);
    setControllerP(_Pgain);
    setControllerI(_Igain);
    setControllerD(_Dgain);
    
    //setup the controller object
    //set deadband and limits
    toggleDeadband(true);
    setDeadband(_deadband);
 
}
 
void LinearActuator::update()
{
 
 
    //update the position velocity filter
    if (_adc_channel == 0) {
        _filter.update(_dt, adc().readCh0());
    } else if (_adc_channel == 1) {
        _filter.update(_dt, adc().readCh1());
    } else {
        error("\n\r This ADC channel does not exist");
    }
 
    //refresh the filter results and load into class variables
    refreshPVState();
 
    // update the PID controller with latest data
    _pid.update(_position_mm, _velocity_mms, _filter.getDt());
 
    if (_init) {
        //The initialization phase is active
        //dont run the motors until the velocity stabilizes
        if (abs(_velocity_mms)<0.1) {
            //we must be converged and can now release the motor controls
            _init = false;
        }
    } else if (_limit) {
        //if you end up here, an interrupt was triggered by an edge detection
        //case on the limit switch. That function would have stopped the motor
        //This logic should allow it to be re-enabled if the output being asked
        //for by the controller is the correct direction.
 
        if (_pid.getOutput() < 0.0) { //a negative pid output results in motion toward the switch
            //dont let the motor run
            return;
        } else {
            //We are now trucking along in the correct direction, it is ok to
            //reset the limit variable and allow the motor to run
            _limit = false;
        }
    } else if (_paused) {
        //if you get here, the pause function has stopped the motor
        //the only way out is for a function call to unpause the motor
        //this case also keeps the controller disconnected in the event that
        //homing is happening
        return;
    }
 
    else {
        //pipe controller data into the motor driver
        //check that the limit switch is not pressed and if it is only let the
        //motor run if the command is a negative number
        //this catches the case where the piston is being moved off of the switch
        //and the motor command reverses for some reason
 
        if ((_limitSwitch.read() == 0) && (_pid.getOutput()< 0)) {
            //dont run
            return;
        }
        _motor.run(_pid.getOutput());
    }
}
 
void LinearActuator::start()
{
    _init = true;
    _pulse.attach(this,&LinearActuator::update, _dt);
    
}
 
void LinearActuator::stop()
{
    _motor.stop();
    _pulse.detach();
}
 
void LinearActuator::pause()
{
    //this allows the controller to keep running while turning off the motor output
    _motor.stop();
    //paused flag causes controller output not to be piped to the motor
    _paused = true;
}
 
void LinearActuator::unpause()
{
    //this resumes motor operation
    _paused = false;
}
 
void LinearActuator::refreshPVState()
{
    _position = _filter.getPosition();
    _velocity = _filter.getVelocity();
 
    _position_mm = counts_to_dist(_position);
    _velocity_mms = counts_to_velocity(_velocity);
 
//    _position_mL = _mm_to_mL(_position_mm);
//    _velocity_mLs = _mm_to_mL(_velocity_mms);
 
}
 
// setting and getting variables
void LinearActuator::setPosition_mm(float dist)
{
    // convert mm representation to volume in mL
//    _SetPoint_mL = _mm_to_mL(dist);
    _SetPoint_mm = clamp<float>(dist, 0.0, _extendLimit);  //this is another spot that prevents the requested set point from going out of range, this template function is defined in the controller header file fyi
 
    _pid.writeSetPoint(_SetPoint_mm);
 
}
 
float LinearActuator::getPosition_mm()
{
    return _position_mm;
}
 
float LinearActuator::getPosition_counts()
{
    return _position; // returns raw adc counts (useful for zeroing)
}
 
float LinearActuator::getVelocity_mms()
{
    return _velocity_mms;
}
 
void LinearActuator::setControllerP(float P)
{
    _Pgain = P;
    _pid.setPgain(_Pgain);
    return;
}
 
float LinearActuator::getControllerP()
{
    return _Pgain;
}
 
void LinearActuator::setControllerI(float I)
{
    _Igain = I;
    _pid.setIgain(_Igain);
    return;
}
 
float LinearActuator::getControllerI()
{
    return _Igain;
}
 
void LinearActuator::setControllerD(float D)
{
    _Dgain = D;
    _pid.setDgain(_Dgain);
    return;
}
 
float LinearActuator::getControllerD()
{
    return _Dgain;
}
 
float LinearActuator::getOutput()
{
    return _pid.getOutput();
}
 
void LinearActuator::setZeroCounts(int zero)
{
    _zeroCounts = clamp<int>(zero, 0, 4096);
    return;
}
 
int LinearActuator::getZeroCounts()
{
    return _zeroCounts;    
}
 
void LinearActuator::setTravelLimit(float limit)
{
    _extendLimit = limit;
    return;
}
 
float LinearActuator::getTravelLimit()
{
    return _extendLimit;   
}
 
void LinearActuator::setPotSlope(float slope)
{
    _slope = slope;
    return;
}
 
float LinearActuator::getPotSlope()
{
    return _slope;    
}
 
float LinearActuator::counts_to_dist(int count)
{
    float conv = _slope*(count-_zeroCounts);
    return conv;
}
 
void LinearActuator::setFilterFrequency(float frequency)
{
    _filterFrequency = frequency;
    _filter.writeWn(frequency);   
}
 
int LinearActuator::dist_to_counts(float dist)
{
    float conv = (dist/_slope)+_zeroCounts;
    return (int) conv;
}
 
float LinearActuator::counts_to_velocity(int count)
{
    float conv = count*_slope;
    return conv;
}
 
void LinearActuator::_switchPressed()
{
    //first thing to do is stop the motor
    _motor.stop();
    _limit = true;
}
 
void LinearActuator::homePiston()
{
    //start calling the update for the Linear Actuator
    //start the controller update and immediatley pause the motor output
    start();
    pause();
    
    //trap program execution here until the filter is converged
    while(_init){
        //just wait here until the things calm down   
    }
    
    //Now that the readings are stabilized
    // This sends the motor on a kamakaze mission toward the limit switch
    // The interrupt should catch and stop it and the piston is now at home
    //position
    _motor.run(-1.0);
    
    while (1) {
        //trap the program here while we wait for the limit switch to be triggered
        //when it does, the limit interrupt will stop the motors
        if (_limit) {
            //the switch has been pressed
            if (abs(_filter.getVelocity()) < 0.1) {
                //this is here to make sure the adc filter is not jittering around
                //we are probably stable enough to take a zero here
                _zeroCounts = _filter.getPosition();
                
                // This can be used for troubleshooting
                //pc().printf("\n\rzero_counts: %4i     \n\r" , _zeroCounts);
                //stop the update loop
                stop();
                return;
            }
        }
    }
}
 
bool LinearActuator::getSwitch()
{
    return _limit;
}
 
 void LinearActuator::setDeadband(float deadband)
{
    _deadband = deadband;
    _pid.setDeadBand(_deadband);
    return;    
}
 
bool LinearActuator::toggleDeadband(bool toggle)
{
    _pid.toggleDeadBand(toggle);
    return toggle;
}