### Monday, August 21, 2006

## DC Motor Programming Madness

I have here a pseudo-PIC program for driving a DC motor using PWM and an encoder. This non-working example might serve as a base for an all-out DC driver. This example has overshoot prediction and dynamic speed-adjustment for correcting tiny errors. I Apologize for this disjointed posting.. can never seem to post programming related material without it becoming a bit chaotic.

Example Computer output to Comms/PIC:

Each line here represents a 'job' in this program

X+200,Y+50, 100

X+100,Y+50, 100

X+10,Y-10, 100

X-20,Y+50, 100

(X movement, Y movement, Speed (in pulses per second)

All this data is in Pulses. Software translates positional data to # of pulses needed. On DC motors each pulse represents an encoder slit.

RepRap Variables in this example, mostly generated from original vector coords=

JobX=200 ' how far to move on X

JobY=50 'how far to move on Y

TotalTime=200 'Total pulses needed for the job. (Always equals largest absolute value of jobX or jobY)

Time=0 'current pulse # in job

dX=0 ' desired pulse position in job

dY=0 ' desired pulse position in job

X=0 ' actual position (in pulses)

Y=0 ' actual position (in pulses)

(Keep these in buffer so it knows what is up next. So it can prepare speed changes beforehand:)

NextJobX

NextJobY

NextJobTotalTime

NextSpeed

RepRap Pseudo-IO in this example:

XmotorPWM, sends a 0-100% duty cycle for motor X

YmotorPWM, sends a 0-100% duty cycle for motor Y

Example Settings for the equations below:

Speed=100pps (speed in desired pulses per second)

MaxSpeedX=200pps (speed of motor at 100%PWM)

MaxSpeedY=200pps (speed of motor at 100%PWM)

Overshoot=9 (average overshoot in # of pulses at 100%PWM)

Correction=20 (1-100, represents rate of per-cycle motor speed corrections.)

Every Predicted Pulse (On PIC would be every (1/Speed) seconds. In example it is every 1/100th second)

Time=Time+1

dX=JobX * (Time/Totaltime)

dY=JobY * (Time/Totaltime)

XmotorPWM=(Speed*(JobX/Totaltime) /MaxSpeedX). Will return 0-100% for PWM speed. Needs to be modified in case it falls behind/ahead.

XmotorPWM=(Speed*(JobX/Totaltime) /MaxSpeedX)+ ( (dX-X)/100 * Correction ) Correction=10 will modify the motor by 1% per pulse

Now, to account for next-job-speed-prediction, you need to modify it further when it nears the end of it's job:

if Time >= Totaltime - ( Overshoot * (Speed/MaxSpeedX) ) then

XmotorPWM=(NextSpeed*(NextJobX/NextTotaltime) /MaxSpeedX

end if

Calibration needed to make it work:

MaxSpeedX,Y (total pulses measured after 1sec full-speed movement)

OvershootX,Y (overshoot measured in pulses, from going 100% to 0%

Correction (value from 0-255, sets the ferocity in which motor speeds are adjusted to keep it within its desired position. 10=1% correction, 100=10%, etc)

Programming note: The extra variables in memory like dX and dY can be trimmed out and replaced with more equations, I just used them to make it look nicer.

Other Programming note: Murphy's law dictates there is at least one malformed equation in a pseudoprogram this long.

Final:

I hope some of this makes sense. Again, I mostly wanted to show that it was possible to have PWM control with dynamic adjustment of speed to keep in-line with pulses just as a stepper motor would. That, and being able to change speed a few cycles early, using the difference in speeds and a set ratio to determine how early to change.

Have fun.

-Rei

Example Computer output to Comms/PIC:

Each line here represents a 'job' in this program

X+200,Y+50, 100

X+100,Y+50, 100

X+10,Y-10, 100

X-20,Y+50, 100

(X movement, Y movement, Speed (in pulses per second)

All this data is in Pulses. Software translates positional data to # of pulses needed. On DC motors each pulse represents an encoder slit.

RepRap Variables in this example, mostly generated from original vector coords=

JobX=200 ' how far to move on X

JobY=50 'how far to move on Y

TotalTime=200 'Total pulses needed for the job. (Always equals largest absolute value of jobX or jobY)

Time=0 'current pulse # in job

dX=0 ' desired pulse position in job

dY=0 ' desired pulse position in job

X=0 ' actual position (in pulses)

Y=0 ' actual position (in pulses)

(Keep these in buffer so it knows what is up next. So it can prepare speed changes beforehand:)

NextJobX

NextJobY

NextJobTotalTime

NextSpeed

RepRap Pseudo-IO in this example:

XmotorPWM, sends a 0-100% duty cycle for motor X

YmotorPWM, sends a 0-100% duty cycle for motor Y

Example Settings for the equations below:

Speed=100pps (speed in desired pulses per second)

MaxSpeedX=200pps (speed of motor at 100%PWM)

MaxSpeedY=200pps (speed of motor at 100%PWM)

Overshoot=9 (average overshoot in # of pulses at 100%PWM)

Correction=20 (1-100, represents rate of per-cycle motor speed corrections.)

Every Predicted Pulse (On PIC would be every (1/Speed) seconds. In example it is every 1/100th second)

Time=Time+1

dX=JobX * (Time/Totaltime)

dY=JobY * (Time/Totaltime)

XmotorPWM=(Speed*(JobX/Totaltime) /MaxSpeedX). Will return 0-100% for PWM speed. Needs to be modified in case it falls behind/ahead.

XmotorPWM=(Speed*(JobX/Totaltime) /MaxSpeedX)+ ( (dX-X)/100 * Correction ) Correction=10 will modify the motor by 1% per pulse

Now, to account for next-job-speed-prediction, you need to modify it further when it nears the end of it's job:

if Time >= Totaltime - ( Overshoot * (Speed/MaxSpeedX) ) then

XmotorPWM=(NextSpeed*(NextJobX/NextTotaltime) /MaxSpeedX

end if

Calibration needed to make it work:

MaxSpeedX,Y (total pulses measured after 1sec full-speed movement)

OvershootX,Y (overshoot measured in pulses, from going 100% to 0%

Correction (value from 0-255, sets the ferocity in which motor speeds are adjusted to keep it within its desired position. 10=1% correction, 100=10%, etc)

Programming note: The extra variables in memory like dX and dY can be trimmed out and replaced with more equations, I just used them to make it look nicer.

Other Programming note: Murphy's law dictates there is at least one malformed equation in a pseudoprogram this long.

Final:

I hope some of this makes sense. Again, I mostly wanted to show that it was possible to have PWM control with dynamic adjustment of speed to keep in-line with pulses just as a stepper motor would. That, and being able to change speed a few cycles early, using the difference in speeds and a set ratio to determine how early to change.

Have fun.

-Rei

Comments:

Links to this post:

<< Home

Biggest problem you'll have in pic code is multiplication and division. This is difficult to do in limited memory and instruction space (And very inefficient, to boot -- division of 16 bit integers will probably need to execute on the order of 200+ total instructions to perform the calculation.)

I remember digging into 6502 assembly and figuring out how they did the floating point operations years and years ago (I was just a kid at the time). Pretty amazing work. It seems you see less of that kind of engineering, and more dependance on faster hardware and more memory these days.

Post a Comment
I remember digging into 6502 assembly and figuring out how they did the floating point operations years and years ago (I was just a kid at the time). Pretty amazing work. It seems you see less of that kind of engineering, and more dependance on faster hardware and more memory these days.

Links to this post:

<< Home