include ./gcc4mbed/build/gcc4mbed.mk\r
\r
flash: \r
- lpc21isp $(PROJECT).hex /dev/ttyUSB0 115200 14746\r
+ lpc21isp $(PROJECT).hex /dev/ttyACM0 115200 14746\r
\r
\r
// Command to retreive the value of a specific configuration setting
void Config::config_get_command( string parameter ){
- this->kernel->serial->printf("%s\r\n", this->get_string( get_checksum( parameter ) ).c_str() );
+ this->kernel->serial->printf("%s\r\n", this->value( get_checksum( parameter ) )->value.c_str() );
}
// Command to set the value of a specific configuration setting
// Get a value from the configuration as a string
// Because we don't like to waste space in Flash with lengthy config parameter names, we take a checksum instead so that the name does not have to be stored
// See get_checksum
-string Config::get_string(uint16_t check_sum){
+ConfigValue* Config::value(uint16_t check_sum){
+ ConfigValue* result = new ConfigValue;
+ result->check_sum = check_sum;
// Open the config file ( find it if we haven't already found it )
FILE *lp = fopen(this->get_config_file().c_str(), "r");
string buffer;
if( buffer[0] == '#' ){ buffer.clear(); continue; } // Ignore comments
size_t begin_key = buffer.find_first_not_of(" ");
size_t begin_value = buffer.find_first_not_of(" ", buffer.find_first_of(" ", begin_key));
+ string key = buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key);
+
// If this line matches the checksum
- if(get_checksum(buffer.substr(begin_key, buffer.find_first_of(" ", begin_key) - begin_key)) != check_sum){ buffer.clear(); continue; }
- fclose(lp);
- return buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value);
- }else{
- buffer += c;
+ if(get_checksum(key) != check_sum){ buffer.clear(); continue; }
+ result->found = true;
+ result->key = key;
+ result->value = buffer.substr(begin_value, buffer.find_first_of("\r\n# ", begin_value+1)-begin_value);
+ buffer += c;
+ break;
}
} while (c != EOF);
fclose(lp);
- this->kernel->serial->printf("ERROR: configuration key not found\r\n");
+ return result;
}
-// Get a value from the file as a number
-double Config::get(uint16_t check_sum){
- string value = this->get_string( check_sum );
- return atof(remove_non_number(value).c_str());
-}
-
-// Returns true if the corresponding config value contains any of the characters
-bool Config::has_characters(uint16_t check_sum, string mask ){
- size_t found = this->get_string(check_sum).find_first_of(mask);
- if( found != string::npos ){ return true; }else{ return false; }
-}
-
-
// Get the filename for the config file
string Config::get_config_file(){
if( this->config_file_found ){ return this->config_file; }
#define CONFIG_H
#include "mbed.h"
#include "libs/Kernel.h"
+#include "libs/utils.h"
#include <string>
using std::string;
#define config_set_checksum 55538
#define config_load_checksum 3143
+class ConfigValue{
+ public:
+ ConfigValue(){
+ this->found = false;
+ this->default_set = false;
+ };
+
+ ConfigValue* required(){
+ if( this->found == true ){
+ return this;
+ }else{
+ error("could not find config setting with checksum %u, please see http://smoothieware.org/configuring-smoothie\r\n", this->check_sum );
+ }
+ }
+
+ double as_number(){
+ if( this->found == false && this->default_set == true ){
+ return this->default_double;
+ }else{
+ double result = atof(remove_non_number(value).c_str());
+ if( result == 0.0 && this->value.find_first_not_of("0.") != string::npos ){
+ error("config setting '%s' with value '%s' is not a valid number, please see http://smoothieware.org/configuring-smoothie\r\n", this->key.c_str(), this->value.c_str() );
+ }
+ return result;
+ }
+ }
+
+ ConfigValue* by_default(double value){
+ this->default_set = true;
+ this->default_double = value;
+ return this;
+ }
+
+ bool has_characters( string mask ){
+ if( this->value.find_first_of(mask) != string::npos ){ return true; }else{ return false; }
+ }
+
+ bool is_inverted(){
+ return this->has_characters(string("!"));
+ }
+
+ string value;
+ string key;
+ uint16_t check_sum;
+ bool found;
+ bool default_set;
+ double default_double;
+};
+
+
class Config : public Module {
public:
Config();
void config_set_command( string parameters );
void config_load_command(string parameters );
void set_string( uint16_t check_sum, string value);
- string get_string(uint16_t check_sum);
- double get(uint16_t check_sum);
+ ConfigValue* value(uint16_t check_sum);
bool has_characters(uint16_t check_sum, string str );
string get_config_file();
void try_config_file(string candidate);
// Config first, because we need the baud_rate setting before we start serial
this->config = new Config();
// Serial second, because the other modules might want to say something
- this->serial = new SerialConsole(USBTX, USBRX, this->config->get(baud_rate_setting_ckeckusm));
+ this->serial = new SerialConsole(USBTX, USBRX, this->config->value(baud_rate_setting_ckeckusm)->by_default(9600)->as_number());
this->add_module( this->config );
this->add_module( this->serial );
void Kernel::add_module(Module* module){
module->kernel = this;
module->on_module_loaded();
+ module->register_for_event(ON_CONFIG_RELOAD);
}
void Kernel::register_for_event(unsigned int id_event, Module* module){
double get_duration_left(unsigned int already_taken_steps);
vector<std::string> commands;
- unsigned short steps[3]; // Number of steps for each axis for this block
- //float speeds[3]; // Speeds for each axis, used in the planning process
- unsigned short steps_event_count; // Steps for the longest axis
+ unsigned int steps[3]; // Number of steps for each axis for this block
+ unsigned int steps_event_count; // Steps for the longest axis
unsigned int nominal_rate; // Nominal rate in steps per minute
float nominal_speed; // Nominal speed in mm per minute
float millimeters; // Distance for this move
- double entry_speed;
+ double entry_speed;
unsigned int rate_delta; // Nomber of steps to add to the speed for each acceleration tick
unsigned int initial_rate; // Initial speed in steps per minute
unsigned int final_rate; // Final speed in steps per minute
#include "libs/Kernel.h"
#include "Block.h"
#include "Planner.h"
+
+
Planner::Planner(){
clear_vector(this->position);
}
void Planner::on_config_reload(void* argument){
- this->acceleration = this->kernel->config->get(acceleration_checksum);
- this->max_jerk = this->kernel->config->get(max_jerk_checksum );
+ this->acceleration = this->kernel->config->value(acceleration_checksum )->required()->as_number();
+ this->max_jerk = this->kernel->config->value(max_jerk_checksum )->required( )->as_number();
+ this->junction_deviation = this->kernel->config->value(junction_deviation_checksum )->by_default(0.05)->as_number();
}
// Do not append block with no movement
if( target[ALPHA_STEPPER] == this->position[ALPHA_STEPPER] && target[BETA_STEPPER] == this->position[BETA_STEPPER] && target[GAMMA_STEPPER] == this->position[GAMMA_STEPPER] ){ this->computing = false; return; }
-
+
// Stall here if the queue is ful
- while( this->queue.size() >= this->queue.capacity() ){ wait_us(100); }
+ while( this->queue.size() >= this->queue.capacity() ){ wait_us(100); }
// Clean up the vector of commands in the block we are about to replace
// It is quite strange to do this here, we really should do it inside Block->pop_and_execute_gcode
}
}
- // Add/get a new block from the queue
this->queue.push_back(Block());
block = this->queue.get_ref( this->queue.size()-1 );
block->planner = this;
block->nominal_speed = block->millimeters * inverse_minute; // (mm/min) Always > 0
block->nominal_rate = ceil(block->steps_event_count * inverse_minute); // (step/min) Always > 0
+ //this->kernel->serial->printf("nom_speed: %f nom_rate: %u step_event_count: %u block->steps_z: %u \r\n", block->nominal_speed, block->nominal_rate, block->steps_event_count, block->steps[2] );
+
// Compute the acceleration rate for the trapezoid generator. Depending on the slope of the line
// average travel per step event changes. For a line along one axis the travel per step event
// is equal to the travel/step in the particular axis. For a 45 degree line the steppers of both
// Compute maximum junction velocity based on maximum acceleration and junction deviation
double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
vmax_junction = min(vmax_junction,
- sqrt(this->acceleration*60*60 * 0.05 * sin_theta_d2/(1.0-sin_theta_d2)) ); // TODO: Get from config
+ sqrt(this->acceleration*60*60 * this->junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
}
}
}
#include "../communication/utils/Gcode.h"
#include "Block.h"
-#define acceleration_checksum 25326
-#define max_jerk_checksum 61012
+#define acceleration_checksum 25326
+#define max_jerk_checksum 61012
+#define junction_deviation_checksum 6035
// TODO: Get from config
#define MINIMUM_PLANNER_SPEED 0.0
double acceleration; // Setting
double max_jerk; // Setting
+ double junction_deviation;
};
}
void Robot::on_config_reload(void* argument){
- this->feed_rate = this->kernel->config->get(default_feed_rate_checksum)/60;
- this->seek_rate = this->kernel->config->get(default_seek_rate_checksum)/60;
- this->mm_per_line_segment = this->kernel->config->get(mm_per_line_segment_checksum);
- this->mm_per_arc_segment = this->kernel->config->get(mm_per_arc_segment_checksum);
+ this->feed_rate = this->kernel->config->value(default_feed_rate_checksum )->by_default(100)->as_number()/60;
+ this->seek_rate = this->kernel->config->value(default_seek_rate_checksum )->by_default(100)->as_number()/60;
+ this->mm_per_line_segment = this->kernel->config->value(mm_per_line_segment_checksum)->by_default(0.1)->as_number();
+ this->mm_per_arc_segment = this->kernel->config->value(mm_per_arc_segment_checksum )->by_default(10 )->as_number();
+ this->arc_correction = this->kernel->config->value(arc_correction_checksum )->by_default(5 )->as_number();
}
//A GCode has been received
double millimeters_of_travel = sqrt( pow( deltas[X_AXIS], 2 ) + pow( deltas[Y_AXIS], 2 ) + pow( deltas[Z_AXIS], 2 ) );
if( millimeters_of_travel < 0.001 ){ return; }
double duration = millimeters_of_travel / rate;
+ //this->kernel->serial->printf("dur: %f mm: %f rate: %f target_z: %f steps_z: %d deltas_z: %f \r\n", duration, millimeters_of_travel, rate, target[2], steps[2], deltas[2] );
this->kernel->planner->append_block( steps, rate*60, millimeters_of_travel, deltas );
- memcpy(this->last_milestone, target, sizeof(double)*3); // this->position[] = target[];
+ memcpy(this->last_milestone, target, sizeof(double)*3); // this->last_milestone[] = target[];
}
for (i = 1; i<segments; i++) { // Increment (segments-1)
- if (count < 25 ) { // TODO: Get from config
+ if (count < this->arc_correction ) {
// Apply vector rotation matrix
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
#define default_feed_rate_checksum 47357
#define mm_per_line_segment_checksum 30176
#define mm_per_arc_segment_checksum 15470
+#define arc_correction_checksum 5074
+
#define NEXT_ACTION_DEFAULT 0
#define NEXT_ACTION_DWELL 1
uint8_t plane_axis_0, plane_axis_1, plane_axis_2; // Current plane ( XY, XZ, YZ )
BaseSolution* arm_solution; // Selected Arm solution ( millimeters to step calculation )
double mm_per_line_segment; // Setting : Used to split lines into segments
- double mm_per_arc_segment; // Setting : Used to split arcs into segments
+ double mm_per_arc_segment; // Setting : Used to split arcs into segmentrs
+
+ // Number of arc generation iterations by small angle approximation before exact arc trajectory
+ // correction. This parameter maybe decreased if there are issues with the accuracy of the arc
+ // generations. In general, the default value is more than enough for the intended CNC applications
+ // of grbl, and should be on the order or greater than the size of the buffer to help with the
+ // computational efficiency of generating arcs.
+ int arc_correction; // Setting : how often to rectify arc computation
+
};
#endif
void Stepper::on_config_reload(void* argument){
LPC_GPIO_TypeDef *gpios[5] ={LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4};
- this->microseconds_per_step_pulse = this->kernel->config->get(microseconds_per_step_pulse_ckeckusm );
- this->acceleration_ticks_per_second = this->kernel->config->get(acceleration_ticks_per_second_checksum);
- this->minimum_steps_per_minute = this->kernel->config->get(minimum_steps_per_minute_checksum );
- this->base_stepping_frequency = this->kernel->config->get(base_stepping_frequency_checksum );
- this->step_gpio_port = gpios[(int)this->kernel->config->get(step_gpio_port_checksum )];
- this->dir_gpio_port = gpios[(int)this->kernel->config->get(dir_gpio_port_checksum )];
- this->alpha_step_pin = this->kernel->config->get(alpha_step_pin_checksum );
- this->beta_step_pin = this->kernel->config->get(beta_step_pin_checksum );
- this->gamma_step_pin = this->kernel->config->get(gamma_step_pin_checksum );
- this->alpha_dir_pin = this->kernel->config->get(alpha_dir_pin_checksum );
- this->beta_dir_pin = this->kernel->config->get(beta_dir_pin_checksum );
- this->gamma_dir_pin = this->kernel->config->get(gamma_dir_pin_checksum );
- this->step_mask = ( 1 << this->alpha_step_pin ) + ( 1 << this->beta_step_pin ) + ( 1 << this->gamma_step_pin );
- this->dir_mask = ( 1 << this->alpha_dir_pin ) + ( 1 << this->beta_dir_pin ) + ( 1 << this->gamma_dir_pin );
- this->step_bits[ALPHA_STEPPER ] = this->alpha_step_pin;
- this->step_bits[BETA_STEPPER ] = this->beta_step_pin;
- this->step_bits[GAMMA_STEPPER ] = this->gamma_step_pin;
- this->step_invert_mask = ( this->kernel->config->has_characters( alpha_step_pin_checksum, string("!") ) << this->alpha_step_pin ) +
- ( this->kernel->config->has_characters( beta_step_pin_checksum, string("!") ) << this->beta_step_pin ) +
- ( this->kernel->config->has_characters( gamma_step_pin_checksum, string("!") ) << this->gamma_step_pin );
- this->dir_invert_mask = ( this->kernel->config->has_characters( alpha_dir_pin_checksum, string("!") ) << this->alpha_dir_pin ) +
- ( this->kernel->config->has_characters( beta_dir_pin_checksum, string("!") ) << this->beta_dir_pin ) +
- ( this->kernel->config->has_characters( gamma_dir_pin_checksum, string("!") ) << this->gamma_dir_pin );
+ this->microseconds_per_step_pulse = this->kernel->config->value(microseconds_per_step_pulse_ckeckusm )->by_default(5 )->as_number();
+ this->acceleration_ticks_per_second = this->kernel->config->value(acceleration_ticks_per_second_checksum)->by_default(100 )->as_number();
+ this->minimum_steps_per_minute = this->kernel->config->value(minimum_steps_per_minute_checksum )->by_default(1200 )->as_number();
+ this->base_stepping_frequency = this->kernel->config->value(base_stepping_frequency_checksum )->by_default(100000)->as_number();
+ this->step_gpio_port = gpios[(int)this->kernel->config->value(step_gpio_port_checksum )->by_default(0 )->as_number()];
+ this->dir_gpio_port = gpios[(int)this->kernel->config->value(dir_gpio_port_checksum )->by_default(0 )->as_number()];
+ this->alpha_step_pin = this->kernel->config->value(alpha_step_pin_checksum )->required( )->as_number();
+ this->beta_step_pin = this->kernel->config->value(beta_step_pin_checksum )->required( )->as_number();
+ this->gamma_step_pin = this->kernel->config->value(gamma_step_pin_checksum )->required( )->as_number();
+ this->alpha_dir_pin = this->kernel->config->value(alpha_dir_pin_checksum )->required( )->as_number();
+ this->beta_dir_pin = this->kernel->config->value(beta_dir_pin_checksum )->required( )->as_number();
+ this->gamma_dir_pin = this->kernel->config->value(gamma_dir_pin_checksum )->required( )->as_number();
+ this->step_mask = ( 1 << this->alpha_step_pin ) + ( 1 << this->beta_step_pin ) + ( 1 << this->gamma_step_pin );
+ this->dir_mask = ( 1 << this->alpha_dir_pin ) + ( 1 << this->beta_dir_pin ) + ( 1 << this->gamma_dir_pin );
+ this->step_bits[ALPHA_STEPPER ] = this->alpha_step_pin;
+ this->step_bits[BETA_STEPPER ] = this->beta_step_pin;
+ this->step_bits[GAMMA_STEPPER ] = this->gamma_step_pin;
+ this->step_invert_mask = ( this->kernel->config->value( alpha_step_pin_checksum )->is_inverted() << this->alpha_step_pin ) +
+ ( this->kernel->config->value( beta_step_pin_checksum )->is_inverted() << this->beta_step_pin ) +
+ ( this->kernel->config->value( gamma_step_pin_checksum )->is_inverted() << this->gamma_step_pin );
+ this->dir_invert_mask = ( this->kernel->config->value( alpha_dir_pin_checksum )->is_inverted() << this->alpha_dir_pin ) +
+ ( this->kernel->config->value( beta_dir_pin_checksum )->is_inverted() << this->beta_dir_pin ) +
+ ( this->kernel->config->value( gamma_dir_pin_checksum )->is_inverted() << this->gamma_dir_pin );
// Set the Timer interval for Match Register 1,
LPC_TIM0->MR1 = (( SystemCoreClock/4 ) / 1000000 ) * this->microseconds_per_step_pulse;
void Stepper::set_step_events_per_minute( double steps_per_minute ){
// We do not step slower than this
- if( steps_per_minute < this->minimum_steps_per_minute ){ steps_per_minute = this->minimum_steps_per_minute; } //TODO: Get from config
+ if( steps_per_minute < this->minimum_steps_per_minute ){ steps_per_minute = this->minimum_steps_per_minute; }
// The speed factor is the factor by which we must multiply the minimal step frequency to reach the maximum step frequency
// The higher, the smoother the movement will be, but the closer the maximum and minimum frequencies are, the smaller the factor is
- double speed_factor = this->base_stepping_frequency / (steps_per_minute/60L); //TODO: Get from config
+ double speed_factor = this->base_stepping_frequency / (steps_per_minute/60L);
if( speed_factor < 1 ){ speed_factor=1; }
this->counter_increment = int(floor((1<<16)/speed_factor));
+ // TODO : Test if we don't get a better signal with a floored speed_factor
+
// Set the Timer interval
LPC_TIM0->MR0 = floor( ( SystemCoreClock/4 ) / ( (steps_per_minute/60L) * speed_factor ) );
#include <math.h>
CartesianSolution::CartesianSolution(Config* passed_config) : config(passed_config){
- this->alpha_steps_per_mm = this->config->get(alpha_steps_per_mm_checksum);
- this->beta_steps_per_mm = this->config->get( beta_steps_per_mm_checksum);
- this->gamma_steps_per_mm = this->config->get(gamma_steps_per_mm_checksum);
+ this->alpha_steps_per_mm = this->config->value(alpha_steps_per_mm_checksum)->as_number();
+ this->beta_steps_per_mm = this->config->value( beta_steps_per_mm_checksum)->as_number();
+ this->gamma_steps_per_mm = this->config->value(gamma_steps_per_mm_checksum)->as_number();
}
void CartesianSolution::millimeters_to_steps( double millimeters[], int steps[] ){
}
void Extruder::on_config_reload(void* argument){
- this->microseconds_per_step_pulse = this->kernel->config->get(microseconds_per_step_pulse_ckeckusm);
+ this->microseconds_per_step_pulse = this->kernel->config->value(microseconds_per_step_pulse_ckeckusm)->by_default(5)->as_number();
}
void Extruder::on_block_begin(void* argument){
// Turn laser off laser at the end of a move
void Laser::on_block_end(void* argument){
this->laser_pin = 0;
- //this->laser_on = false;
}
// Set laser power at the beginning of a block
// Turn laser on/off depending on received GCodes
void Laser::on_gcode_execute(void* argument){
Gcode* gcode = static_cast<Gcode*>(argument);
+ this->laser_on = false;
if( gcode->has_letter('G' )){
int code = gcode->get_value('G');
if( code == 0 ){ // G0