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

Revision:
62:d502889e74f1
Child:
65:2ac186553959
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LinearActuator/LinearActuator.cpp	Mon Jun 18 14:45:37 2018 +0000
@@ -0,0 +1,325 @@
+#include "mbed.h"
+#include "LinearActuator.hpp"
+#include "StaticDefs.hpp"
+#include "ConfigFile.h"
+ 
+// this is where the variables that can be set are set when the object is created
+LinearActuator::LinearActuator(float interval, PinName pwm, PinName dir, PinName reset, PinName limit, int adc_ch):
+    _motor(pwm, dir, reset),
+    _filter(),
+    _pid(),
+    _pulse(),
+    _limitSwitch(limit)
+{
+    _limitSwitch.fall(callback(this, &LinearActuator::_switchPressed));
+    
+    _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;
+ 
+    _pid_high_limit = 0.0;
+    _pid_low_limit = 0.0;
+}
+ 
+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;
+        }
+        
+        // clamp the output to the motor to -1.0 to 1.0
+        if (_pid.getOutput() > 1.0)
+            _motor.run(1.0);
+        else if (_pid.getOutput() < -1.0)
+            _motor.run(-1.0);
+        else 
+            _motor.run(_pid.getOutput());
+    }
+}
+
+// using main loop ticker (attached at 0.01 intervals)
+void LinearActuator::runLinearActuator() {
+    _init = true;
+}
+ 
+void LinearActuator::start() {
+    _init = true;
+    _pulse.attach(this,&LinearActuator::update, _dt);
+}
+ 
+void LinearActuator::stop() {
+    _motor.stop();
+    _pulse.detach();
+    _init = true;
+}
+ 
+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);
+}
+ 
+// setting and getting variables
+void LinearActuator::setPosition_mm(float 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::getSetPosition_mm() {
+    return _SetPoint_mm;
+}
+ 
+float LinearActuator::getPosition_mm() {
+    return _position_mm;
+}
+ 
+float LinearActuator::getPosition_counts() {
+    return _position;
+}
+ 
+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();
+    
+    //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(-0.5);
+    
+    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) {
+            pc().printf("\r\nHit limit switch\r\n");
+            //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);
+                return;
+            }
+        }
+    }
+}
+ 
+bool LinearActuator::getSwitch() {
+    return _limit;
+}
+ 
+ void LinearActuator::setDeadband(float deadband) {
+    _deadband = deadband;
+    _pid.setDeadBand(_deadband);
+    return;    
+}
+
+float LinearActuator::getDeadband() {
+    return _deadband;
+}
+ 
+bool LinearActuator::toggleDeadband(bool toggle) {
+    _pid.toggleDeadBand(toggle);
+    return toggle;
+}
+
+void LinearActuator::setPIDHighLimit(float high_limit) {
+    _pid_high_limit = high_limit;
+    _pid.setHiLimit(_pid_high_limit);
+}
+
+void LinearActuator::setPIDLowLimit(float low_limit) {
+    _pid_low_limit = low_limit;
+    _pid.setLoLimit(_pid_low_limit);                   //default at zero, or the switch retracted
+}
\ No newline at end of file