# PICMicrocontroller based Computer Numerical Control

## 3D Line to Stepper Axis Pulses in a PIC16F

This code converts a line in 3 dimensions into the pulse and direction signals necessary to make a 3 axis stepper motor driven CNC machine follow that line while maintaining predefined maximum acceleration and maximum velocity parameters.

```/*
3D Line to Stepper Axis Pulses

Purpose: Convert a line in 3 dimensions into the pulse and direction signals necessary to make a 3
axis stepper motor driven CNC machine follow that line while maintaining predefined maximum
acceleration and maximum velocity parameters.

Limitations: Must fit in a small microcontroller. e.g. PIC 16F690 with 4K of code space and 256
bytes of RAM.

DONE:
- steps and directions on port pins... Motors turning!
- figure out how to adapt Bresenham to 3d... Appears to work
- code up some velocity and acceleration control.. Could be done
- figure out why mv and ma are not being returned to their original values. Is sd not being
calculated correctly? yeah, sd needed to just be incremented and lots of other tweaks...
TODO:
- acceleration ramping is NOT correct. Must incorporate the fact that a given change in the delay
between steps has more effect when the delay is small, as compared to when it is large.
E.g. motor spinning at 500uS between pulses, is reduced by 250uS, that doubles the motor speed.
But when /increased/ by 250uS, that does NOT halve the motor speed. Formula may be:
starting velocity * (1/sqrt(x))
where x is the step... or the time interval... not clear yet.
- simulate, debug, test, etc... with xaxis=bigaxis
- looks like sd is always just half of i?
- change each axis variables into a structure so they can easily passed as parameters
- handle y and z being the big axis
- decide how the starting and goal positions are going to get set. Minimal G code interpreter?
- decide how the max velocity and acceleration settings are getting set. G code?
- clean up order of declarations, subroutines, move things into include files and all that other
crap C programmers are expected to do for some strange reason.

http://forums.reprap.org/read.php?12,9459 Arduino G code to stepper. See user.cpp file.

Compiler notes: Using >>1 throughout in place of /2 because some compilers are seriously too stupid
to optimize a divide by two in to a right shift.
*/

// OPTIONS
#define DEBUG
/* When defined, printf's the step,stopping distance, x,y,z and velocity and acceleration
to the console */
#define ACCELERATION
/* When defined, the code will attempt to accelerate from STARTING_VELOCITY to MAXIMUM_VELOCITY*/
#define RAMP_ACCELERATION
/* When defined, the code attempt to smooth the change in acceleration and so the G-Force
experienced by the load being moved through the lines path will build and fall over some time.
When not defined, the acceleration is a fixed value so the G-Force at the load will jump from
0 to a fixed value as soon as
motion begins. */
#define STARTING_VELOCITY	800
//mS between steps
#define MAXIMUM_VELOCITY	20
//ms between steps
#define	MAXIMUM_ACCELERATION	20
//maximum acceleration as change in uSecond delay time between steps.
#define	MAXIMUM_DELTA_ACCELERATION	10
//maximum change in acceleration. Must be less than MAXIMUM_ACCELERATION

#include <stdlib.h>
#ifdef DEBUG
#include <stdio.h>
#endif

#define STEPX	RA1
#define STEPY	RA2
#define STEPZ	RA4
#define STEPA	RA4
#define DIR 	RA5

typedef enum {cw=0,ccw=1} tdirection;	// so clock wise is false
typedef enum {xaxis=1,yaxis=2,zaxis=4,aaxis=8} taxis;

#define tcoordinate int
/* tcoordinate must be a type which can hold the range of positions through which the system
will travel when expressed as individual steps. */

//Current position.
// Must be maintained from one movement to the next. step() does this job
static tcoordinate	xp;	//current position in the X axis.
static tcoordinate	yp;	//current position in the Y axis.
static tcoordinate	zp;	//current position in the Z axis.

//current direction for each axis, assume forward(true)
tdirection 		xd=cw;	//X direction
tdirection		yd=cw;	//Y direction
tdirection		zd=cw;	//Z direction

void step(taxis anaxis, tdirection adir, tcoordinate *apos) {
//	DIR = 0;
STEPX = STEPY = STEPZ = STEPA = 0;
__delay_ms(8); //otherwise you can't see the pulse.
(*apos)++;
}
else {
(*apos)--;
}
*/	(cw == adir) ? ((*apos)++) : ((*apos)--);
if (anaxis & aaxis) {STEPA = 1;}
if (anaxis & zaxis) {STEPZ = 1;}
if (anaxis & yaxis) {STEPY = 1;}
if (anaxis & xaxis) {STEPX = 1;}
__delay_ms(8); //otherwise you can't see the pulse.
STEPX = 0;	//X LED is 2 GND, so turn it back off now
}

//goal position
tcoordinate	xg;	//X axis goal position
tcoordinate	yg;	//Y axis goal position
tcoordinate	zg;	//Z axis goal position

/* Limits. We are assuming that all axis have the same max values, which is unlikely, but
simplifies the code, and can be functional, as long as we limit all axis to the weakest
axis. */
#define		sv	STARTING_VELOCITY
//starting velocity as uSecond delay time between steps.

short		mv = MAXIMUM_VELOCITY;
//maximum velocity as uSecond delay time between steps.

#ifdef RAMP_ACCELERATION
short		ma = MAXIMUM_DELTA_ACCELERATION;
//maximum acceleration
#define 		mda	MAXIMUM_DELTA_ACCELERATION
//maximum change in acceleration
#else
#define		ma	MAXIMUM_ACCELERATION
//maximum acceleration as change in uSecond delay time between steps.
#endif

//velocity of each axis, expressed in timer ticks between steps.
unsigned short		xv=sv;	//velocity of the X axis
unsigned short 		yv=sv;	//velocity of the Y axis
unsigned short 		zv=sv;	//velocity of the Z axis

void posgoal2stepdir(tcoordinate *p, tcoordinate *g, tcoordinate *s, tdirection *d) {
/*translate our current position, and the goal position, into the number of steps required to
reach that goal and the direction to travel. */
signed tcoordinate i;
i = *g - *p ;		//how far do we have to move?
*d = cw;
if (i<0) {		//is the goal less than the current position?
*d = ccw;	//set the direction to reverse(false)
i = (i>0?i:-i);	//change to a count
};
*s = (tcoordinate)i;	//convert to a distance in the coordinate plain.
}

void main() {
/* stopping distance. This keeps track of how long we expect to take to get stopped once we get
going. */
tcoordinate	sd = 0;	//stopping distance

//number of steps required
tcoordinate	xs;	//X axis
tcoordinate	ys;	//Y axis
tcoordinate	zs;	//Z axis
init();

//some test values
//	xg=10;yg=5;zg=2;
//	xp=20;xg=10;yg=5;zg=2;	//
xp=20;xg=100;yp=5;yg=50;zg=2;	//

//figure out distance and direction for each axis
posgoal2stepdir(&xp,&xg,&xs,&xd);
posgoal2stepdir(&yp,&yg,&ys,&yd);
posgoal2stepdir(&zp,&zg,&zs,&zd);

//find which axis has the largest move
taxis bigstep = xaxis;
if (ys>xs) bigstep = yaxis;
if (xs>xs) bigstep = zaxis;
/* Now we know which axis needs to travel the farthest. So that one should be
the one we step most often. The other two axis get stepped when the error in
their position exceeds one step as per the Bresenham algorithm.
http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
The other axis can not possibly exceed the velocity and acceleration of the
“big” axis and should be a scaled version of that maximum.
*/

if (xaxis == bigstep) {
//Bresenham error
signed tcoordinate	ye;	//Y axis
signed tcoordinate	ze;	//Z axis
ye = ze = (xs >> 1); //error for each smaller distance starts as half the largest distance
#ifdef DEBUG
puts("step:stop\tx\ty\tz\tvel\tacc\r");
#endif
for ( tcoordinate i = xs; i > 0; i--) {	//i counts down steps to the end of this movement
step(xaxis, xd, &xp);	// we always move the big axis and step does dir and pos
//pretty much pure Bresenham here except step() manages direction so we don’t have to.
ye -= ys;
ze -= zs;
if (ye < 0) {
step(yaxis, yd, &yp);
ye += xs;
};
if (ze < 0) {
step(zaxis, zd, &zp);
ze += xs;
};
#ifdef ACCELERATION
//figure out how long to wait for the next step by considering position, velocity, and acceleration
if ( i > sd ) {	//unless we are nearing the end...
if ( xv > mv ) { // unless we are at max velocity
// Note: _greater_ because smaller values mean less delay and so faster
xv -= ma; // reduce delay to increase speed by max acceleration.
#ifdef RAMP_ACCELERATION
if (xv >= (mv+((sv-mv)>>1))) { // greater because smaller is faster
ma += mda;	//increase acceleration,
}		// we are not yet half way to max velocity
else {		// xv is now less than twice mv
ma -= mda;	//decrease acceleration,
}		// we are reaching max velocity
#endif
sd++;	 // more speed means more distance needed to stop
}
}
else {	//we are nearing the end
xv += ma;	// increase delay to reduce speed by max (de)acceleration.
#ifdef RAMP_ACCELERATION
if (xv <= (sv-((sv-mv)>>1))) { // less because smaller is faster
ma += mda;	//decrease deceleration,
}		// we are coming to a halt.
else {		// xv is now less than twice mv
ma -= mda;	//increase deceleration,
}		// we are still nearer max velocity
#endif
} // end if ( i > sd )
#endif //ACCELERATION

#ifdef DEBUG
printf("%04d:%04d\t%d\t%d\t%d\t%d\t%d\r",i,sd,xp,yp,zp,xv,ma);
#endif
delay(xv);	//pause to give the motors time to get to the new step
}	// end for
} 	// end if (xaxis=bigaxis)

//And all that again for the case of Y being the bigaxis or Z...

if (yaxis == bigstep) {  };
//...
if (zaxis == bigstep) {  };
//...
//Or we could make a subroutine...

}

```

 file: /Techref/microchip/CNC16F-jn.htm, 10KB, , updated: 2016/2/15 23:17, local time: 2021/12/3 05:44, TOP NEW HELP FIND:  34.207.247.69:LOG IN

 ©2021 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?Please DO link to this page! Digg it! / MAKE! PIC Microcontroller 16F based Computer Numerical Control

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.

Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
 Did you find what you needed? "No. I'm looking for: " "No. Take me to the search page." "No. Take me to the top so I can drill down by catagory" "No. I'm willing to pay for help, please refer me to a qualified consultant" "No. But I'm interested. me at when this page is expanded."

 PICList 2021 contributors: o List host: MIT, Site host massmind.org, Top posters @20211203 Neil, Harold Hallikainen, Alan Pearce, RussellMc, Bob Blick, Allen Mulvey, Justin Richards, Dwayne Reid, madscientistatlarge, Sean Breheny, * Page Editors: James Newton, David Cary, and YOU! * Roman Black of Black Robotics donates from sales of Linistep stepper controller kits. * Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters. * Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated! * Contributors: Richard Seriani, Sr.

.