parent
							
								
									5e7c66f454
								
							
						
					
					
						commit
						b1469c0ce9
					
				| @ -0,0 +1,198 @@ | |||||||
|  | #include <digitalWriteFast.h> | ||||||
|  | //this is to use DWF library, it will increase the speed of digitalRead/Write command
 | ||||||
|  | //used in the interrupt function doEncoderMotor0, but may be used everywhere.
 | ||||||
|  | /*
 | ||||||
|  | https://github.com/danithebest91/ServoStrap
 | ||||||
|  |  i have made this code for the LMD18245 motor controller,  | ||||||
|  |   i have merged the pid code of  Josh Kopel  | ||||||
|  |     whith the code of makerbot servo-controller board, | ||||||
|  |   you can use this code on the some board changing some values. | ||||||
|  |   Daniele Poddighe | ||||||
|  |    external ardware require a quadrature encoder, timing slit strip and a dc motor, | ||||||
|  |    all you can find inside an old printer, i have took it from canon and hp printers(psc1510) | ||||||
|  |     | ||||||
|  |    for motor controll you can choose different type of H-bridge, i have used LMD18245, | ||||||
|  |    you can order 3 of it on ti.com sample request, the hardware needed is explained on the datasheet but i'm drowing | ||||||
|  |    the schematic and PCB layout on eagle. | ||||||
|  |     | ||||||
|  |     | ||||||
|  |    read a rotary encoder with interrupts | ||||||
|  |    Encoder hooked up with common to GROUND, | ||||||
|  |    encoder0PinA to pin 2, encoder0PinB to pin 4 (or pin 3 see below) | ||||||
|  |    it doesn't matter which encoder pin you use for A or B  | ||||||
|  |     | ||||||
|  |    is possible to change PID costants by sending on serial interfaces the values separated by ',' in this order: KP,KD,KI | ||||||
|  |    example: 5.2,3.1,0 so we have  KP=5.2 KD=3.1 KI=0 is only for testing purposes, but i will leave this function with eeprom storage | ||||||
|  |     | ||||||
|  |    This code use Port manipulation : | ||||||
|  |    Port registers allow for lower-level and faster manipulation of the i/o pins of the microcontroller on an Arduino board. The chips used on the Arduino board | ||||||
|  |    (the ATmega8 and ATmega168) have three ports:  | ||||||
|  |     B (digital pin 8 to 13) | ||||||
|  |     C (analog input pins) | ||||||
|  |     D (digital pins 0 to 7) | ||||||
|  |    https://www.arduino.cc/en/Reference/PortManipulation
 | ||||||
|  |     | ||||||
|  |    https://www.arduino.cc/en/Hacking/PinMapping
 | ||||||
|  |    https://www.arduino.cc/en/Hacking/PinMapping168
 | ||||||
|  | */  | ||||||
|  | 
 | ||||||
|  | #define encoder0PinA  2 // PD2 (INT0) You can't modify port mapping here because this code use Port manipulation (I2)
 | ||||||
|  | #define encoder0PinB  8  // PB0; (I8)
 | ||||||
|  | 
 | ||||||
|  | #define MotorIN1     5 //(I5) IN1
 | ||||||
|  | #define MotorIN2     6 //(I6) IN2
 | ||||||
|  | 
 | ||||||
|  | //from ramps 1.4 stepper driver
 | ||||||
|  | #define STEP_PIN              3  //PD3 (INT1) (I3)
 | ||||||
|  | #define DIR_PIN               14 //PC0; (A0)
 | ||||||
|  | //#define ENABLE_PIN            13 //PB5; for now is USELESS (I13)
 | ||||||
|  | 
 | ||||||
|  | //to use current motor as speed control, the LMD18245 has 4 bit cuttent output
 | ||||||
|  | //#define  M0 9   //assign 4 bit from PORTB register to current control -> Bxx0000x (x mean any)
 | ||||||
|  | //#define  M1 10  // PB1; PB2; PB3; PB4
 | ||||||
|  | //#define  M2 11
 | ||||||
|  | //#define  M3 12
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | volatile long encoder0Pos = 0; | ||||||
|  | 
 | ||||||
|  | long target = 0; | ||||||
|  | long target1 = 0; | ||||||
|  | int amp=212; | ||||||
|  | //correction = Kp * error + Kd * (error - prevError) + kI * (sum of errors)
 | ||||||
|  | //PID controller constants
 | ||||||
|  | float KP = 6.0 ; //position multiplier (gain) 2.25
 | ||||||
|  | float KI = 0.1; // Intergral multiplier (gain) .25
 | ||||||
|  | float KD = 1.3; // derivative multiplier (gain) 1.0
 | ||||||
|  | 
 | ||||||
|  | int lastError = 0; | ||||||
|  | int sumError = 0; | ||||||
|  | 
 | ||||||
|  | //Integral term min/max (random value and not yet tested/verified)
 | ||||||
|  | int iMax = 100; | ||||||
|  | int iMin = 0; | ||||||
|  | 
 | ||||||
|  | long previousTarget = 0; | ||||||
|  | long previousMillis = 0;        // will store last time LED was updated
 | ||||||
|  | long interval = 5;           // interval at which to blink (milliseconds)
 | ||||||
|  | 
 | ||||||
|  | //for motor control ramps 1.4
 | ||||||
|  | bool newStep = false; | ||||||
|  | bool oldStep = false; | ||||||
|  | bool dir = false; | ||||||
|  | 
 | ||||||
|  | void setup() {  | ||||||
|  |   pinModeFast(2, INPUT); | ||||||
|  |   pinModeFast(encoder0PinA, INPUT);  | ||||||
|  |   pinModeFast(encoder0PinB, INPUT);   | ||||||
|  |    | ||||||
|  |   pinModeFast(DirectionPin, OUTPUT);  | ||||||
|  |   //pinMode(SpeedPin, OUTPUT);
 | ||||||
|  |    | ||||||
|  |   //ramps 1.4 motor control
 | ||||||
|  |     pinModeFast(STEP_PIN, INPUT); | ||||||
|  |     pinModeFast(DIR_PIN, INPUT); | ||||||
|  |     //pinModeFast(M0,OUTPUT);
 | ||||||
|  |     //pinModeFast(M1,OUTPUT);
 | ||||||
|  |     //pinModeFast(M2,OUTPUT);
 | ||||||
|  |     //pinModeFast(M3,OUTPUT);
 | ||||||
|  | 
 | ||||||
|  |   attachInterrupt(0, doEncoderMotor0, CHANGE);  // encoder pin on interrupt 0 - pin 2
 | ||||||
|  |   attachInterrupt(1, countStep, RISING);  //on pin 3
 | ||||||
|  |    | ||||||
|  |   Serial.begin (115200); | ||||||
|  |   Serial.println("start");                // a personal quirk
 | ||||||
|  | 
 | ||||||
|  | }  | ||||||
|  | 
 | ||||||
|  | void loop(){ | ||||||
|  |    | ||||||
|  |   while (Serial.available() > 0) { | ||||||
|  |     KP = Serial.parseFloat(); | ||||||
|  |     KD = Serial.parseFloat(); | ||||||
|  |     KI = Serial.parseFloat(); | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     Serial.println(KP); | ||||||
|  |     Serial.println(KD); | ||||||
|  |     Serial.println(KI); | ||||||
|  | } | ||||||
|  |    | ||||||
|  |   if(millis() - previousTarget > 1000){ //enable this code only for test purposes because it loss a lot of time
 | ||||||
|  |   Serial.print(encoder0Pos); | ||||||
|  |   Serial.print(','); | ||||||
|  |   Serial.println(target1); | ||||||
|  |   previousTarget=millis(); | ||||||
|  |   } | ||||||
|  |          | ||||||
|  |   target = target1; | ||||||
|  |   docalc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void docalc() { | ||||||
|  |    | ||||||
|  |   if (millis() - previousMillis > interval)  | ||||||
|  |   { | ||||||
|  |     previousMillis = millis();   // remember the last time we blinked the LED
 | ||||||
|  |      | ||||||
|  |     long error = encoder0Pos - target ; // find the error term of current position - target    
 | ||||||
|  |      | ||||||
|  |     //generalized PID formula
 | ||||||
|  |     //correction = Kp * error + Kd * (error - prevError) + kI * (sum of errors)
 | ||||||
|  |     long ms = KP * error + KD * (error - lastError) +KI * (sumError); | ||||||
|  |         | ||||||
|  |     lastError = error;     | ||||||
|  |     sumError += error; | ||||||
|  |      | ||||||
|  |     //scale the sum for the integral term
 | ||||||
|  |     if(sumError > iMax) { | ||||||
|  |       sumError = iMax; | ||||||
|  |     } else if(sumError < iMin){ | ||||||
|  |       sumError = iMin; | ||||||
|  |     } | ||||||
|  |     int motorspeed = map(ms,0,amp,0,255); | ||||||
|  |    if( motorspeed >= 255) motorspeed=255; | ||||||
|  |     | ||||||
|  |     if(ms > 0){ | ||||||
|  |  	  digitalWriteFast ( MotorIN1 ,LOW ); | ||||||
|  | 	  analogWrite ( MotorIN2,  motorspeed ); | ||||||
|  |     } | ||||||
|  |     if(ms < 0){ | ||||||
|  |  	  digitalWriteFast ( MotorIN1 ,HIGH ); | ||||||
|  | 	  analogWrite ( MotorIN2,  255-motorspeed ); | ||||||
|  |       ms = -1 * ms; | ||||||
|  |     } | ||||||
|  |   }   | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void doEncoderMotor0(){ | ||||||
|  |   if (((PIND&B0000100)>>2) == HIGH) {   // found a low-to-high on channel A; if(digitalRead(encoderPinA)==HIGH){.... read PD2 (I2)
 | ||||||
|  |    | ||||||
|  |     if ((PINB&B0000001) == LOW) {  // check channel B to see which way; if(digitalRead(encoderPinB)==LOW){.... read PB0 (I8)
 | ||||||
|  |                                              // encoder is turning
 | ||||||
|  |       encoder0Pos-- ;         // CCW
 | ||||||
|  |     }  | ||||||
|  |     else { | ||||||
|  |       encoder0Pos++ ;         // CW
 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   else                                        // found a high-to-low on channel A
 | ||||||
|  |   {  | ||||||
|  |     if ((PINB&B0000001) == LOW) {   // check channel B to see which way; if(digitalRead(encoderPinB)==LOW){.... read PB0 (I8)
 | ||||||
|  |                                               // encoder is turning  
 | ||||||
|  |       encoder0Pos++ ;          // CW
 | ||||||
|  |     }  | ||||||
|  |     else { | ||||||
|  |       encoder0Pos-- ;          // CCW
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  |   | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void countStep(){ | ||||||
|  |   dir = (PINC&B0000001);  // dir=digitalRead(dir_pin) read PC0, 14 digital; 
 | ||||||
|  |                                   //here will be (PINB&B0000001) to not use shift in the stable version
 | ||||||
|  |             if (dir) target1++; | ||||||
|  |             else target1--; | ||||||
|  | } | ||||||
					Loading…
					
					
				
		Reference in new issue