Difference between revisions of "PIC Servo Controller"
From Mech
Jump to navigationJump to searchm (→Circuit) |
|||
| Line 1: | Line 1: | ||
==Code== |
|||
<pre> |
|||
#include <18f4520.h> |
|||
#device ADC=10 // set ADC to 10 bit accuracy |
|||
#fuses HS,NOLVP,NOWDT,NOPROTECT |
|||
#use delay(clock=40000000) |
|||
#use rs232(baud=19200, UART1) // hardware uart much better; uses RC6/TX and RC7/RX |
|||
#define PanTorqueMax 650 // 650 corresponds to 100% duty cycle for driving the motor full on in one dirction |
|||
#define PanTorqueMin -650 // -650 corresponds to 0% duty cylce for driving the motor full on in the other direction |
|||
#define pGain 0 // This is the Proportional coefficient, adjust this first |
|||
#define iGain 0 // This is the Integral coefficient, adjust this second |
|||
#define dGain 0 // This is the Derivative coefficient, adjust this last |
|||
signed int32 rise,fall,pulse_width; |
|||
int32 msecs=0; |
|||
signed int32 PanTarget = 0; |
|||
signed int32 PanActual = 0; |
|||
signed int32 PanError, PanErrorLastTime=0, PanIntegral, PanDerivative, PanTorque=0; |
|||
int16 value; |
|||
int i=0; |
|||
#int_ccp1 // This is the CCP capture interrupt, this allows you to use one pin (CCP1) to capture both |
|||
// the rising edge and falling edge of the servo PWM signal, which leaves the other CCP pin |
|||
// open for drving the servo motor |
|||
void isr() |
|||
{ |
|||
if (i==0) {output_high(PIN_A1); |
|||
rise = CCP_1; |
|||
setup_ccp1(CCP_CAPTURE_FE); |
|||
i=1;} |
|||
else if (i==1) {output_low(PIN_A1); |
|||
fall = CCP_1; |
|||
pulse_width = fall - rise; |
|||
setup_ccp1(CCP_CAPTURE_RE); |
|||
i=0;} |
|||
} |
|||
#INT_TIMER2 // designates that this is the routine to call when timer2 overflows |
|||
void Timer2isr() { |
|||
msecs++; // keep track of time |
|||
if ((msecs & 7) == 0) { // servo routine every 8ms is plenty. 125x/sec |
|||
output_high(PIN_B0); |
|||
PanTarget=pulse_width; |
|||
PanActual=read_adc(); |
|||
PanActual=25*PanActual; |
|||
PanError = PanTarget - PanActual; // position error |
|||
PanIntegral += PanError; |
|||
PanDerivative = PanError - PanErrorLastTime; |
|||
PanErrorLastTime = PanError; |
|||
PanTorque = pGain * PanError + iGain * PanIntegral + dGain * PanDerivative; |
|||
TorqueShifted=PanTorque>>16; |
|||
if (PanTorque < PanTorqueMin) PanTorque = PanTorqueMin; |
|||
if (PanTorque > PanTorqueMax) PanTorque = PanTorqueMax; |
|||
if (PanActual<PanTarget){ |
|||
output_low(PIN_C0); |
|||
set_pwm2_duty(PanTorque); |
|||
} |
|||
else if (PanActual>PanTarget){ |
|||
output_high(PIN_C0); |
|||
set_pwm2_duty(650 + PanTorque); |
|||
} |
|||
output_low(PIN_B0); |
|||
} |
|||
} |
|||
void main() { |
|||
setup_timer_2(T2_DIV_BY_4, 156, 16); // clock at 16KHz, interrupt every 4*25nS * 4 * 156 * 16 = 1.0mS |
|||
setup_timer_1(T1_INTERNAL); //start timer 1 |
|||
setup_adc_ports(AN0); // Enable analog inputs; This will read the ADC on pin AN0 |
|||
setup_adc(ADC_CLOCK_INTERNAL); |
|||
setup_ccp2(CCP_PWM); // PWM output on CCP1/RC2, pin 17 |
|||
setup_ccp1(CCP_CAPTURE_RE); |
|||
enable_interrupts(INT_CCP1); |
|||
enable_interrupts(INT_TIMER2); |
|||
enable_interrupts(GLOBAL); |
|||
//set_pwm2_duty(value); // h-bridge for pan motor from CCP2 (pin 16, RC1) to C0 (pin 16) |
|||
//output_high(PIN_C3); |
|||
while (TRUE) { |
|||
//This is useful for debugging using the RS-232 serial communication |
|||
printf("pulse width: %Lu Target: %Ld Actual: %Ld Torque: %Ld \r\n", pulse_width,PanTarget,PanActual,PanTorque); |
|||
} |
|||
} |
|||
</pre> |
|||
==Circuit== |
==Circuit== |
||
Revision as of 23:47, 19 March 2009
Code
#include <18f4520.h>
#device ADC=10 // set ADC to 10 bit accuracy
#fuses HS,NOLVP,NOWDT,NOPROTECT
#use delay(clock=40000000)
#use rs232(baud=19200, UART1) // hardware uart much better; uses RC6/TX and RC7/RX
#define PanTorqueMax 650 // 650 corresponds to 100% duty cycle for driving the motor full on in one dirction
#define PanTorqueMin -650 // -650 corresponds to 0% duty cylce for driving the motor full on in the other direction
#define pGain 0 // This is the Proportional coefficient, adjust this first
#define iGain 0 // This is the Integral coefficient, adjust this second
#define dGain 0 // This is the Derivative coefficient, adjust this last
signed int32 rise,fall,pulse_width;
int32 msecs=0;
signed int32 PanTarget = 0;
signed int32 PanActual = 0;
signed int32 PanError, PanErrorLastTime=0, PanIntegral, PanDerivative, PanTorque=0;
int16 value;
int i=0;
#int_ccp1 // This is the CCP capture interrupt, this allows you to use one pin (CCP1) to capture both
// the rising edge and falling edge of the servo PWM signal, which leaves the other CCP pin
// open for drving the servo motor
void isr()
{
if (i==0) {output_high(PIN_A1);
rise = CCP_1;
setup_ccp1(CCP_CAPTURE_FE);
i=1;}
else if (i==1) {output_low(PIN_A1);
fall = CCP_1;
pulse_width = fall - rise;
setup_ccp1(CCP_CAPTURE_RE);
i=0;}
}
#INT_TIMER2 // designates that this is the routine to call when timer2 overflows
void Timer2isr() {
msecs++; // keep track of time
if ((msecs & 7) == 0) { // servo routine every 8ms is plenty. 125x/sec
output_high(PIN_B0);
PanTarget=pulse_width;
PanActual=read_adc();
PanActual=25*PanActual;
PanError = PanTarget - PanActual; // position error
PanIntegral += PanError;
PanDerivative = PanError - PanErrorLastTime;
PanErrorLastTime = PanError;
PanTorque = pGain * PanError + iGain * PanIntegral + dGain * PanDerivative;
TorqueShifted=PanTorque>>16;
if (PanTorque < PanTorqueMin) PanTorque = PanTorqueMin;
if (PanTorque > PanTorqueMax) PanTorque = PanTorqueMax;
if (PanActual<PanTarget){
output_low(PIN_C0);
set_pwm2_duty(PanTorque);
}
else if (PanActual>PanTarget){
output_high(PIN_C0);
set_pwm2_duty(650 + PanTorque);
}
output_low(PIN_B0);
}
}
void main() {
setup_timer_2(T2_DIV_BY_4, 156, 16); // clock at 16KHz, interrupt every 4*25nS * 4 * 156 * 16 = 1.0mS
setup_timer_1(T1_INTERNAL); //start timer 1
setup_adc_ports(AN0); // Enable analog inputs; This will read the ADC on pin AN0
setup_adc(ADC_CLOCK_INTERNAL);
setup_ccp2(CCP_PWM); // PWM output on CCP1/RC2, pin 17
setup_ccp1(CCP_CAPTURE_RE);
enable_interrupts(INT_CCP1);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
//set_pwm2_duty(value); // h-bridge for pan motor from CCP2 (pin 16, RC1) to C0 (pin 16)
//output_high(PIN_C3);
while (TRUE) {
//This is useful for debugging using the RS-232 serial communication
printf("pulse width: %Lu Target: %Ld Actual: %Ld Torque: %Ld \r\n", pulse_width,PanTarget,PanActual,PanTorque);
}
}