C++ class for controlling DC motor with encoder feedback. Dependencies include LS7366LIB, MotCon, and PID.

Dependencies:   PID LS7366LIB MotCon2

Revision:
12:7a7fe3baf733
Parent:
11:93d924320ddc
--- a/Axis.cpp	Tue Nov 15 15:41:33 2016 +0000
+++ b/Axis.cpp	Wed Jan 09 13:35:44 2019 +0000
@@ -4,14 +4,73 @@
 #include "MotCon.h"
 #include "PID.h"
 
-Axis::Axis(SPI& spi, PinName cs, PinName pwm, PinName dir, PinName analog, int* limit): _spi(spi), _cs(cs), _pwm(pwm), _dir(dir) , _analog(analog){
+Axis::Axis(SPI& spi, PinName cs, PinName pwm, PinName dir, PinName analog, int* limit): _spi(spi), _cs(cs), _pwm(pwm), _dir(dir) , _dir2(NC), _analog(analog){
     this->_cs = 1;           // Initialize chip select as off (high)
     this->_pwm = 0.0;
     this->_dir = 0;
+    this->_dir2 = 0;
     this->co = 0.0;
     this->Tdelay = .01;
-    this->Pk = 140.0; //120.0;      //rough gains, seem to work well but could use tuning   
-    this->Ik = 95.0;  //75.0;
+    this->Pk = 450.0; //120.0;      //rough gains, seem to work well but could use tuning   
+    this->Ik = 105.0;  //75.0;
+    this->Dk = 0.0;
+    this->set_point = 0.0;
+    this->set_point_last = 0.0;
+    this->pos = 0.0;
+    this->vel = 0.0;
+    this->acc = 0.0;
+    this->stat = -1;
+    this->pos_cmd = 0.0;
+    this->vel_cmd = 0.0;
+    this->vel_avg_cmd = 0;
+    this->acc_cmd = 0.0;
+    this->vel_max = 2700.0 * Tdelay; //counts * Tdelay
+    this->acc_max = 1200.0 * Tdelay; //counts/sec/sec  * Tdelay
+    this->p_higher = 0.0;
+    this->p_lower = 0.0;
+    this->vel_accum = 0.0;
+    this->moveTime = 0.0;
+    this->enc = 0;
+    this->moveStatus = 0;     //status flag to indicate state of profile movement
+    this->moveState = 0;      //used for state machine in movement profiles
+    this->debug = 0;   
+    this->update.attach(this, &Axis::paramUpdate, this->Tdelay);
+    this->axisState = 0;
+    this->mot_I_lim = .35;    
+    this->dIdT = 0.0;
+    this->motI = 0.0;
+    this->motI_last = 0.0;
+    this->mot_I_max = 0.0;
+    this->mot_I_max_last = 0.0;
+    this->motInvert = 0;
+    this->dataFormat = 'r'; //default is radians
+//    this->ctsPerDeg = cpd;  //update counts per degree passed from constructor
+    this->moveMode=0;   //0 is position (default), 1 is velocity, 2 is acceleration
+    
+    this->pid = new PID(0.0,0.0,0.0,Tdelay); //Kc, Ti, Td, interval
+    this->ls7366 = new LS7366(spi, cs);  //LS7366 encoder interface IC
+    this->motcon = new MotCon(pwm, dir);
+    this->ptr_limit = limit;
+    
+    //start at 0    
+    this->ls7366->LS7366_reset_counter();
+    this->ls7366->LS7366_quad_mode_x4();       
+    this->ls7366->LS7366_write_DTR(0);
+    
+    this->set_point = 0.0;
+    this->pid->setSetPoint(this->set_point);
+    this->enc = this->ls7366->LS7366_read_counter();  //update class variable    
+}
+
+Axis::Axis(SPI& spi, PinName cs, PinName pwm, PinName dir, PinName dir2, PinName analog, int* limit): _spi(spi), _cs(cs), _pwm(pwm), _dir(dir) , _dir2(dir2),_analog(analog){
+    this->_cs = 1;           // Initialize chip select as off (high)
+    this->_pwm = 0.0;
+    this->_dir = 0;
+    this->_dir2 = 0;
+    this->co = 0.0;
+    this->Tdelay = .01;
+    this->Pk = 450.0; //120.0;      //rough gains, seem to work well but could use tuning   
+    this->Ik = 105.0;  //75.0;
     this->Dk = 0.0;
     this->set_point = 0.0;
     this->set_point_last = 0.0;
@@ -36,13 +95,19 @@
     this->update.attach(this, &Axis::paramUpdate, Tdelay);
     this->axisState = 0;
     this->mot_I_lim = .35;    
+    this->dIdT = 0.0;
+    this->motI = 0.0;
+    this->motI_last = 0.0;
+    this->mot_I_max = 0.0;
+    this->mot_I_max_last = 0.0;
     this->motInvert = 0;
     this->dataFormat = 'r'; //default is radians
 //    this->ctsPerDeg = cpd;  //update counts per degree passed from constructor
+    this->moveMode=0;   //0 is position (default), 1 is velocity, 2 is acceleration
     
-    this->pid = new PID(0.0,0.0,0.0,Tdelay); //Kc, Ti, Td, interval
+    this->pid = new PID(0.0,0.0,0.0,this->Tdelay); //Kc, Ti, Td, interval
     this->ls7366 = new LS7366(spi, cs);  //LS7366 encoder interface IC
-    this->motcon = new MotCon(pwm, dir);
+    this->motcon = new MotCon(pwm, dir, dir2);
     this->ptr_limit = limit;
     
     //start at 0    
@@ -55,7 +120,7 @@
     this->enc = this->ls7366->LS7366_read_counter();  //update class variable    
 }
 
-void Axis::init(void){ 
+void Axis::init(float encCountsPerRev){ 
     //resets the controllers internals
     this->pid->reset();
 
@@ -69,6 +134,9 @@
     
     this->pid->setInterval(this->Tdelay);
       
+    //set the encoder counts per revolution/linear throw
+    this->countsPerRev=encCountsPerRev;
+      
     //start at 0    
     this->ls7366->LS7366_reset_counter();
     this->ls7366->LS7366_quad_mode_x4();       
@@ -86,19 +154,33 @@
                                                         
     this->pid->setTunings(this->Pk, this->Ik, this->Dk); //turns on controller    
 }
-    
+
+void Axis::updatePIDgains(float P, float I, float D){
+    this->Pk = P; //120.0;      //rough gains, seem to work well but could use tuning   
+    this->Ik = I;  //75.0;
+    this->Dk = D;
+    this->pid->setTunings(this->Pk, this->Ik, this->Dk);
+}
+
 void Axis::paramUpdate(void){    
     //testOut = 1;    
     this->enc = this->ls7366->LS7366_read_counter();
-    this->pos = (float)this->enc; // * this->countsPerDeg * PI/180.0; //times counts/degree and convert to radians
-        
-    this->vel = (this->pos - this->pos_last) * this->Tdelay;
-    this->acc = (this->vel - this->vel_last);
+    //this->pos = (float)this->enc; // * this->countsPerDeg * PI/180.0; //times counts/degree and convert to radians
+    
+    this->pos =  ((float)this->enc / this->countsPerRev) * 6.28319; //Conver pos to radians
+    this->vel = (this->pos - this->pos_last) * (1.0/this->Tdelay); //current vel in radians
+    this->acc = (this->vel - this->vel_last) * (1.0/this->Tdelay);
 
     this->pid->setSetPoint(this->set_point);    
     
     //Update the process variable.
-    this->pid->setProcessValue(this->pos);
+    if(this->moveMode == 0)
+        this->pid->setProcessValue(this->pos);
+    if(this->moveMode == 1)
+        this->pid->setProcessValue(this->vel);
+    if(this->moveMode == 2)
+        this->pid->setProcessValue(this->acc);
+        
     //Set the new output.
     this->co = this->pid->compute();
 
@@ -120,30 +202,7 @@
     this->set_point_last = this->set_point;
 }
 
-void Axis::center(void){    
-    while((*this->ptr_limit == 1) && (this->readCurrent() < mot_I_lim)){ //limit switch not pressed and mot current not exceeded
-       this->set_point += 100;
-       wait(.05);
-       if(this->debug)
-            printf("T=%.2f SP=%.3f co=%.3f pos=%.3f vel=%.3f acc=%.3f limit=%d motI=%.3f\r\n", t.read(), this->set_point, this->co, this->pos, this->vel, this->acc,*this->ptr_limit, this->_analog.read());
-    }
-    wait(.5);
-    while((*this->ptr_limit == 0)){ //limit switch is pressed
-       this->set_point -= 10;
-       wait(.1);
-       if(this->debug)
-            printf("T=%.2f SP=%.3f co=%.3f pos=%.3f vel=%.3f acc=%.3f limit=%d motI=%.3f\r\n", t.read(), this->set_point, this->co, this->pos, this->vel, this->acc,*this->ptr_limit, this->_analog.read());
-    }
-    this->zero();   //zero channel        
-    
-//    this->set_point = -(totalCounts/2.0);
-        
-    if(this->debug)
-        printf("HOME END:T=%.2f SP=%.3f co=%.3f pos=%.3f vel=%.3f acc=%.3f limit=%d motI=%.3f\r\n", t.read(), this->set_point, this->co, this->pos, this->vel, this->acc,*this->ptr_limit, this->_analog.read());
-//    pc.printf("End Home\r\n\r\n");
-}
-
-void Axis::moveUpdate(void){               
+void Axis::moveUpdateTrapezoid(void){               
 
 /*    if(*this->ptr_limit == 0){
         this->moveState = 4;    //terminate the move
@@ -251,12 +310,17 @@
     this->moveState = 1;
     this->t.reset();
     this->t.start();
-    this->moveProfile.attach(this, &Axis::moveUpdate, this->Tdelay);
+    this->moveProfile.attach(this, &Axis::moveUpdateTrapezoid, this->Tdelay);
 }
 
 float Axis::readCurrent(void){    
-    motCurrent = (this->_analog.read() * 3.3) / .525;  //525mV per amp
-    return motCurrent;
+    this->motI = (this->_analog.read() * 3.3) / .525;  //525mV per amp
+    if(this->motI > this->mot_I_max){
+        this->mot_I_max = this->motI;
+    }
+    this->dIdT = motI - motI_last;
+    this->motI_last = motI;
+    return this->motI;
 }
 
 void Axis::axisOff(void){
@@ -267,10 +331,12 @@
 
 void Axis::axisOn(void){    
     this->co = 0.0;
-    this->pid->reset();              
-    //start at 0
-    this->set_point = 0.0;
-    this->pid->setSetPoint(0); 
+    this->pid->reset();
+    //start at 0 if not already homed   (commented out on 20181217 to accomodate vel mode
+//    if(this->stat != 0){
+//        this->set_point = 0.0;
+//        this->pid->setSetPoint(0); 
+//    }
                                                         
     this->pid->setTunings(this->Pk, this->Ik, this->Dk); //turns on controller
     this->axisState = 1;
@@ -286,6 +352,7 @@
     this->enc = this->ls7366->LS7366_read_counter();
     
     this->pos = 0.0;
+    this->pid->reset();     //added to avoid possible itegral windup effects on instant position change 20170616
     this->set_point = 0.0;
     this->pid->setSetPoint(0);    
     
@@ -297,4 +364,27 @@
         
     this->set_point = (float)value;
     this->pid->setSetPoint(this->set_point);        
-}
\ No newline at end of file
+}
+
+//mode = 0 position, 1 - volocity, 2 - acceleration
+void Axis::changeMoveMode(int mode){    
+        
+    if(mode == 0){
+        this->Tdelay = .01;
+        //Encoder counts limit
+        this->moveMode = 0;
+    }
+    else if(mode == 1){
+        this->Tdelay = .05;
+        //this->pid->setInputLimits(-100.0, 100.0);
+        this->moveMode = 1;        
+    }
+    else if(mode == 2){
+        this->Tdelay = .05;
+        //this->pid->setInputLimits(-100.0, 100.0);
+        this->moveMode = 2;  
+    }
+    this->pid->setInterval(this->Tdelay);
+    this->update.attach(this, &Axis::paramUpdate, this->Tdelay);
+}
+