Update to Code
Spent the morning checking the code to determine why the X axis motor controller smoked. I don't know! The code seems to be doing what it should.
The code now scans a circles. The circle is pretty rough:
Set the driver to 1/8 micro-steps:
It has taken me a while to determine that what I am seeing is overshoot:
The overshoot is in the order of half a full step. Unfortunately there is not much I can do about it.
Here is the current code:
/*
Simple 3 Axis Motion Controller
===============================
Written by Alan Cooper (agp.cooper@gmail.com)
This work is licensed under the Creative Commons Attribution-NonCommercial 2.5 License.
This means you are free to copy and share the code (but not to sell it).
*/
#include <math.h> // For PI, radians(), sin() and cos()
// Motor controller (CNC board) pin mapping:
#define DirX 2
#define DirY 3
#define DirZ 4
#define StepX 5
#define StepY 6
#define StepZ 7
#define Enable 8 // Active low
#define Laser 12 // Turn laser on or off
// Motor Controller direction settings
bool xReverse=false;
bool yReverse=true;
bool zReverse=false;
// Movement control parameters
long stepCountDown; // Movement steps remaining
unsigned long movementRate; // Steps per second
unsigned long movementInterval; // Step period (uS)
unsigned long movementRampIncr; // Step period (uS)
long xNew,yNew,zNew; // New co-ordinates
long xCurrent,yCurrent,zCurrent; // Current co-ordinates
void motionControl(void)
{
static unsigned long movementPreviousMicros=0;
static unsigned long movementCurrentMicros=0;
static unsigned long movementRamp;
static long stepCountUp=0;
static long stepX,stepY,stepZ;
static long dx,dy,dz,ax,ay,az,sx,sy,sz,mx,my,mz;
// Process motion command at end of current movement
if (stepCountDown==-1) {
stepCountDown=0;
stepCountUp=0;
// Determine movement parameters
dx=xNew-xCurrent;
dy=yNew-yCurrent;
dz=zNew-zCurrent;
ax=abs(dx);
ay=abs(dy);
az=abs(dz);
sx=xNew<xCurrent?-1:xNew>xCurrent?1:0;
sy=yNew<yCurrent?-1:yNew>yCurrent?1:0;
sz=zNew<zCurrent?-1:zNew>zCurrent?1:0;
if ((ax>=ay)&&(ax>=az)) {
mx=0;
my=ay-(ax>>1);
mz=az-(ax>>1);
stepCountDown=ax;
} else if ((ay>=ax)&&(ay>=az)) {
mx=ax-(ay>>1);
my=0;
mz=az-(ay>>1);
stepCountDown=ay;
} else {
mx=ax-(az>>1);
my=ay-(az>>1);
mz=0;
stepCountDown=az;
}
// Set counters
if (stepCountDown>0) {
stepCountUp=1;
} else {
stepCountDown=-1;
stepCountUp=-1;
}
// Set the stepper directions
if (xReverse) {
digitalWrite(DirX,(1-sx)>>1);
} else {
digitalWrite(DirX,(sx+1)>>1);
}
if (yReverse) {
digitalWrite(DirY,(1-sy)>>1);
} else {
digitalWrite(DirY,(sy+1)>>1);
}
if (zReverse) {
digitalWrite(DirZ,(1-sz)>>1);
} else {
digitalWrite(DirZ,(sz+1)>>1);
}
}
// Advance Steppers
if (stepCountDown>0) {
movementRamp=movementInterval;
if ((stepCountUp==1)||(stepCountDown==1)) movementRamp+=movementRampIncr;
movementCurrentMicros=micros();
if (movementCurrentMicros-movementPreviousMicros>movementRamp) {
movementPreviousMicros=movementCurrentMicros;
// Advance steppers
stepX=0;
stepY=0;
stepZ=0;
if ((ax>=ay)&&(ax>=az)) {
if (my>=0) {
my-=ax;
stepY=sy;
}
if (mz>=0) {
mz-=ax;
stepZ=sz;
}
my+=ay;
mz+=az;
stepX=sx;
} else if ((ay>=ax)&&(ay>=az)) {
if (mx>=0) {
mx-=ay;
stepX=sx;
}
if (mz>=0) {
mz-=ay;
stepZ=sz;
}
mx+=ax;
mz+=az;
stepY=sy;
} else {
if (mx>=0) {
mx-=az;
stepX=sx;
}
if (my>=0) {
my-=az;
stepY=sy;
}
mx+=ax;
my+=ay;
stepZ=sz;
}
xCurrent+=stepX;
yCurrent+=stepY;
zCurrent+=stepZ;
// Step pulse (high for at least 10 us)
digitalWrite(StepX,abs(stepX));
digitalWrite(StepY,abs(stepY));
digitalWrite(StepZ,abs(stepZ));
delayMicroseconds(10);
digitalWrite(StepX,LOW);
digitalWrite(StepY,LOW);
digitalWrite(StepZ,LOW);
stepCountDown--;
stepCountUp++;
// Flag end of movement
if (stepCountDown==0) {
stepCountDown=-1;
stepCountUp=-1;
}
}
} else {
movementPreviousMicros=micros(); // Reset movement rate clock to ensure near full cycle on start
}
}
int iSin[360];
int iCos[360];
void setup()
{
// Initialise Motor Controller
// Note: The motor controller is using 1/16 micro-stepping
pinMode(DirX,OUTPUT);
pinMode(StepX,OUTPUT);
pinMode(DirY,OUTPUT);
pinMode(StepY,OUTPUT);
pinMode(DirZ,OUTPUT);
pinMode(StepZ,OUTPUT);
pinMode(Enable,OUTPUT);
pinMode(Laser,OUTPUT);
digitalWrite(DirX,LOW);
digitalWrite(StepX,LOW);
digitalWrite(DirY,LOW);
digitalWrite(StepY,LOW);
digitalWrite(DirZ,LOW);
digitalWrite(StepZ,LOW);
digitalWrite(Enable,LOW); // Active low
digitalWrite(Laser,LOW); // Active high
// Set Global Variables
xNew=0;
yNew=0;
zNew=0;
xCurrent=0;
yCurrent=0;
zCurrent=0;
stepCountDown=-1; // Number of steps remaining in motion
movementRate=2000; // Step per second
movementInterval=1000000/movementRate; // Micro-seconds
movementRampIncr=500; // Micro-seconds
// LED
pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,LOW);
// Prepare circle array
for (int i=0;i<360;i++) {
iSin[i]=(int)(200*sin(radians(i)));
iCos[i]=(int)(200*cos(radians(i)));
}
}
void loop()
{
// LED timer
static unsigned long intervalMillisLED=0;
static unsigned long currentMillisLED=0;
static unsigned long previousMillisLED=0;
// Use LED to indicate working
if (stepCountDown==0) {
intervalMillisLED=1000;
} else {
intervalMillisLED=100;
}
currentMillisLED=millis();
if (currentMillisLED-previousMillisLED>intervalMillisLED) {
previousMillisLED=currentMillisLED;
digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
}
/* Motion Command */
static int angle=-1;
// Make a circle
if (stepCountDown==-1) {
if (angle==-1) {
digitalWrite(Laser,LOW);
angle=0;
xNew=iCos[angle];
yNew=iSin[angle];
zNew=0;
} else {
digitalWrite(Laser,HIGH);
angle+=15;
if (angle>=360) angle=0;
xNew=iCos[angle];
yNew=iSin[angle];
zNew=0;
}
}
// Process Motion Command
motionControl();
}
Well that just about wraps it up.
AlanX
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
A trapazoidal velocity profile will help too.
Are you sure? yes | no
You are correct with regard to the problem which is oscillation like a spring but more mass will slow the frequency but not the magnitude.
The answer is to dampen (again you are correct) the oscillation by adding friction, say a "spring loaded disk to disk brake" between the stepper and the mounting hub.
So it is a mechanical issue. Having said that a position sensor and PID will work also.
I have the same problem with my direct drive SCARA, but in this case I can solve the problem by using belt drive gearing. The belt and gearing adds some friction to the system.
This project gives an example of a PID solution:
https://hackaday.io/project/164193-as5600-stepper-motor-encoder
AlanX
Are you sure? yes | no
I know I'm like 1.5 years late here, but how about just adding more mass to dampen your overshoot?
Are you sure? yes | no