Kernel* kernel = new Kernel();
- kernel->serial->printf("Smoothie ( grbl port ) version 0.2 \r\nstart\r\n");
+ kernel->serial->printf("Smoothie ( grbl port ) version 0.4 \r\nstart\r\n");
kernel->add_module( new Laser(p21) );
kernel->add_module( new Extruder(p26) );
size_t comment = possible_command.find_first_of(";");
if( comment != string::npos ){ possible_command = possible_command.substr(0, comment); }
+ // Dispatch
Gcode gcode = Gcode();
gcode.command = possible_command;
this->kernel->call_event(ON_GCODE_RECEIVED, &gcode );
this->kernel->serial->printf("ok\r\n");
+
+ // Ignore comments
}else if( first_char == ';' || first_char == '(' ){
this->kernel->serial->printf("ok\r\n");
}
this->baud(baud_rate);
}
-
// Called when the module has just been loaded
void SerialConsole::on_module_loaded() {
// We want to be called every time a new char is received
#include "Gcode.h"
#include "mbed.h"
-Gcode::Gcode(){
-}
+Gcode::Gcode(){}
+// Whether or not a Gcode has a letter
bool Gcode::has_letter( char letter ){
return ( this->command.find( letter ) != string::npos );
}
+// Retrieve the value for a given letter
double Gcode::get_value( char letter ){
size_t start = this->command.find(letter);
size_t end = this->command.find_first_not_of("1234567890.-", start+1);
double millimeters_of_travel;
bool call_on_gcode_execute_event_immediatly;
bool on_gcode_execute_event_called;
+
};
#endif
Block::Block(){
clear_vector(this->steps);
- this->times_taken = 0;
+ this->times_taken = 0; // A block can be "taken" by any number of modules, and the next block is not moved to until all the modules have "released" it. This value serves as a tracker.
}
void Block::debug(Kernel* kernel){
// +-------------+
// time -->
void Block::calculate_trapezoid( double entryfactor, double exitfactor ){
+
this->initial_rate = ceil(this->nominal_rate * entryfactor); // (step/min)
this->final_rate = ceil(this->nominal_rate * exitfactor); // (step/min)
double acceleration_per_minute = this->rate_delta * this->planner->kernel->stepper->acceleration_ticks_per_second * 60.0;
player->pop_and_process_new_block();
}
}
+
+
+
Planner* planner;
Player* player;
- short times_taken;
+ short times_taken; // A block can be "taken" by any number of modules, and the next block is not moved to until all the modules have "released" it. This value serves as a tracker.
};
memcpy(this->previous_unit_vec, unit_vec, sizeof(unit_vec)); // previous_unit_vec[] = unit_vec[]
this->previous_nominal_speed = block->nominal_speed;
+ // Update current position
memcpy(this->position, target, sizeof(int)*3);
+
+ // Math-heavy re-computing of the whole queue to take the new
this->recalculate();
-
- this->computing = false;
+ // The block can now be used
block->ready();
- this->kernel->call_event(ON_STEPPER_WAKE_UP, this);
-}
-
-
-//TODO : Make a part of Player
-// Gcodes are attached to their respective block in the queue so that the on_gcode_execute event can be called with the gcode when the block is executed
-void Planner::attach_gcode_to_queue(Gcode* gcode){
- //If the queue is empty, execute immediatly, otherwise attach to the last added block
- if( this->kernel->player->queue.size() == 0 ){
- this->kernel->call_event(ON_GCODE_EXECUTE, gcode );
- }else{
- this->kernel->player->queue.get_ref( this->kernel->player->queue.size() - 1 )->append_gcode(gcode);
- }
}
-
// Recalculates the motion plan according to the following algorithm:
//
// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor)
}
}
-// We are done with this block, discard it
-void Planner::discard_current_block(){
-}
// Debug function
void Planner::dump_queue(){
}
}
-
-
// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the
// acceleration within the allotted distance.
double Planner::max_allowable_speed(double acceleration, double target_velocity, double distance) {
using namespace std;
-
-
-
class Planner : public Module {
public:
Planner();
void append_block( int target[], double feed_rate, double distance, double deltas[] );
double max_allowable_speed( double acceleration, double target_velocity, double distance);
- void attach_gcode_to_queue(Gcode* gcode);
void recalculate();
void reverse_pass();
void forward_pass();
void recalculate_trapezoids();
void dump_queue();
Block* get_current_block();
- void discard_current_block();
void cleanup_queue();
void on_module_loaded();
void on_config_reload(void* argument);
int position[3]; // Current position, in steps
double previous_unit_vec[3];
- bool computing; // Whether or not we are currently computing the queue, TODO: Checks if this is necessary
Block last_deleted_block; // Item -1 in the queue, TODO: Grbl does not need this, but Smoothie won't work without it, we are probably doing something wrong
bool has_deleted_block; // Flag for above value
float previous_nominal_speed;
double acceleration; // Setting
double max_jerk; // Setting
- double junction_deviation;
+ double junction_deviation; // Setting
};
}
+// Get configuration from the config file
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->value(microseconds_per_step_pulse_ckeckusm )->by_default(5 )->as_number();
if( block->millimeters == 0.0 ){ return; }
this->current_block = block;
+
+ // Mark the new block as of interrest to us
this->current_block->take();
+
+ // Setup
this->trapezoid_generator_reset();
this->update_offsets();
for( int stpr=ALPHA_STEPPER; stpr<=GAMMA_STEPPER; stpr++){ this->counters[stpr] = 0; this->stepped[stpr] = 0; }
// Set bits for direction and steps
this->out_bits = this->current_block->direction_bits;
for( int stpr=ALPHA_STEPPER; stpr<=GAMMA_STEPPER; stpr++){
- this->counters[stpr] += this->counter_increment; // (1<<16)>>this->divider; // Basically += 1/divider if we were in floating point arythmetic, but here the counters precision is 1/(2^16).
+ this->counters[stpr] += this->counter_increment;
if( this->counters[stpr] > this->offsets[stpr] && this->stepped[stpr] < this->current_block->steps[stpr] ){
this->counters[stpr] -= this->offsets[stpr] ;
this->stepped[stpr]++;
}
}
// If current block is finished, reset pointer
- this->step_events_completed += this->counter_increment; // (1<<16)>>this->divider; // /this->divider;
+ this->step_events_completed += this->counter_increment;
if( this->step_events_completed >= this->current_block->steps_event_count<<16 ){
if( this->stepped[ALPHA_STEPPER] == this->current_block->steps[ALPHA_STEPPER] && this->stepped[BETA_STEPPER] == this->current_block->steps[BETA_STEPPER] && this->stepped[GAMMA_STEPPER] == this->current_block->steps[GAMMA_STEPPER] ){
this->current_block->release();
}
}
+// We compute this here instead of each time in the interrupt
void Stepper::update_offsets(){
for( int stpr=ALPHA_STEPPER; stpr<=GAMMA_STEPPER; stpr++){
this->offsets[stpr] = (int)floor((float)((float)(1<<16)*(float)((float)this->current_block->steps_event_count / (float)this->current_block->steps[stpr])));
// interrupt. It can be assumed that the trapezoid-generator-parameters and the
// current_block stays untouched by outside handlers for the duration of this function call.
void Stepper::trapezoid_generator_tick() {
- if(this->current_block && !this->kernel->planner->computing ) {
+ if(this->current_block ) {
if(this->step_events_completed < this->current_block->accelerate_until<<16) {
this->trapezoid_adjusted_rate += this->current_block->rate_delta;
if (this->trapezoid_adjusted_rate > this->current_block->nominal_rate ) {
// 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);
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
+ this->counter_increment = int(floor((1<<16)/floor(speed_factor)));
// Set the Timer interval
LPC_TIM0->MR0 = floor( ( SystemCoreClock/4 ) / ( (steps_per_minute/60L) * speed_factor ) );
LPC_TIM1->TCR = 1;
}
+// Get config
void Extruder::on_config_reload(void* argument){
this->microseconds_per_step_pulse = 5; //this->kernel->config->value(microseconds_per_step_pulse_ckeckusm)->by_default(5)->as_number();
}
this->button_ticker.attach_us(this, &Pauser::button_tick, 1000000/100);
}
+//TODO: Make this use InterruptIn
+//Check the state of the button and ask accordingly
void Pauser::button_tick(){
if(this->button_state != this->button){
this->button_state = this->button;