Laser::Laser()
{
laser_on = false;
- scale= 1;
- manual_fire= false;
+ scale = 1;
+ manual_fire = false;
+ fire_duration = 0;
}
void Laser::on_module_loaded()
}
- uint32_t period= THEKERNEL->config->value(laser_module_pwm_period_checksum)->by_default(20)->as_number();
+ uint32_t period = THEKERNEL->config->value(laser_module_pwm_period_checksum)->by_default(20)->as_number();
this->pwm_pin->period_us(period);
this->pwm_pin->write(this->pwm_inverting ? 1 : 0);
this->laser_maximum_power = THEKERNEL->config->value(laser_module_maximum_power_checksum)->by_default(1.0f)->as_number() ;
this->register_for_event(ON_CONSOLE_LINE_RECEIVED);
this->register_for_event(ON_GET_PUBLIC_DATA);
- // no point in updating the power more than the PWM frequency, but no more than 1KHz
- THEKERNEL->slow_ticker->attach(std::min(1000UL, 1000000/period), this, &Laser::set_proportional_power);
+ // no point in updating the power more than the PWM frequency, but not faster than 1KHz
+ ms_per_tick = 1000 / std::min(1000UL, 1000000 / period);
+ THEKERNEL->slow_ticker->attach(std::min(1000UL, 1000000 / period), this, &Laser::set_proportional_power);
}
void Laser::on_console_line_received( void *argument )
if (cmd == "fire") {
string power = shift_parameter(possible_command);
if(power.empty()) {
- msgp->stream->printf("Usage: fire power%%|off\n");
+ msgp->stream->printf("Usage: fire power%% [durationms]|off|status\n");
return;
}
float p;
+ fire_duration = 0; // By default unlimited
+ if(power == "status") {
+ msgp->stream->printf("laser manual state: %s\n", manual_fire ? "on" : "off");
+ return;
+ }
if(power == "off" || power == "0") {
- p= 0;
+ p = 0;
msgp->stream->printf("turning laser off and returning to auto mode\n");
-
- }else{
- p= strtof(power.c_str(), NULL);
- p= confine(p, 0.0F, 100.0F);
- msgp->stream->printf("WARNING: Firing laser at %1.2f%% power, entering manual mode use fire off to return to auto mode\n", p);
+ } else {
+ p = strtof(power.c_str(), NULL);
+ p = confine(p, 0.0F, 100.0F);
+ string duration = shift_parameter(possible_command);
+ if(!duration.empty()) {
+ fire_duration = atoi(duration.c_str());
+ // Avoid negative values, its just incorrect
+ if (fire_duration < ms_per_tick) {
+ msgp->stream->printf("WARNING: Minimal duration is %ld ms, not firing\n", ms_per_tick);
+ return;
+ }
+ // rounding to minimal value
+ if (fire_duration % ms_per_tick != 0) {
+ fire_duration = (fire_duration / ms_per_tick) * ms_per_tick;
+ }
+ msgp->stream->printf("WARNING: Firing laser at %1.2f%% power, for %ld ms, use fire off to stop test fire earlier\n", p, fire_duration);
+ } else {
+ msgp->stream->printf("WARNING: Firing laser at %1.2f%% power, entering manual mode use fire off to return to auto mode\n", p);
+ }
}
- p= p/100.0F;
- manual_fire= set_laser_power(p);
+ p = p / 100.0F;
+ manual_fire = set_laser_power(p);
}
}
if (gcode->has_m) {
if (gcode->m == 221) { // M221 S100 change laser power by percentage S
if(gcode->has_letter('S')) {
- this->scale= gcode->get_value('S') / 100.0F;
+ this->scale = gcode->get_value('S') / 100.0F;
} else {
gcode->stream->printf("Laser power scale at %6.2f %%\n", this->scale * 100.0F);
float Laser::current_speed_ratio(const Block *block) const
{
// find the primary moving actuator (the one with the most steps)
- size_t pm= 0;
- uint32_t max_steps= 0;
+ size_t pm = 0;
+ uint32_t max_steps = 0;
for (size_t i = 0; i < THEROBOT->get_number_registered_motors(); i++) {
// find the motor with the most steps
if(block->steps[i] > max_steps) {
- max_steps= block->steps[i];
- pm= i;
+ max_steps = block->steps[i];
+ pm = i;
}
}
// figure out the ratio of its speed, from 0 to 1 based on where it is on the trapezoid,
// this is based on the fraction it is of the requested rate (nominal rate)
- float ratio= block->get_trapezoid_rate(pm) / block->nominal_rate;
+ float ratio = block->get_trapezoid_rate(pm) / block->nominal_rate;
return ratio;
}
// Note to avoid a race condition where the block is being cleared we check the is_ready flag which gets cleared first,
// as this is an interrupt if that flag is not clear then it cannot be cleared while this is running and the block will still be valid (albeit it may have finished)
if(block != nullptr && block->is_ready && block->is_g123) {
- float requested_power = ((float)block->s_value/(1<<11)) / this->laser_maximum_s_value; // s_value is 1.11 Fixed point
+ float requested_power = ((float)block->s_value / (1 << 11)) / this->laser_maximum_s_value; // s_value is 1.11 Fixed point
float ratio = current_speed_ratio(block);
power = requested_power * ratio * scale;
// called every millisecond from timer ISR
uint32_t Laser::set_proportional_power(uint32_t dummy)
{
- if(manual_fire) return 0;
+ if(manual_fire) {
+ // If we have fire duration set
+ if (fire_duration) {
+ // Decrease it each ms
+ fire_duration -= ms_per_tick;
+ // And if it turned 0, disable laser and manual fire mode
+ if (fire_duration <= 0) {
+ set_laser_power(0);
+ manual_fire = false;
+ }
+ }
+ return 0;
+ }
float power;
if(get_laser_power(power)) {
bool Laser::set_laser_power(float power)
{
// Ensure power is >=0 and <= 1
- power= confine(power, 0.0F, 1.0F);
+ power = confine(power, 0.0F, 1.0F);
if(power > 0.00001F) {
this->pwm_pin->write(this->pwm_inverting ? 1 - power : power);
if(!laser_on && this->ttl_used) this->ttl_pin->set(true);
laser_on = true;
- }else{
+ } else {
this->pwm_pin->write(this->pwm_inverting ? 1 : 0);
if (this->ttl_used) this->ttl_pin->set(false);
laser_on = false;
{
if(argument == nullptr) {
set_laser_power(0);
- manual_fire= false;
+ manual_fire = false;
}
}
float Laser::get_current_power() const
{
- return pwm_pin->read() * 100;
+ float p = pwm_pin->read();
+ return (this->pwm_inverting ? 1 - p : p) * 100;
}