Fixed a number of bugs caused by using abs() on floats and long ints. Added support for selectively inverting bits of the stepping port. Debugged, optimized and cleaned up timing code for the step-pulses.

This commit is contained in:
Simen Svale Skogsrud 2010-02-27 19:55:09 +01:00
parent 6ac3b3f2e6
commit a42c03601d
14 changed files with 4430 additions and 106 deletions

View File

@ -35,7 +35,7 @@ FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
# Tune the lines below only if you know what you are doing:
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) -B 10
AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) -B 10 -F
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I.
# symbolic targets:

View File

@ -23,11 +23,13 @@
#define VERSION "0.0"
#define X_STEPS_PER_MM 128.0
#define Y_STEPS_PER_MM 128.0
#define Z_STEPS_PER_MM 128.0
#define X_STEPS_PER_MM 94.488188976378
#define Y_STEPS_PER_MM 94.488188976378
#define Z_STEPS_PER_MM 94.488188976378
#define INCHES_PER_MM 25.4
#define STEP_PULSE_MICROSECONDS 30
#define INCHES_PER_MM (1.0/25.4)
#define X_STEPS_PER_INCH X_STEPS_PER_MM*INCHES_PER_MM
#define Y_STEPS_PER_INCH Y_STEPS_PER_MM*INCHES_PER_MM
#define Z_STEPS_PER_INCH Z_STEPS_PER_MM*INCHES_PER_MM
@ -35,12 +37,12 @@
#define RAPID_FEEDRATE 960.0 // in millimeters per minute
#define DEFAULT_FEEDRATE 960.0
#define STEPPERS_ENABLE_DDR DDRB
#define STEPPERS_ENABLE_PORT PORTB
#define STEPPERS_ENABLE_BIT 6
#define STEPPERS_ENABLE_DDR DDRD
#define STEPPERS_ENABLE_PORT PORTD
#define STEPPERS_ENABLE_BIT 2
#define STEPPING_DDR DDRB
#define STEPPING_PORT PORTB
#define STEPPING_DDR DDRC
#define STEPPING_PORT PORTC
#define X_STEP_BIT 0
#define Y_STEP_BIT 1
#define Z_STEP_BIT 2
@ -48,19 +50,20 @@
#define Y_DIRECTION_BIT 4
#define Z_DIRECTION_BIT 5
#define LIMIT_DDR DDRC
#define LIMIT_PORT PORTC
#define X_LIMIT_BIT 0
#define Y_LIMIT_BIT 1
#define Z_LIMIT_BIT 2
#define SPINDLE_ENABLE_DDR DDRC
#define SPINDLE_ENABLE_PORT PORTC
#define SPINDLE_ENABLE_BIT 3
#define LIMIT_DDR DDRD
#define LIMIT_PORT PORTD
#define X_LIMIT_BIT 3
#define Y_LIMIT_BIT 4
#define Z_LIMIT_BIT 5
#define SPINDLE_DIRECTION_DDR DDRC
#define SPINDLE_DIRECTION_PORT PORTC
#define SPINDLE_DIRECTION_BIT 4
#define SPINDLE_ENABLE_DDR DDRD
#define SPINDLE_ENABLE_PORT PORTD
#define SPINDLE_ENABLE_BIT 6
#define SPINDLE_DIRECTION_DDR DDRD
#define SPINDLE_DIRECTION_PORT PORTD
#define SPINDLE_DIRECTION_BIT 7
#define BAUD_RATE 9600
@ -69,4 +72,11 @@
#define STEPPING_MASK (STEP_MASK | DIRECTION_MASK)
#define LIMIT_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT))
// Use this line for default operation (step-pulses high)
#define STEPPING_INVERT_MASK 0
// Uncomment this line for inverted stepping (step-pulses low, rest high)
// #define STEPPING_INVERT_MASK (STEP_MASK)
// Or bake your own like this adding any step-bits or directions you want to invert:
// #define STEPPING_INVERT_MASK (STEP_MASK | (1<<Z_DIRECTION_BIT))
#endif

View File

@ -118,7 +118,7 @@ void gc_init() {
}
inline float to_millimeters(double value) {
return(gc.inches_mode ? value * INCHES_PER_MM : value);
return(gc.inches_mode ? (value * INCHES_PER_MM) : value);
}

File diff suppressed because it is too large Load Diff

1674
gcode/miller.gcode Normal file

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,7 @@ double theta(double x, double y)
// Find the quadrant of the coordinate
int quadrant_of_the_circle(int32_t x, int32_t y) {
if (abs(x)<abs(y)){
if (labs(x)<labs(y)){
if (y>0) {
return(0);
} else {

4
main.c
View File

@ -33,12 +33,14 @@
int main(void)
{
beginSerial(BAUD_RATE);
st_init();
st_init(); // initialize the stepper subsystem
mc_init(); // initialize motion control subsystem
spindle_init(); // initialize spindle controller
gc_init(); // initialize gcode-parser
sp_init(); // initialize the serial protocol
st_start(); // start the stepper subsystem
for(;;){
sleep_mode();
sp_process(); // process the serial protocol

View File

@ -96,7 +96,7 @@ void mc_line(double x, double y, double z, float feed_rate, int invert_feed_rate
target[Z_AXIS] = round(z*Z_STEPS_PER_MM);
// Determine direction and travel magnitude for each axis
for(axis = X_AXIS; axis <= Z_AXIS; axis++) {
step_count[axis] = abs(target[axis] - position[axis]);
step_count[axis] = labs(target[axis] - position[axis]);
direction[axis] = signof(target[axis] - position[axis]);
}
// Find the magnitude of the axis with the longest travel
@ -138,7 +138,9 @@ void mc_line(double x, double y, double z, float feed_rate, int invert_feed_rate
}
}
}
if(step_bits) { step_steppers(step_bits); }
if(step_bits) {
step_steppers(step_bits);
}
} while (step_bits);
mode = MC_MODE_AT_REST;
}
@ -210,11 +212,11 @@ void mc_arc(double theta, double angular_travel, double radius, double linear_tr
int target_quadrant = quadrant_of_the_circle(target_x, target_y);
uint32_t arc_steps=0;
// Will this whole arc take place within the same quadrant?
if (start_quadrant == target_quadrant && (abs(angular_travel) <= (M_PI/2))) {
if (start_quadrant == target_quadrant && (fabs(angular_travel) <= (M_PI/2))) {
if(quadrant_horizontal(start_quadrant)) { // a horizontal quadrant where x will be the primary direction
arc_steps = abs(target_x-start_x);
arc_steps = labs(target_x-start_x);
} else { // a vertical quadrant where y will be the primary direction
arc_steps = abs(target_y-start_y);
arc_steps = labs(target_y-start_y);
}
} else { // the start and target points are in different quadrants
// Lets estimate the amount of steps along half a quadrant
@ -234,7 +236,7 @@ void mc_arc(double theta, double angular_travel, double radius, double linear_tr
// Set up the linear interpolation of the "depth" axis -----------------------------------------------------
int32_t linear_steps = abs(st_millimeters_to_steps(linear_travel, axis_linear));
int32_t linear_steps = labs(st_millimeters_to_steps(linear_travel, axis_linear));
int linear_direction = signof(linear_travel);
// The number of steppings needed to trace this motion is equal to the motion that require the maximum
// amount of steps: the arc or the line:
@ -247,7 +249,7 @@ void mc_arc(double theta, double angular_travel, double radius, double linear_tr
// Calculate feed rate -------------------------------------------------------------------------------------
// We then calculate the millimeters of helical travel
double millimeters_of_travel = hypot(angular_travel*radius, abs(linear_travel));
double millimeters_of_travel = hypot(angular_travel*radius, labs(linear_travel));
// Then we calculate the microseconds between each step as if we will trace the full circle.
// It doesn't matter what fraction of the circle we are actually going to trace. The pace is the same.
compute_and_set_step_pace(feed_rate, millimeters_of_travel, maximum_steps, invert_feed_rate);
@ -288,12 +290,12 @@ void mc_arc(double theta, double angular_travel, double radius, double linear_tr
direction[axis_1] = dx;
direction[axis_2] = dy;
// Check which axis will be "major" for this stepping
if (abs(x)<abs(y)) {
if (labs(x)<labs(y)) {
// X is major: Step arc horizontally
error += 1 + 2*x * dx;
x+=dx;
diagonal_error = error + 1 + 2*y*dy;
if(abs(error) >= abs(diagonal_error)) {
if(labs(error) >= labs(diagonal_error)) {
y += dy;
error = diagonal_error;
step_bits |= diagonal_bits; // step diagonal
@ -305,7 +307,7 @@ void mc_arc(double theta, double angular_travel, double radius, double linear_tr
error += 1 + 2*y * dy;
y+=dy;
diagonal_error = error + 1 + 2*x * dx;
if(abs(error) >= abs(diagonal_error)) {
if(labs(error) >= labs(diagonal_error)) {
x += dx;
error = diagonal_error;
step_bits |= diagonal_bits; // step diagonal
@ -362,16 +364,7 @@ void set_stepper_directions(int8_t *direction)
((direction[Z_AXIS]&0x80)>>(7-Z_DIRECTION_BIT)));
}
// Step enabled steppers. Enabled should be an array of three bytes. Each byte represent one
// stepper motor in the order X, Y, Z. Set the bytes of the steppers you want to step to
// 1, and the rest to 0.
inline void step_steppers(uint8_t bits)
{
st_buffer_step(direction_bits | bits);
}
// Step only one motor
inline void step_axis(uint8_t axis)
{
st_buffer_step(direction_bits | st_bit_for_stepper(axis));
}

View File

@ -1,2 +1,2 @@
socat -d -d READLINE /dev/tty.usbserial-A4001o6L,clocal=1,nonblock=1,cread=1,cs8,ixon=1,ixoff=1
socat -d -d READLINE /dev/tty.usbserial-A9007QcR,clocal=1,nonblock=1,cread=1,cs8,ixon=1,ixoff=1

View File

@ -24,18 +24,21 @@ if ARGV.empty?
exit
end
SerialPort.open('/dev/tty.usbserial-A4001o6L', 9600) do |sp|
SerialPort.open('/dev/tty.usbserial-A9007QcR', 9600) do |sp|
sp.write("\r\n\r\n");
sleep 5
ARGV.each do |file|
puts "Processing file #{file}"
prebuffer = $prebuffer ? 10 : 0
prebuffer = $prebuffer ? 7 : 0
File.readlines(file).each do |line|
next if line.strip == ''
puts line.strip
sp.write("#{line.strip}\r\n");
if prebuffer == 0
sleep 0.1
begin
result = sp.gets.strip
puts result unless result == '' or result == 'ok'
puts "Grbl >> #{result}" unless result == '' or result == 'ok'
end while result != 'ok'
else
prebuffer -= 1

View File

@ -26,9 +26,9 @@
#include <math.h>
#include "nuts_bolts.h"
#define BLOCK_BUFFER_SIZE 128
#define LINE_BUFFER_SIZE 128
char line[BLOCK_BUFFER_SIZE];
char line[LINE_BUFFER_SIZE];
uint8_t line_counter;
void prompt() {
@ -79,6 +79,9 @@ void sp_process()
{
if((c < 32)) { // Line is complete. Then execute!
line[line_counter] = 0;
// printString("->");
// printString(line);
// printString("<-\r\n");
gc_execute_line(line);
line_counter = 0;
prompt();

View File

@ -25,6 +25,7 @@
#include "stepper.h"
#include "config.h"
#include <math.h>
#include <util/delay.h>
#include "nuts_bolts.h"
#include <avr/interrupt.h>
@ -58,14 +59,13 @@ SIGNAL(SIG_OUTPUT_COMPARE1A)
config_pace_timer(next_pace);
next_pace = 0;
} else {
// Set the direction pins a nanosecond or two before you step the steppers
popped ^= STEPPING_INVERT_MASK;
// Set the direction pins a cuple of nanoseconds before we step the steppers
STEPPING_PORT = (STEPPING_PORT & ~DIRECTION_MASK) | (popped & DIRECTION_MASK);
// Then pulse the stepping pins
STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | popped;
// Reset and start timer 2 which will reset the motor port after 5 microsecond
TCNT2 = 0; // reset counter
OCR2A = 5*TICKS_PER_MICROSECOND; // set the trigger time
TIMSK2 |= (1<<OCIE2A); // enable interrupt
// Reset step pulse reset timer
TCNT2 = -(((STEP_PULSE_MICROSECONDS-4)*TICKS_PER_MICROSECOND)/8);
}
// move the step buffer tail to the next instruction
step_buffer_tail = (step_buffer_tail + 1) % STEP_BUFFER_SIZE;
@ -73,11 +73,11 @@ SIGNAL(SIG_OUTPUT_COMPARE1A)
}
// This interrupt is set up by SIG_OUTPUT_COMPARE1A when it sets the motor port bits. It resets
// the motor port after a short period (5us) completing one step cycle.
SIGNAL(SIG_OUTPUT_COMPARE2A)
// the motor port after a short period (STEP_PULSE_MICROSECONDS) completing one step cycle.
SIGNAL(SIG_OVERFLOW2)
{
STEPPING_PORT = STEPPING_PORT & ~STEP_MASK; // reset stepping pins (leave the direction pins)
TIMSK2 &= ~(1<<OCIE2A); // disable this timer interrupt until next time
// reset stepping pins (leave the direction pins)
STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | (STEPPING_INVERT_MASK & STEPPING_MASK);
}
// Initialize and start the stepper motor subsystem
@ -85,7 +85,7 @@ void st_init()
{
// Configure directions of interface pins
STEPPING_DDR |= STEPPING_MASK;
printInteger(STEPPING_DDR);
STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | STEPPING_INVERT_MASK;
LIMIT_DDR &= ~(LIMIT_MASK);
STEPPERS_ENABLE_DDR |= 1<<STEPPERS_ENABLE_BIT;
@ -101,17 +101,16 @@ void st_init()
// Configure Timer 2
TCCR2A = 0; // Normal operation
TCCR2B = 1<<CS20; // Full speed, no prescaler
TCCR2B = (1<<CS21); // Full speed, 1/8 prescaler
TIMSK2 = 0; // All interrupts disabled
sei();
// start off with a mellow pace
config_pace_timer(20000);
st_start();
}
void st_buffer_step(uint8_t motor_port_bits)
inline void st_buffer_step(uint8_t motor_port_bits)
{
// Buffer nothing unless stepping subsystem is running
if (stepper_mode != STEPPER_MODE_RUNNING) { return; }
@ -146,8 +145,10 @@ void st_flush()
// Start the stepper subsystem
void st_start()
{
// Enable timer interrupt
// Enable timer interrupts
TIMSK1 |= (1<<OCIE1A);
TIMSK2 |= (1<<TOIE2);
// set enable pin
STEPPERS_ENABLE_PORT |= 1<<STEPPERS_ENABLE_BIT;
stepper_mode = STEPPER_MODE_RUNNING;
}
@ -155,8 +156,12 @@ void st_start()
// Execute all buffered steps, then stop the stepper subsystem
inline void st_stop()
{
// flush pending operations
st_synchronize();
// disable timer interrupts
TIMSK1 &= ~(1<<OCIE1A);
TIMSK2 &= ~(1<<TOIE2);
// reset enable pin
STEPPERS_ENABLE_PORT &= ~(1<<STEPPERS_ENABLE_BIT);
stepper_mode = STEPPER_MODE_STOPPED;
}
@ -238,42 +243,6 @@ int check_limit_switch(int axis)
return((LIMIT_PORT&mask) || (LIMIT_PORT&mask));
}
// void perform_go_home()
// {
// int axis;
// if(stepper_mode.home.phase == PHASE_HOME_RETURN) {
// // We are running all axes in reverse until all limit switches are tripped
// // Check all limit switches:
// for(axis=X_AXIS; axis <= Z_AXIS; axis++) {
// stepper_mode.home.away[axis] |= check_limit_switch(axis);
// }
// // Step steppers. First retract along Z-axis. Then X and Y.
// if(stepper_mode.home.away[Z_AXIS]) {
// step_axis(Z_AXIS);
// } else {
// // Check if all axes are home
// if(!(stepper_mode.home.away[X_AXIS] || stepper_mode.home.away[Y_AXIS])) {
// // All axes are home, prepare next phase: to nudge the tool carefully out of the limit switches
// memset(stepper_mode.home.direction, 1, sizeof(stepper_mode.home.direction)); // direction = [1,1,1]
// set_direction_bits(stepper_mode.home.direction);
// stepper_mode.home.phase == PHASE_HOME_NUDGE;
// return;
// }
// step_steppers(stepper_mode.home.away);
// }
// } else {
// for(axis=X_AXIS; axis <= Z_AXIS; axis++) {
// if(check_limit_switch(axis)) {
// step_axis(axis);
// return;
// }
// }
// // When this code is reached it means all axes are free of their limit-switches. Complete the cycle and rest:
// clear_vector(stepper_mode.position); // By definition this is location [0, 0, 0]
// stepper_mode.mode = MODE_AT_REST;
// }
// }
void st_go_home()
{
// Todo: Perform the homing cycle

View File

@ -42,7 +42,7 @@ uint8_t st_bit_for_stepper(int axis);
void st_buffer_pace(uint32_t microseconds);
// Buffer a new instruction for the steppers
void st_buffer_step(uint8_t motor_port_bits);
inline void st_buffer_step(uint8_t motor_port_bits);
// Block until all buffered steps are executed
void st_synchronize();

View File

@ -28,7 +28,7 @@
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#define RX_BUFFER_SIZE 128
#define RX_BUFFER_SIZE 256
unsigned char rx_buffer[RX_BUFFER_SIZE];