From 0b4166b9fa5bee3b3095791d939aacfe60450027 Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Mon, 3 Jul 2017 17:55:53 -0700 Subject: [PATCH] Home and probing base functionality working --- Makefile | 6 +- avr/src/axis.c | 21 +++- avr/src/command.c | 9 +- avr/src/gcode_expr.c | 7 +- avr/src/gcode_expr.h | 1 + avr/src/gcode_parser.c | 29 +++-- avr/src/gcode_state.h | 3 +- avr/src/machine.c | 166 ++++++++++++++++----------- avr/src/machine.h | 8 +- avr/src/messages.def | 1 + avr/src/motor.c | 1 - avr/src/plan/arc.c | 13 ++- avr/src/plan/arc.h | 1 - avr/src/plan/exec.c | 20 +++- avr/src/plan/jog.c | 15 +-- avr/src/plan/jog.h | 5 - avr/src/plan/line.c | 4 + avr/src/plan/planner.c | 3 +- avr/src/plan/runtime.c | 4 +- avr/src/plan/state.c | 17 ++- avr/src/plan/state.h | 2 + avr/src/status.h | 2 +- avr/src/varcb.c | 2 +- avr/src/vars.c | 25 ++-- avr/src/vars.def | 2 + package.json | 2 +- scripts/update-bbctrl | 4 +- setup.py | 1 + src/jade/templates/control-view.jade | 13 ++- src/js/control-view.js | 31 ++--- src/py/bbctrl/Web.py | 26 +++++ src/resources/config-template.json | 6 +- src/stylus/style.styl | 8 +- 33 files changed, 291 insertions(+), 167 deletions(-) mode change 100644 => 100755 scripts/update-bbctrl diff --git a/Makefile b/Makefile index 13dd22e..c432c8f 100644 --- a/Makefile +++ b/Makefile @@ -49,8 +49,10 @@ publish: pkg echo -n $(VERSION) > dist/latest.txt rsync $(RSYNC_OPTS) dist/$(PKG_NAME).tar.bz2 dist/latest.txt $(PUB_PATH)/ -install: pkg - rsync dist/$(PKG_NAME).tar.bz2 bbmc@bbctrl.local:update.tar.bz2 +update: pkg + http_proxy= curl -i -X PUT -H "Content-Type: multipart/form-data" \ + -F "firmware=@dist/$(PKG_NAME).tar.bz2" \ + http://bbctrl.local/api/firmware/update mount: mkdir -p $(DEST) diff --git a/avr/src/axis.c b/avr/src/axis.c index 30b744c..2ad4511 100644 --- a/avr/src/axis.c +++ b/avr/src/axis.c @@ -130,7 +130,6 @@ AXIS_GET(zero_backoff, float, 0) AXIS_GET(latch_backoff, float, 0) AXIS_GET(recip_jerk, float, 0) - /* Note on jerk functions * * Jerk values can be rather large. Jerk values are stored in the system in @@ -157,3 +156,23 @@ AXIS_VAR_SET(latch_velocity, float) AXIS_VAR_SET(zero_backoff, float) AXIS_VAR_SET(latch_backoff, float) AXIS_VAR_SET(jerk_max, float) + + +float get_homing_dir(int axis) { + switch (axes[axis].homing_mode) { + case HOMING_DISABLED: break; + case HOMING_STALL_MIN: case HOMING_SWITCH_MIN: return -1; + case HOMING_STALL_MAX: case HOMING_SWITCH_MAX: return 1; + } + return 0; +} + + +float get_home(int axis) { + switch (axes[axis].homing_mode) { + case HOMING_DISABLED: break; + case HOMING_STALL_MIN: case HOMING_SWITCH_MIN: return get_travel_min(axis); + case HOMING_STALL_MAX: case HOMING_SWITCH_MAX: return get_travel_max(axis); + } + return NAN; +} diff --git a/avr/src/command.c b/avr/src/command.c index 5e79172..89e12e2 100644 --- a/avr/src/command.c +++ b/avr/src/command.c @@ -34,10 +34,7 @@ #include "vars.h" #include "estop.h" #include "i2c.h" -#include "plan/jog.h" -#include "plan/calibrate.h" #include "plan/buffer.h" -#include "plan/arc.h" #include "plan/state.h" #include "config.h" #include "pgmspace.h" @@ -268,11 +265,7 @@ void command_callback() { default: if (estop_triggered()) {status = STAT_MACHINE_ALARMED; break;} else if (mp_is_flushing()) break; // Flush GCode command - else if (!mp_queue_get_room() || - mp_is_resuming() || - mach_arc_active() || - calibrate_busy() || - mp_jog_busy()) return; // Wait + else if (!mp_is_ready()) return; // Wait for motion planner // Parse and execute GCode command status = gc_gcode_parser(_cmd); diff --git a/avr/src/gcode_expr.c b/avr/src/gcode_expr.c index 083bdb6..8ac1a50 100644 --- a/avr/src/gcode_expr.c +++ b/avr/src/gcode_expr.c @@ -35,7 +35,7 @@ #include -static float _parse_gcode_number(char **p) { +float parse_gcode_number(char **p) { // Avoid parsing G0X10 as a hexadecimal number if (**p == '0' && toupper(*(*p + 1)) == 'X') { (*p)++; // pointer points to X @@ -246,8 +246,6 @@ float parse_gcode_expression(char **p) { bool unary = true; // Used to detect unary minus while (!parser.error && **p) { - if (_op_empty() && parser.valPtr == 1) break; // We're done - switch (**p) { case ' ': case '\n': case '\r': case '\t': (*p)++; break; case '#': _val_push(_parse_gcode_var(p)); unary = false; break; @@ -260,12 +258,13 @@ float parse_gcode_expression(char **p) { _op_apply(); _op_pop(); // Pop opening bracket + if (_op_empty() && parser.valPtr == 1) return _val_pop(); unary = false; break; default: if (isdigit(**p) || **p == '.') { - _val_push(_parse_gcode_number(p)); + _val_push(parse_gcode_number(p)); unary = false; } else if (isalpha(**p)) { diff --git a/avr/src/gcode_expr.h b/avr/src/gcode_expr.h index c449f52..d7a963a 100644 --- a/avr/src/gcode_expr.h +++ b/avr/src/gcode_expr.h @@ -29,4 +29,5 @@ #pragma once +float parse_gcode_number(char **p); float parse_gcode_expression(char **p); diff --git a/avr/src/gcode_parser.c b/avr/src/gcode_parser.c index 642436b..97fbe40 100644 --- a/avr/src/gcode_parser.c +++ b/avr/src/gcode_parser.c @@ -81,7 +81,11 @@ static char *_parse_gcode_comment(char *p) { static stat_t _parse_gcode_value(char **p, float *value) { - *value = parse_gcode_expression(p); + while (isspace(**p)) (*p)++; // skip whitespace + + if (**p == '[') *value = parse_gcode_expression(p); + else *value = parse_gcode_number(p); + return parser.error; } @@ -201,8 +205,11 @@ static stat_t _execute_gcode_block() { case NEXT_ACTION_GOTO_G30_POSITION: // G30 status = mach_goto_g30_position(parser.gn.target, parser.gf.target); break; - case NEXT_ACTION_SET_ABSOLUTE_ORIGIN: // G28.3 - mach_set_absolute_origin(parser.gn.target, parser.gf.target); + case NEXT_ACTION_CLEAR_HOME: // G28.2 + mach_clear_home(parser.gf.target); + break; + case NEXT_ACTION_SET_HOME: // G28.3 + mach_set_home(parser.gn.target, parser.gf.target); break; case NEXT_ACTION_SET_COORD_DATA: mach_set_coord_offsets(parser.gn.parameter, parser.gn.target, @@ -261,25 +268,26 @@ static stat_t _execute_gcode_block() { status = mach_probe(parser.gn.target, parser.gf.target, parser.gn.motion_mode); break; - case MOTION_MODE_SEEK_CLOSE_ERR: // G38.6 + case MOTION_MODE_SEEK_CLOSE_ERR: // G38.6 status = mach_seek(parser.gn.target, parser.gf.target, parser.gn.motion_mode); break; - case MOTION_MODE_SEEK_CLOSE: // G38.7 + case MOTION_MODE_SEEK_CLOSE: // G38.7 status = mach_seek(parser.gn.target, parser.gf.target, parser.gn.motion_mode); break; - case MOTION_MODE_SEEK_OPEN_ERR: // G38.8 + case MOTION_MODE_SEEK_OPEN_ERR: // G38.8 status = mach_seek(parser.gn.target, parser.gf.target, parser.gn.motion_mode); break; - case MOTION_MODE_SEEK_OPEN: // G38.9 + case MOTION_MODE_SEEK_OPEN: // G38.9 status = mach_seek(parser.gn.target, parser.gf.target, parser.gn.motion_mode); break; default: break; // Should not get here } } + // un-set absolute override once the move is planned mach_set_absolute_mode(false); @@ -322,7 +330,8 @@ static stat_t _process_gcode_word(char letter, float value) { SET_MODAL(MODAL_GROUP_G0, next_action, NEXT_ACTION_GOTO_G28_POSITION); case 1: SET_MODAL(MODAL_GROUP_G0, next_action, NEXT_ACTION_SET_G28_POSITION); - case 3: SET_NON_MODAL(next_action, NEXT_ACTION_SET_ABSOLUTE_ORIGIN); + case 2: SET_NON_MODAL(next_action, NEXT_ACTION_CLEAR_HOME); + case 3: SET_NON_MODAL(next_action, NEXT_ACTION_SET_HOME); default: return STAT_GCODE_COMMAND_UNSUPPORTED; } break; @@ -374,11 +383,9 @@ static stat_t _process_gcode_word(char letter, float value) { } break; - case 64: SET_MODAL(MODAL_GROUP_G13,path_mode, PATH_CONTINUOUS); + case 64: SET_MODAL(MODAL_GROUP_G13, path_mode, PATH_CONTINUOUS); case 80: SET_MODAL(MODAL_GROUP_G1, motion_mode, MOTION_MODE_CANCEL_MOTION_MODE); - // case 90: SET_MODAL(MODAL_GROUP_G3, distance_mode, ABSOLUTE_MODE); - // case 91: SET_MODAL(MODAL_GROUP_G3, distance_mode, INCREMENTAL_MODE); case 90: switch (_point(value)) { case 0: SET_MODAL(MODAL_GROUP_G3, distance_mode, ABSOLUTE_MODE); diff --git a/avr/src/gcode_state.h b/avr/src/gcode_state.h index 8c97677..4dc2665 100644 --- a/avr/src/gcode_state.h +++ b/avr/src/gcode_state.h @@ -46,7 +46,8 @@ typedef enum { NEXT_ACTION_SET_COORD_DATA, // G10 NEXT_ACTION_GOTO_G28_POSITION, // G28 go to machine position NEXT_ACTION_SET_G28_POSITION, // G28.1 set position in abs coordinates - NEXT_ACTION_SET_ABSOLUTE_ORIGIN, // G28.3 origin set + NEXT_ACTION_CLEAR_HOME, // G28.3 clear axis home + NEXT_ACTION_SET_HOME, // G28.3 set axis home position NEXT_ACTION_GOTO_G30_POSITION, // G30 NEXT_ACTION_SET_G30_POSITION, // G30.1 NEXT_ACTION_SET_ORIGIN_OFFSETS, // G92 diff --git a/avr/src/machine.c b/avr/src/machine.c index 50e29ad..f15fb35 100644 --- a/avr/src/machine.c +++ b/avr/src/machine.c @@ -259,19 +259,49 @@ void mach_set_position(const float position[]) { /*** Get position of axis in absolute coordinates * - * NOTE: Machine position is always returned in mm mode. No units conversion + * NOTE: Machine position is always returned in mm mode. No unit conversion * is performed. */ float mach_get_axis_position(uint8_t axis) {return mach.position[axis];} -/* Critical helpers +/* Set the position of a single axis in the model, planner and runtime * - * Core functions supporting the machining functions - * These functions are not part of the NIST defined functions + * This command sets an axis/axes to a position provided as an argument. + * This is useful for setting origins for probing, and other operations. + * + * !!!!! DO NOT CALL THIS FUNCTION WHILE IN A MACHINING CYCLE !!!!! + * + * More specifically, do not call this function if there are any moves + * in the planner or if the runtime is moving. The system must be + * quiescent or you will introduce positional errors. This is true + * because the planned / running moves have a different reference + * frame than the one you are now going to set. These functions should + * only be called during initialization sequences and during cycles + * when you know there are no more moves in the planner and that all motion + * has stopped. */ +void mach_set_axis_position(unsigned axis, float position) { + //if (!mp_is_quiescent()) ALARM(STAT_MACH_NOT_QUIESCENT); + if (AXES <= axis) return; + + // TODO should set work position, accounting for offsets + + mach.position[axis] = position; + mp_set_axis_position(axis, position); + mp_runtime_set_axis_position(axis, position); + mp_runtime_set_steps_from_position(); +} +/// Do not call this function while machine is moving or queue is not empty +void mach_set_position_from_runtime() { + for (int axis = 0; axis < AXES; axis++) { + mach.position[axis] = mp_runtime_get_work_position(axis); + mp_set_axis_position(axis, mach.position[axis]); + } +} + /*** Calculate target vector * @@ -308,17 +338,13 @@ void mach_calc_target(float target[], const float values[], /*** Return error code if soft limit is exceeded * - * Must be called with target properly set in GM struct. Best done - * after mach_calc_target(). - * - * Tests for soft limit for any axis if min and max are - * different values. You can set min and max to 0,0 to disable soft - * limits for an axis. Also will not test a min or a max if the value - * is < -1000000 (negative one million). This allows a single end to - * be tested w/the other disabled, should that requirement ever arise. + * Tests for soft limit for any axis if min and max are different values. You + * can set min and max to 0 to disable soft limits for an axis. */ stat_t mach_test_soft_limits(float target[]) { for (int axis = 0; axis < AXES; axis++) { + if (!axis_is_enabled(axis) || !axis_get_homed(axis)) continue; + float min = axis_get_travel_min(axis); float max = axis_get_travel_max(axis); @@ -333,9 +359,10 @@ stat_t mach_test_soft_limits(float target[]) { } -/* machining functions - * Values are passed in pre-unit_converted state (from gn structure) - * All operations occur on gm (current model state) +/* Machining functions + * + * Values are passed in pre-unit_converted state (from gn structure) + * All operations occur on gm (current model state) * * These are organized by section number (x.x.x) in the order they are * found in NIST RS274 NGCv3 @@ -408,33 +435,6 @@ void mach_set_coord_system(coord_system_t cs) { } -/* Set the position of a single axis in the model, planner and runtime - * - * This command sets an axis/axes to a position provided as an argument. - * This is useful for setting origins for probing, and other operations. - * - * !!!!! DO NOT CALL THIS FUNCTION WHILE IN A MACHINING CYCLE !!!!! - * - * More specifically, do not call this function if there are any moves - * in the planner or if the runtime is moving. The system must be - * quiescent or you will introduce positional errors. This is true - * because the planned / running moves have a different reference - * frame than the one you are now going to set. These functions should - * only be called during initialization sequences and during cycles - * when you know there are no more moves in the planner and that all motion - * has stopped. - */ -void mach_set_axis_position(unsigned axis, float position) { - //if (!mp_is_quiescent()) ALARM(STAT_MACH_NOT_QUIESCENT); - if (AXES <= axis) return; - - mach.position[axis] = position; - mp_set_axis_position(axis, position); - mp_runtime_set_axis_position(axis, position); - mp_runtime_set_steps_from_position(); -} - - stat_t mach_zero_all() { for (unsigned axis = 0; axis < AXES; axis++) { stat_t status = mach_zero_axis(axis); @@ -456,7 +456,7 @@ stat_t mach_zero_axis(unsigned axis) { // G28.3 functions and support -static stat_t _exec_absolute_origin(mp_buffer_t *bf) { +static stat_t _exec_home(mp_buffer_t *bf) { const float *origin = bf->target; const float *flags = bf->unit; @@ -480,20 +480,28 @@ static stat_t _exec_absolute_origin(mp_buffer_t *bf) { * the planner queue. This includes the runtime position and the step * recording done by the encoders. */ -void mach_set_absolute_origin(float origin[], bool flags[]) { - float value[AXES]; +void mach_set_home(float origin[], bool flags[]) { + mp_buffer_t *bf = mp_queue_get_tail(); for (int axis = 0; axis < AXES; axis++) - if (flags[axis]) { - value[axis] = TO_MM(origin[axis]); - mach.position[axis] = value[axis]; // set model position - mp_set_axis_position(axis, value[axis]); // set mm position + if (flags[axis] && isfinite(origin[axis])) { + // TODO What about work offsets? + mach.position[axis] = TO_MM(origin[axis]); // set model position + mp_set_axis_position(axis, mach.position[axis]); // set mm position + axis_set_homed(axis, true); + + bf->target[axis] = origin[axis]; + bf->unit[axis] = flags[axis]; } - mp_buffer_t *bf = mp_queue_get_tail(); - copy_vector(bf->target, origin); - copy_vector(bf->unit, flags); - mp_queue_push_nonstop(_exec_absolute_origin, mach_get_line()); + // Synchronized update of runtime position + mp_queue_push_nonstop(_exec_home, mach_get_line()); +} + + +void mach_clear_home(bool flags[]) { + for (int axis = 0; axis < AXES; axis++) + if (flags[axis]) axis_set_homed(axis, false); } @@ -503,8 +511,8 @@ void mach_set_absolute_origin(float origin[], bool flags[]) { /// G92 void mach_set_origin_offsets(float offset[], bool flags[]) { - // set offsets in the Gcode model extended context mach.origin_offset_enable = true; + for (int axis = 0; axis < AXES; axis++) if (flags[axis]) mach.origin_offset[axis] = mach.position[axis] - @@ -515,6 +523,7 @@ void mach_set_origin_offsets(float offset[], bool flags[]) { /// G92.1 void mach_reset_origin_offsets() { mach.origin_offset_enable = false; + for (int axis = 0; axis < AXES; axis++) mach.origin_offset[axis] = 0; } @@ -566,6 +575,12 @@ stat_t mach_plan_line(float target[], switch_id_t sw) { // Free Space Motion (4.3.4) static stat_t _feed(float values[], bool flags[], switch_id_t sw) { + // Trap inverse time mode wo/ feed rate + if (!mach_is_rapid() && mach.gm.feed_mode == INVERSE_TIME_MODE && + !parser.gf.feed_rate) + return STAT_GCODE_FEEDRATE_NOT_SPECIFIED; + + // Compute target position float target[AXES]; mach_calc_target(target, values, flags); @@ -575,10 +590,10 @@ static stat_t _feed(float values[], bool flags[], switch_id_t sw) { // prep and plan the move mach_update_work_offsets(); // update resolved offsets - mach_plan_line(target, sw); + RITORNO(mach_plan_line(target, sw)); copy_vector(mach.position, target); // update model position - return status; + return STAT_OK; } @@ -629,32 +644,56 @@ stat_t mach_probe(float values[], bool flags[], motion_mode_t mode) { } -stat_t mach_seek(float values[], bool flags[], motion_mode_t mode) { - mach_set_motion_mode(mode); +stat_t _exec_set_seek_position(mp_buffer_t *bf) { + mach_set_position_from_runtime(); + mp_pause_queue(false); + return STAT_NOOP; // No move queued +} - float target[AXES]; - mach_calc_target(target, values, flags); + +stat_t mach_seek(float target[], bool flags[], motion_mode_t mode) { + mach_set_motion_mode(mode); switch_id_t sw = SW_PROBE; for (int axis = 0; axis < AXES; axis++) if (flags[axis]) { + // Convert to incremental move + if (mach.gm.distance_mode == ABSOLUTE_MODE) + target[axis] += mach.position[axis]; + if (!axis_is_enabled(axis)) return STAT_SEEK_AXIS_DISABLED; if (sw != SW_PROBE) return STAT_SEEK_MULTIPLE_AXES; if (fp_EQ(target[axis], mach.position[axis])) return STAT_SEEK_ZERO_MOVE; bool min = target[axis] < mach.position[axis]; + + if (mode == MOTION_MODE_SEEK_OPEN_ERR || + mode == MOTION_MODE_SEEK_OPEN) min = !min; + switch (axis) { case AXIS_X: sw = min ? SW_MIN_X : SW_MAX_X; break; case AXIS_Y: sw = min ? SW_MIN_Y : SW_MAX_Y; break; case AXIS_Z: sw = min ? SW_MIN_Z : SW_MAX_Z; break; case AXIS_A: sw = min ? SW_MIN_A : SW_MAX_A; break; } + + if (!switch_is_enabled(sw)) return STAT_SEEK_SWITCH_DISABLED; + + STATUS_DEBUG("Axis target %f, position %f, planner %f, runtime %f", + target[axis], mach.position[axis], + mp_get_axis_position(axis), + mp_runtime_get_axis_position(axis)); } if (sw == SW_PROBE) return STAT_SEEK_MISSING_AXIS; - return _feed(values, flags, sw); + RITORNO(_feed(target, flags, sw)); + + mp_pause_queue(true); + mp_queue_push_nonstop(_exec_set_seek_position, mach_get_line()); + + return STAT_OK; } @@ -689,11 +728,6 @@ void mach_set_path_mode(path_mode_t mode) { /// G1 stat_t mach_feed(float values[], bool flags[]) { - // trap zero feed rate condition - if (fp_ZERO(mach.gm.feed_rate) || - (mach.gm.feed_mode == INVERSE_TIME_MODE && !parser.gf.feed_rate)) - return STAT_GCODE_FEEDRATE_NOT_SPECIFIED; - mach_set_motion_mode(MOTION_MODE_FEED); return _feed(values, flags, 0); } diff --git a/avr/src/machine.h b/avr/src/machine.h index c053441..271959f 100644 --- a/avr/src/machine.h +++ b/avr/src/machine.h @@ -67,6 +67,8 @@ void mach_update_work_offsets(); const float *mach_get_position(); void mach_set_position(const float position[]); float mach_get_axis_position(uint8_t axis); +void mach_set_axis_position(unsigned axis, float position); +void mach_set_position_from_runtime(); // Critical helpers void mach_calc_target(float target[], const float values[], const bool flags[]); @@ -84,14 +86,14 @@ void mach_set_distance_mode(distance_mode_t mode); void mach_set_arc_distance_mode(distance_mode_t mode); void mach_set_coord_offsets(coord_system_t coord_system, float offset[], bool flags[]); +void mach_set_coord_system(coord_system_t coord_system); -void mach_set_axis_position(unsigned axis, float position); -void mach_set_absolute_origin(float origin[], bool flags[]); +void mach_set_home(float origin[], bool flags[]); +void mach_clear_home(bool flags[]); stat_t mach_zero_all(); stat_t mach_zero_axis(unsigned axis); -void mach_set_coord_system(coord_system_t coord_system); void mach_set_origin_offsets(float offset[], bool flags[]); void mach_reset_origin_offsets(); void mach_suspend_origin_offsets(); diff --git a/avr/src/messages.def b/avr/src/messages.def index ca4a85a..c69933b 100644 --- a/avr/src/messages.def +++ b/avr/src/messages.def @@ -121,6 +121,7 @@ STAT_MSG(MOVE_DURING_PROBE, "Probing error - move during probe") STAT_MSG(SEEK_MULTIPLE_AXES, "Seek error - multiple axes specified") STAT_MSG(SEEK_MISSING_AXIS, "Seek error - no axis specified") STAT_MSG(SEEK_AXIS_DISABLED, "Seek error - specified axis is disabled") +STAT_MSG(SEEK_SWITCH_DISABLED, "Seek error - target switch is disabled") STAT_MSG(SEEK_ZERO_MOVE, "Seek error - axis move too short or zero") STAT_MSG(SEEK_SWTICH_NOT_FOUND, "Seek error - move end before switch change") diff --git a/avr/src/motor.c b/avr/src/motor.c index 7419bc2..4e421ff 100644 --- a/avr/src/motor.c +++ b/avr/src/motor.c @@ -40,7 +40,6 @@ #include "pgmspace.h" #include "plan/runtime.h" -#include "plan/calibrate.h" #include diff --git a/avr/src/plan/arc.c b/avr/src/plan/arc.c index 7f6d382..25ad833 100644 --- a/avr/src/plan/arc.c +++ b/avr/src/plan/arc.c @@ -40,6 +40,8 @@ #include "config.h" #include "util.h" +#include + #include #include #include @@ -462,6 +464,7 @@ stat_t mach_arc_feed(float values[], bool values_f[], // arc endpoints // Note, arc soft limits are not tested here arc.running = true; // Enable arc run in callback + mp_pause_queue(true); // Hold queue until arc is done mach_arc_callback(); // Queue initial arc moves mach_set_position(arc.target); // update model position @@ -494,14 +497,14 @@ void mach_arc_callback() { // run the line mach_plan_line(arc.position, 0); - if (!--arc.segments) arc.running = false; + if (!--arc.segments) mach_abort_arc(); } } -bool mach_arc_active() {return arc.running;} - - /// Stop arc movement without maintaining position /// OK to call if no arc is running -void mach_abort_arc() {arc.running = false;} +void mach_abort_arc() { + arc.running = false; + mp_pause_queue(false); +} diff --git a/avr/src/plan/arc.h b/avr/src/plan/arc.h index b54ed7f..13a047f 100644 --- a/avr/src/plan/arc.h +++ b/avr/src/plan/arc.h @@ -44,5 +44,4 @@ stat_t mach_arc_feed(float target[], bool flags[], float offsets[], float P, bool P_f, bool modal_g1_f, motion_mode_t motion_mode); void mach_arc_callback(); -bool mach_arc_active(); void mach_abort_arc(); diff --git a/avr/src/plan/exec.c b/avr/src/plan/exec.c index dc19f4a..2814275 100644 --- a/avr/src/plan/exec.c +++ b/avr/src/plan/exec.c @@ -248,6 +248,9 @@ static void _plan_hold() { ex.tail_length = available_length; ex.exit_velocity = 0; } + + // Don't error if seek was stopped + bf->flags &= ~BUFFER_SEEK_ERROR; } @@ -273,6 +276,10 @@ static stat_t _exec_aline_init(mp_buffer_t *bf) { ex.cruise_velocity = bf->cruise_velocity; ex.exit_velocity = bf->exit_velocity; + // Enforce min cruise velocity + // TODO How does cruise_velocity ever end up zero when length is non-zero? + if (ex.cruise_velocity < 10) ex.cruise_velocity = 10; + ex.section = SECTION_HEAD; ex.section_new = true; ex.hold_planned = false; @@ -363,10 +370,15 @@ stat_t mp_exec_aline(mp_buffer_t *bf) { } // If seeking, end move when switch is in target state. - if ((bf->flags & BUFFER_SEEK_CLOSE && !switch_is_active(bf->sw)) || - (bf->flags & BUFFER_SEEK_OPEN && switch_is_active(bf->sw))) { - mp_runtime_set_velocity(0); - return STAT_NOOP; + if ((((bf->flags & BUFFER_SEEK_CLOSE) && switch_is_active(bf->sw)) || + ((bf->flags & BUFFER_SEEK_OPEN) && !switch_is_active(bf->sw))) && + !ex.hold_planned) { + if (!fp_ZERO(mp_runtime_get_velocity())) _plan_hold(); + else { + mp_runtime_set_velocity(0); + bf->flags &= ~BUFFER_SEEK_ERROR; + return STAT_NOOP; + } } // Plan holds diff --git a/avr/src/plan/jog.c b/avr/src/plan/jog.c index e2a9682..346cc92 100644 --- a/avr/src/plan/jog.c +++ b/avr/src/plan/jog.c @@ -140,10 +140,9 @@ static stat_t _exec_jog(mp_buffer_t *bf) { // Check if we are done if (done) { // Update machine position - for (int axis = 0; axis < AXES; axis++) - mach_set_axis_position(axis, mp_runtime_get_work_position(axis)); - + mach_set_position_from_runtime(); mp_set_cycle(CYCLE_MACHINING); // Default cycle + mp_pause_queue(false); return STAT_NOOP; // Done, no move executed } @@ -163,11 +162,8 @@ static stat_t _exec_jog(mp_buffer_t *bf) { } -bool mp_jog_busy() {return mp_get_cycle() == CYCLE_JOGGING;} - - uint8_t command_jog(int argc, char *argv[]) { - if (!mp_jog_busy() && + if (mp_get_cycle() != CYCLE_JOGGING && (mp_get_state() != STATE_READY || mp_get_cycle() != CYCLE_MACHINING)) return STAT_NOOP; @@ -178,15 +174,16 @@ uint8_t command_jog(int argc, char *argv[]) { else velocity[axis] = 0; // Reset - if (!mp_jog_busy()) memset(&jr, 0, sizeof(jr)); + if (mp_get_cycle() != CYCLE_JOGGING) memset(&jr, 0, sizeof(jr)); jr.writing = true; for (int axis = 0; axis < AXES; axis++) jr.next_velocity[axis] = velocity[axis]; jr.writing = false; - if (!mp_jog_busy()) { + if (mp_get_cycle() != CYCLE_JOGGING) { mp_set_cycle(CYCLE_JOGGING); + mp_pause_queue(true); mp_queue_push_nonstop(_exec_jog, -1); } diff --git a/avr/src/plan/jog.h b/avr/src/plan/jog.h index 4dd2e68..f2bfa69 100644 --- a/avr/src/plan/jog.h +++ b/avr/src/plan/jog.h @@ -26,8 +26,3 @@ \******************************************************************************/ #pragma once - -#include - - -bool mp_jog_busy(); diff --git a/avr/src/plan/line.c b/avr/src/plan/line.c index 989f2d6..e83b583 100644 --- a/avr/src/plan/line.c +++ b/avr/src/plan/line.c @@ -375,6 +375,10 @@ stat_t mp_aline(const float target[], buffer_flags_t flags, switch_id_t sw, (flags & BUFFER_EXACT_STOP) ? "true" : "false", feed_rate, feed_override, line); + // Trap zero feed rate condition + if (!(flags & BUFFER_RAPID) && fp_ZERO(feed_rate)) + return STAT_GCODE_FEEDRATE_NOT_SPECIFIED; + // Compute axis and move lengths float axis_length[AXES]; float axis_square[AXES]; diff --git a/avr/src/plan/planner.c b/avr/src/plan/planner.c index 02dafdb..55e51f4 100644 --- a/avr/src/plan/planner.c +++ b/avr/src/plan/planner.c @@ -670,7 +670,8 @@ float mp_get_target_length(float Vi, float Vf, float jerk) { * * A convenient function for determining Vf target velocity for a given * initial velocity (Vi), length (L), and maximum jerk (Jm). Equation e) is - * b) solved for Vf. Equation f) is c) solved for Vf. Use f) (obviously) + * b) solved for Vf. Equation f) is equation c) solved for Vf. We use f) since + * it is more simple. * * e) Vf = (sqrt(L) * (L / sqrt(1 / Jm))^(1/6) + * (1 / Jm)^(1/4) * Vi) / (1 / Jm)^(1/4) diff --git a/avr/src/plan/runtime.c b/avr/src/plan/runtime.c index b191af0..a9c1bf1 100644 --- a/avr/src/plan/runtime.c +++ b/avr/src/plan/runtime.c @@ -51,6 +51,7 @@ typedef struct { int32_t line; // Current move GCode line number uint8_t tool; // Active tool +#if 0 // TODO These are not currently being set float feed; feed_mode_t feed_mode; float feed_override; @@ -63,8 +64,7 @@ typedef struct { path_mode_t path_mode; distance_mode_t distance_mode; distance_mode_t arc_distance_mode; - - float previous_error[MOTORS]; +#endif } mp_runtime_t; static mp_runtime_t rt = {0}; diff --git a/avr/src/plan/state.c b/avr/src/plan/state.c index a8abd2b..29c161b 100644 --- a/avr/src/plan/state.c +++ b/avr/src/plan/state.c @@ -45,6 +45,7 @@ typedef struct { mp_state_t state; mp_cycle_t cycle; mp_hold_reason_t hold_reason; + bool pause; bool hold_requested; bool flush_requested; @@ -154,6 +155,14 @@ bool mp_is_quiescent() { } +bool mp_is_ready() { + return mp_queue_get_room() && !mp_is_resuming() && !ps.pause; +} + + +void mp_pause_queue(bool x) {ps.pause = x;} + + void mp_state_optional_pause() { if (ps.optional_pause_requested) { mp_set_hold_reason(HOLD_REASON_USER_PAUSE); @@ -178,7 +187,10 @@ void mp_state_idle() { } -void mp_state_estop() {_set_state(STATE_ESTOPPED);} +void mp_state_estop() { + _set_state(STATE_ESTOPPED); + mp_pause_queue(false); +} void mp_request_hold() {ps.hold_requested = true;} @@ -233,8 +245,7 @@ void mp_state_callback() { // NOTE The following uses low-level mp calls for absolute position. // Reset to actual machine position. Otherwise machine is set to the // position of the last queued move. - for (int axis = 0; axis < AXES; axis++) - mach_set_axis_position(axis, mp_runtime_get_axis_position(axis)); + mach_set_position_from_runtime(); } // Stop spindle diff --git a/avr/src/plan/state.h b/avr/src/plan/state.h index df9a9d9..a287c42 100644 --- a/avr/src/plan/state.h +++ b/avr/src/plan/state.h @@ -76,6 +76,8 @@ void mp_set_hold_reason(mp_hold_reason_t reason); bool mp_is_flushing(); bool mp_is_resuming(); bool mp_is_quiescent(); +bool mp_is_ready(); +void mp_pause_queue(bool x); void mp_state_optional_pause(); void mp_state_holding(); diff --git a/avr/src/status.h b/avr/src/status.h index ef27054..5e2b91d 100644 --- a/avr/src/status.h +++ b/avr/src/status.h @@ -75,7 +75,7 @@ stat_t status_alarm(const char *location, stat_t status, const char *msg); STATUS_MESSAGE(STAT_LEVEL_INFO, STAT_OK, MSG, ##__VA_ARGS__) #define STATUS_DEBUG(MSG, ...) \ - STATUS_MESSAGE(STAT_LEVEL_WARNING, STAT_OK, MSG, ##__VA_ARGS__) + STATUS_MESSAGE(STAT_LEVEL_DEBUG, STAT_OK, MSG, ##__VA_ARGS__) #define STATUS_WARNING(MSG, ...) \ STATUS_MESSAGE(STAT_LEVEL_WARNING, STAT_OK, MSG, ##__VA_ARGS__) diff --git a/avr/src/varcb.c b/avr/src/varcb.c index ecbd56a..283b156 100644 --- a/avr/src/varcb.c +++ b/avr/src/varcb.c @@ -34,7 +34,7 @@ #include "plan/state.h" // Axis -float get_position(int axis) {return mp_runtime_get_axis_position(axis);} +float get_position(int axis) {return mp_runtime_get_work_position(axis);} void set_position(int axis, float position) { diff --git a/avr/src/vars.c b/avr/src/vars.c index c05a476..70d6762 100644 --- a/avr/src/vars.c +++ b/avr/src/vars.c @@ -69,6 +69,7 @@ MAP(EQ_FUNC, SEMI, flags_t, string, pstring, uint8_t, uint16_t, int32_t, char); // String static void var_print_string(string s) {printf_P(PSTR("\"%s\""), s);} +static float var_string_to_float(string s) {return 0;} // Program string @@ -83,6 +84,8 @@ static void var_print_flags_t(flags_t x) { print_status_flags(x); } +static float var_flags_t_to_float(flags_t x) {return x;} + // Float static bool var_eq_float(float a, float b) { @@ -141,11 +144,7 @@ static float var_char_to_float(char x) {return x;} // int8 #if 0 -static void var_print_int8_t(int8_t x) { - printf_P(PSTR("%"PRIi8), x); -} - - +static void var_print_int8_t(int8_t x) {printf_P(PSTR("%"PRIi8), x);} static int8_t var_parse_int8_t(const char *value) {return strtol(value, 0, 0);} static float var_int8_t_to_float(int8_t x) {return x;} #endif @@ -177,6 +176,7 @@ static float var_uint16_t_to_float(uint16_t x) {return x;} // int32 static void var_print_int32_t(int32_t x) {printf_P(PSTR("%"PRIi32), x);} +static float var_int32_t_to_float(int32_t x) {return x;} // Ensure no code is used more than once @@ -387,15 +387,14 @@ float vars_get_number(const char *_name) { int i; #define VAR(NAME, CODE, TYPE, INDEX, SET, ...) \ - IF(SET) \ - (if (!strcmp(IF_ELSE(INDEX)(name + 1, name), #CODE)) { \ - IF(INDEX) \ - (i = strchr(INDEX##_LABEL, name[0]) - INDEX##_LABEL; \ - if (INDEX <= i) return 0); \ + if (!strcmp(IF_ELSE(INDEX)(name + 1, name), #CODE)) { \ + IF(INDEX) \ + (i = strchr(INDEX##_LABEL, name[0]) - INDEX##_LABEL; \ + if (INDEX <= i) return 0); \ \ - TYPE x = get_##NAME(IF(INDEX)(i)); \ - return var_##TYPE##_to_float(x); \ - }) \ + TYPE x = get_##NAME(IF(INDEX)(i)); \ + return var_##TYPE##_to_float(x); \ + } \ #include "vars.def" #undef VAR diff --git a/avr/src/vars.def b/avr/src/vars.def index f8878f1..dee8446 100644 --- a/avr/src/vars.def +++ b/avr/src/vars.def @@ -67,6 +67,8 @@ VAR(probe_switch, pw, bool, 0, 0, 1, "Probe switch state") // Homing VAR(homing_mode, ho, uint8_t, MOTORS, 1, 1, "Homing type") +VAR(homing_dir, hd, float, MOTORS, 0, 1, "Homing direction") +VAR(home, h, float, MOTORS, 0, 1, "Home position") VAR(search_velocity,sv, float, MOTORS, 1, 1, "Homing search velocity") VAR(latch_velocity, lv, float, MOTORS, 1, 1, "Homing latch velocity") VAR(latch_backoff, lb, float, MOTORS, 1, 1, "Homing latch backoff") diff --git a/package.json b/package.json index 4740ce2..284f3a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bbctrl", - "version": "0.1.10", + "version": "0.1.11", "homepage": "https://github.com/buildbotics/rpi-firmware", "license": "GPL 3+", diff --git a/scripts/update-bbctrl b/scripts/update-bbctrl old mode 100644 new mode 100755 index 0930949..739203b --- a/scripts/update-bbctrl +++ b/scripts/update-bbctrl @@ -1,6 +1,6 @@ #!/bin/bash -UPDATE=$(pwd)/update.tar.bz2 +UPDATE=/var/lib/bbctrl/firmware/update.tar.bz2 if [ ! -e "$UPDATE" ]; then echo "Missing $UPDATE" @@ -16,4 +16,4 @@ cd * ./scripts/install.sh "$*" cd - -rm -rf /tmp/update +rm -rf /tmp/update $UPDATE diff --git a/setup.py b/setup.py index 6356450..8a8ca35 100755 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ setup( 'bbctrl = bbctrl:run' ] }, + scripts = ['scripts/update-bbctrl', 'scripts/upgrade-bbctrl'], install_requires = 'tornado sockjs-tornado pyserial pyudev smbus2'.split(), zip_safe = False, ) diff --git a/src/jade/templates/control-view.jade b/src/jade/templates/control-view.jade index de9c2cd..d814a0a 100644 --- a/src/jade/templates/control-view.jade +++ b/src/jade/templates/control-view.jade @@ -139,7 +139,12 @@ script#control-view-template(type="text/x-template") option(v-for="file in files", :value="file") {{file}} .gcode(:class="{placeholder: !gcode}") - | {{{gcode || 'GCode displays here.'}}} + span(v-if="!gcode.length") GCode displays here. + ul + li(v-for="item in gcode", id="gcode-line-{{$index}}", + track-by="$index") + span {{$index + 1}} + | {{item}} section#content2.tab-content .mdi.pure-form @@ -150,7 +155,11 @@ script#control-view-template(type="text/x-template") input(v-model="mdi", @keyup.enter="submit_mdi") .history(:class="{placeholder: !history}") - | {{history || 'MDI history displays here.'}} + span(v-if="!history.length") MDI history displays here. + ul + li(v-for="item in history", @click="load_history($index)", + track-by="$index") + | {{item}} section#content3.tab-content .jog diff --git a/src/js/control-view.js b/src/js/control-view.js index 0740e49..b182a0b 100644 --- a/src/js/control-view.js +++ b/src/js/control-view.js @@ -14,6 +14,12 @@ function _msg_equal(a, b) { } +function escapeHTML(s) { + var entityMap = {'&': '&', '<': '<', '>': '>'}; + return String(s).replace(/[&<>]/g, function (s) {return entityMap[s];}); +} + + module.exports = { template: '#control-view-template', props: ['config', 'state'], @@ -26,8 +32,8 @@ module.exports = { last_file: '', files: [], axes: 'xyzabc', - gcode: '', - history: '', + gcode: [], + history: [], console: [], speed_override: 1, feed_override: 1 @@ -134,10 +140,15 @@ module.exports = { submit_mdi: function () { this.send(this.mdi); - this.history = this.mdi + '\n' + this.history; + if (!this.history.length || this.history[0] != this.mdi) + this.history.unshift(this.mdi); + this.mdi = ''; }, + load_history: function (index) {this.mdi = this.history[index];}, + + open: function (e) { $('.gcode-file-input').click(); }, @@ -166,7 +177,7 @@ module.exports = { if (!file || this.files.indexOf(file) == -1) { this.file = ''; - this.gcode = ''; + this.gcode = []; return; } @@ -174,17 +185,7 @@ module.exports = { api.get('file/' + file) .done(function (data) { - var lines = data.trimRight().split(/\r?\n/); - var html = '
    '; - - for (var i = 0; i < lines.length; i++) - // TODO escape HTML chars in lines - html += '
  • ' + - '' + (i + 1) + '' + lines[i] + '
  • '; - - html += '
'; - - this.gcode = html; + this.gcode = data.trimRight().split(/\r?\n/); this.last_file = file; Vue.nextTick(this.update_gcode_line); diff --git a/src/py/bbctrl/Web.py b/src/py/bbctrl/Web.py index 6bcf721..72448bb 100644 --- a/src/py/bbctrl/Web.py +++ b/src/py/bbctrl/Web.py @@ -5,6 +5,8 @@ import tornado import sockjs.tornado import logging import datetime +import shutil +import tarfile import bbctrl @@ -36,6 +38,29 @@ class ConfigResetHandler(bbctrl.APIHandler): def put_ok(self): self.ctrl.config.reset() +class FirmwareUpdateHandler(bbctrl.APIHandler): + def prepare(self): pass + + + def put(self): + # Only allow this function in dev mode + if not os.path.exists('/etc/bbctrl-dev-mode'): + self.send_error(403, message = 'Not in dev mode') + return + + firmware = self.request.files['firmware'][0] + + if not os.path.exists('firmware'): os.mkdir('firmware') + + with open('firmware/update.tar.bz2', 'wb') as f: + f.write(firmware['body']) + + import subprocess + ret = subprocess.Popen(['update-bbctrl']) + + self.write_json('ok') + + class UpgradeHandler(bbctrl.APIHandler): def put_ok(self): import subprocess @@ -168,6 +193,7 @@ class Web(tornado.web.Application): (r'/api/config/download', ConfigDownloadHandler), (r'/api/config/save', ConfigSaveHandler), (r'/api/config/reset', ConfigResetHandler), + (r'/api/firmware/update', FirmwareUpdateHandler), (r'/api/upgrade', UpgradeHandler), (r'/api/file(/.+)?', bbctrl.FileHandler), (r'/api/home', HomeHandler), diff --git a/src/resources/config-template.json b/src/resources/config-template.json index 9c50a2f..14f3bb1 100644 --- a/src/resources/config-template.json +++ b/src/resources/config-template.json @@ -17,10 +17,10 @@ "code": "pm" }, "drive-current": { - "type": "float", + "type": "aloat", "min": 0, "max": 8, - "unit": "A", + "unit": "amps", "default": 2, "code": "dc" }, @@ -28,7 +28,7 @@ "type": "float", "min": 0, "max": 8, - "unit": "A", + "unit": "Amps", "default": 0, "code": "ic" } diff --git a/src/stylus/style.styl b/src/stylus/style.styl index 757b7bb..ee556f2 100644 --- a/src/stylus/style.styl +++ b/src/stylus/style.styl @@ -297,6 +297,7 @@ body margin 0 .gcode, .history + font-family courier clear both overflow auto width 100% @@ -304,12 +305,12 @@ body min-width 99% height 200px padding 0.25em - white-space pre + white-space nowrap &.placeholder color #aaa - .gcode ul + .gcode ul, .history ul margin 0 padding 0 list-style none @@ -326,6 +327,9 @@ body &.highlight background-color #eaeaea + .history ul li + cursor pointer + .mdi clear both white-space nowrap -- 2.27.0