From 0e707c3b56296e86c73d571135aa56b992b8d735 Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Wed, 21 Feb 2018 22:18:38 -0800 Subject: [PATCH] - Fixed bug in move exec that was causing bumping between moves. - Fixed planner bug which could create negative s-curve times. - Hide step and optional pause buttons until they are implemented. - Fixed pausing problems. - Limit number of console messages. - Scrollbar on console view. - Log debug messages to console in developer mode. - Fixed AVR log message source. - Fixed step correction. --- CHANGELOG.md | 11 ++ package.json | 2 +- src/avr/Makefile | 9 +- src/avr/src/exec.c | 3 - src/avr/src/exec.h | 1 - src/avr/src/huanyang.c | 97 ++++++++------ src/avr/src/huanyang.h | 188 +++++++++++++++++++++++++++ src/avr/src/lcd.h | 2 +- src/avr/src/line.c | 148 ++++++++++++--------- src/avr/src/main.c | 5 +- src/avr/src/messages.def | 51 ++++---- src/avr/src/motor.c | 14 +- src/avr/src/state.c | 3 + src/avr/test/Makefile | 2 +- src/avr/test/hal.c | 7 - src/avr/test/planner-test.c | 7 +- src/jade/templates/console.jade | 27 ++-- src/jade/templates/control-view.jade | 5 +- src/js/console.js | 1 + src/py/bbctrl/AVR.py | 13 +- src/py/bbctrl/Messages.py | 14 +- src/py/bbctrl/Planner.py | 2 +- src/py/bbctrl/__init__.py | 7 +- src/stylus/style.styl | 14 +- 24 files changed, 435 insertions(+), 198 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e47a4e4..b8c031d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ Buildbotics CNC Controller Firmware Change Log ============================================== +## v0.3.9 + - Fixed bug in move exec that was causing bumping between moves. + - Fixed planner bug which could create negative s-curve times. + - Hide step and optional pause buttons until they are implemented. + - Fixed pausing problems. + - Limit number of console messages. + - Scrollbar on console view. + - Log debug messages to console in developer mode. + - Fixed AVR log message source. + - Fixed step correction. + ## v0.3.8 - Fixed pwr flags display - Added pwr fault flags to indicators diff --git a/package.json b/package.json index 6de8794..a19dd46 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bbctrl", - "version": "0.3.8", + "version": "0.3.9", "homepage": "http://buildbotics.com/", "repository": "https://github.com/buildbotics/bbctrl-firmware", "license": "GPL-3.0+", diff --git a/src/avr/Makefile b/src/avr/Makefile index 3a234d8..304ef1c 100644 --- a/src/avr/Makefile +++ b/src/avr/Makefile @@ -1,8 +1,7 @@ # Makefile for the project Bulidbotics firmware -PROJECT = bbctrl-avr-firmware -MCU = atxmega192a3u -CLOCK = 32000000 -VERSION = 0.5.0 +PROJECT = bbctrl-avr-firmware +MCU = atxmega192a3u +CLOCK = 32000000 TARGET = $(PROJECT).elf @@ -18,7 +17,7 @@ CFLAGS += -Wno-error=strict-aliasing # for _invsqrt CFLAGS += -std=gnu99 -DF_CPU=$(CLOCK)UL -O3 CFLAGS += -funsigned-bitfields -fpack-struct -fshort-enums -funsigned-char CFLAGS += -MD -MP -MT $@ -MF build/dep/$(@F).d -CFLAGS += -Isrc -DVERSION=\"$(VERSION)\" +CFLAGS += -Isrc # Linker flags LDFLAGS += $(COMMON) -Wl,-u,vfprintf -lprintf_flt -lm diff --git a/src/avr/src/exec.c b/src/avr/src/exec.c index 6a38331..ac9227b 100644 --- a/src/avr/src/exec.c +++ b/src/avr/src/exec.c @@ -93,9 +93,6 @@ stat_t exec_move_to_target(float time, const float target[]) { } -void exec_reset_encoder_counts() {st_set_position(ex.position);} - - stat_t exec_next() { if (!ex.cb && !command_exec()) return STAT_NOP; // Queue empty if (!ex.cb) return STAT_AGAIN; // Non-exec command diff --git a/src/avr/src/exec.h b/src/avr/src/exec.h index bb05dd4..db445b6 100644 --- a/src/avr/src/exec.h +++ b/src/avr/src/exec.h @@ -51,5 +51,4 @@ void exec_set_jerk(float j); void exec_set_cb(exec_cb_t cb); stat_t exec_move_to_target(float time, const float target[]); -void exec_reset_encoder_counts(); stat_t exec_next(); diff --git a/src/avr/src/huanyang.c b/src/avr/src/huanyang.c index 0bd5d35..9e8c88b 100644 --- a/src/avr/src/huanyang.c +++ b/src/avr/src/huanyang.c @@ -39,32 +39,38 @@ #include #include +/* + Huanyang supposedly is not quite Modbus compliant. -enum { - HUANYANG_FUNC_READ = 1, - HUANYANG_FUNC_WRITE, - HUANYANG_CTRL_WRITE, - HUANYANG_CTRL_READ, - HUANYANG_FREQ_WRITE, - HUANYANG_RESERVED_1, - HUANYANG_RESERVED_2, - HUANYANG_LOOP_TEST -}; + Message format is: + + [id][cmd][length][data][checksum] + Where: -enum { - HUANYANG_BASE_FREQ = 4, - HUANYANG_MAX_FREQ = 5, - HUANYANG_MIN_FREQ = 11, - HUANYANG_RATED_MOTOR_VOLTAGE = 141, - HUANYANG_RATED_MOTOR_CURRENT = 142, - HUANYANG_MOTOR_POLE = 143, - HUANYANG_RATED_RPM = 144, -}; + id - 1-byte Peer ID + cmd - 1-byte One of hy_cmd_t + length - 1-byte Length data in bytes + data - length bytes - Command arguments + checksum - 16-bit CRC: x^16 + x^15 + x^2 + 1 (0xa001) initial: 0xffff +*/ + + +// See VFD manual pg56 3.1.3 +typedef enum { + HUANYANG_FUNC_READ = 1, // Use hy_func_addr_t + HUANYANG_FUNC_WRITE, // ? + HUANYANG_CTRL_WRITE, // Use hy_ctrl_state_t + HUANYANG_CTRL_READ, // Use hy_ctrl_addr_t + HUANYANG_FREQ_WRITE, // Write frequency as uint16_t + HUANYANG_RESERVED_1, + HUANYANG_RESERVED_2, + HUANYANG_LOOP_TEST, +} hy_cmd_t; // See VFD manual pg57 3.1.3.d -enum { +typedef enum { HUANYANG_TARGET_FREQ, HUANYANG_ACTUAL_FREQ, HUANYANG_ACTUAL_CURRENT, @@ -73,26 +79,31 @@ enum { HUANYANG_ACV, HUANYANG_CONT, HUANYANG_TEMPERATURE, -}; - - -enum { - HUANYANG_FORWARD = 1, - HUANYANG_STOP = 8, - HUANYANG_REVERSE = 17, -}; +} hy_ctrl_addr_t; -enum { +typedef enum { HUANYANG_RUN = 1 << 0, - HUANYANG_JOG = 1 << 1, - HUANYANG_COMMAND_RF = 1 << 2, - HUANYANG_RUNNING = 1 << 3, - HUANYANG_JOGGING = 1 << 4, - HUANYANG_RUNNING_RF = 1 << 5, - HUANYANG_BRACKING = 1 << 6, - HUANYANG_TRACK_START = 1 << 7, -}; + HUANYANG_FORWARD = 1 << 1, + HUANYANG_REVERSE = 1 << 2, + HUANYANG_STOP = 1 << 3, + HUANYANG_REV_FWD = 1 << 4, + HUANYANG_JOG = 1 << 5, + HUANYANG_JOG_FORWARD = 1 << 6, + HUANYANG_JOG_REVERSE = 1 << 1, +} hy_ctrl_state_t; + + +typedef enum { + HUANYANG_STATUS_RUN = 1 << 0, + HUANYANG_STATUS_JOG = 1 << 1, + HUANYANG_STATUS_COMMAND_REV = 1 << 2, + HUANYANG_STATUS_RUNNING = 1 << 3, + HUANYANG_STATUS_JOGGING = 1 << 4, + HUANYANG_STATUS_JOGGING_REV = 1 << 5, + HUANYANG_STATUS_BRAKING = 1 << 6, + HUANYANG_STATUS_TRACK_START = 1 << 7, +} hy_ctrl_status_t; typedef bool (*next_command_cb_t)(int index); @@ -227,17 +238,17 @@ static bool _update(int index) { switch (index) { case 0: { // Update direction uint8_t state = HUANYANG_STOP; - if (0 < ha.speed) state = HUANYANG_FORWARD; - else if (ha.speed < 0) state = HUANYANG_REVERSE; + if (0 < ha.speed) state = HUANYANG_RUN; + else if (ha.speed < 0) state = HUANYANG_RUN | HUANYANG_REV_FWD; _set_command1(HUANYANG_CTRL_WRITE, state); return true; } - case 1: var = HUANYANG_MAX_FREQ; break; - case 2: var = HUANYANG_MIN_FREQ; break; - case 3: var = HUANYANG_RATED_RPM; break; + case 1: var = HY_PD005_MAX_FREQUENCY; break; + case 2: var = HY_PD011_FREQUENCY_LOWER_LIMIT; break; + case 3: var = HY_PD144_RATED_MOTOR_RPM; break; case 4: { // Update freqency // Compute frequency in Hz @@ -319,7 +330,7 @@ static bool _check_response() { return false; } - // Check return function code matches sent + // Check if response code matches the code we sent if (ha.command[1] != ha.response[1]) { STATUS_WARNING("huanyang: invalid function code, expected=%u got=%u", ha.command[2], ha.response[2]); diff --git a/src/avr/src/huanyang.h b/src/avr/src/huanyang.h index ce908dd..fdc44ff 100644 --- a/src/avr/src/huanyang.h +++ b/src/avr/src/huanyang.h @@ -35,3 +35,191 @@ void hy_set(float speed); void hy_reset(); void hy_rtc_callback(); void hy_stop(); + +/// See Huanyang VFD user manual +typedef enum { + HY_PD000_PARAMETER_LOCK, + HY_PD001_SOURCE_OF_OPERATION_COMMANDS, + HY_PD002_SOURCE_OF_OPERATING_FREQUENCY, + HY_PD003_MAIN_FREQUENCY, + HY_PD004_BASE_FREQUENCY, + HY_PD005_MAX_FREQUENCY, + HY_PD006_INTERMEDIATE_FREQUENCY, + HY_PD007_MIN_FREQUENCY, + HY_PD008_MAX_VOLTAGE, + HY_PD009_INTERMEDIATE_VOLTAGE, + HY_PD010_MIN_VOLTAGE, + HY_PD011_FREQUENCY_LOWER_LIMIT, + HY_PD012_RESERVED, + HY_PD013_PARAMETER_RESET, + HY_PD014_ACCEL_TIME_1, + HY_PD015_DECEL_TIME_1, + HY_PD016_ACCEL_TIME_2, + HY_PD017_DECEL_TIME_2, + HY_PD018_ACCEL_TIME_3, + HY_PD019_DECEL_TIME_3, + HY_PD020_ACCEL_TIME_4, + HY_PD021_DECEL_TIME_4, + HY_PD022_FACTORY_RESERVED, + HY_PD023_REV_ROTATION_SELECT, + HY_PD024_STOP_KEY, + HY_PD025_STARTING_MODE, + HY_PD026_STOPPING_MODE, + HY_PD027_STARTING_FREQUENCY, + HY_PD028_STOPPING_FREQUENCY, + HY_PD029_DC_BRAKING_TIME_AT_START, + HY_PD030_DC_BRAKING_TIME_AT_STOP, + HY_PD031_DC_BRAKING_VOLTAGE_LEVEL, + HY_PD032_FREQUENCY_TRACK_TIME, + HY_PD033_CURRENT_LEVEL_FOR_FREQUENCY_TRACK, + HY_PD034_VOLTAGE_RISE_TIME_FOR_FREQUENCY_TRACK, + HY_PD035_FREQUENCY_STEP_LENGTH, + HY_PD036, + HY_PD037, + HY_PD038, + HY_PD039, + HY_PD040, + HY_PD041_CARRIER_FREQUENCY, + HY_PD042_JOGGING_FREQUENCY, + HY_PD043_S_CURVE_TIME, + HY_PD044_MULTI_INPUT_FOR, + HY_PD045_MULTI_INPUT_REV, + HY_PD046_MULTI_INPUT_RST, + HY_PD047_MULTI_INPUT_SPH, + HY_PD048_MULTI_INPUT_SPM, + HY_PD049_MULTI_INPUT_SPL, + HY_PD050_MULTI_OUTPUT_DRV, + HY_PD051_MULTI_OUTPUT_UPF, + HY_PD052_MULTI_OUTPUT_FA_FB_FC, + HY_PD053_MULTI_OUTPUT_KA_KB, + HY_PD054_MULTI_OUTPUT_AM, + HY_PD055_AM_ANALOG_OUTPUT_GAIN, + HY_PD056_SKIP_FREQUENCY_1, + HY_PD057_SKIP_FREQUENCY_2, + HY_PD058_SKIP_FREQUENCY_3, + HY_PD059_SKIP_FREQUENCY_RANGE, + HY_PD060_UNIFORM_FREQUENCY_1, + HY_PD061_UNIFORM_FREQUENCY_2, + HY_PD062_UNIFORM_FREQUENCY_RANGE, + HY_PD063_TIMER_1_TIME, + HY_PD064_TIMER_2_TIME, + HY_PD065_COUNTING_VALUE, + HY_PD066_INTERMEDIATE_COUNTER, + HY_PD067, + HY_PD068, + HY_PD069, + HY_PD070_ANALOG_INPUT, + HY_PD071_ANALOG_FILTERING_CONSTANT, + HY_PD072_HIGHER_ANALOG_FREQUENCY, + HY_PD073_LOWER_ANALOG_FREQUENCY, + HY_PD074_BIAS_DIRECTION_AT_HIGHER_FREQUENCY, + HY_PD075_BIAS_DIRECTION_AT_LOWER_FREQUENCY, + HY_PD076_ANALOG_NEGATIVE_BIAS_REVERSE, + HY_PD077_UP_DOWN_FUNCTION, + HY_PD078_UP_DOWN_SPEED, + HY_PD079, + HY_PD080_PLC_OPERATION, + HY_PD081_AUTO_PLC, + HY_PD082_PLC_RUNNING_DIRECTION, + HY_PD083, + HY_PD084_PLC_RAMP_TIME, + HY_PD085, + HY_PD086_FREQUENCY_2, + HY_PD087_FREQUENCY_3, + HY_PD088_FREQUENCY_4, + HY_PD089_FREQUENCY_5, + HY_PD090_FREQUENCY_6, + HY_PD091_FREQUENCY_7, + HY_PD092_FREQUENCY_8, + HY_PD093, + HY_PD094, + HY_PD095, + HY_PD096, + HY_PD097, + HY_PD098, + HY_PD099, + HY_PD100, + HY_PD101_TIMER_1, + HY_PD102_TIMER_2, + HY_PD103_TIMER_3, + HY_PD104_TIMER_4, + HY_PD105_TIMER_5, + HY_PD106_TIMER_6, + HY_PD107_TIMER_7, + HY_PD108_TIMER_8, + HY_PD109, + HY_PD110, + HY_PD111, + HY_PD112, + HY_PD113, + HY_PD114, + HY_PD115, + HY_PD116, + HY_PD117_AUTOPLC_MEMORY_FUNCTION, + HY_PD118_OVER_VOLTAGE_STALL_PREVENTION, + HY_PD119_STALL_PREVENTION_LEVEL_AT_RAMP_UP, + HY_PD120_STALL_PREVENTION_LEVEL_AT_CONSTANT_SPEED, + HY_PD121_DECEL_TIME_FOR_STALL_PREVENTION_AT_CONSTANT_SPEED, + HY_PD122_STALL_PREVENTION_LEVEL_AT_DECELERATION, + HY_PD123_OVER_TORQUE_DETECT_MODE, + HY_PD124_OVER_TORQUE_DETECT_LEVEL, + HY_PD125_OVER_TORQUE_DETECT_TIME, + HY_PD126, + HY_PD127, + HY_PD128, + HY_PD129, + HY_PD130_NUMBER_OF_AUXILIARY_PUMP, + HY_PD131_CONTINUOUS_RUNNING_TIME_OF_AUXILIARY_PUMPS, + HY_PD132_INTERLOCKING_TIME_OF_AUXILIARY_PUMP, + HY_PD133_HIGH_SPEED_RUNNING_TIME, + HY_PD134_LOW_SPEED_RUNNING_TIME, + HY_PD135_STOPPING_VOLTAGE_LEVEL, + HY_PD136_LASTING_TIME_OF_STOPPING_VOLTAGE_LEVEL, + HY_PD137_WAKEUP_VOLTAGE_LEVEL, + HY_PD138_SLEEP_FREQUENCY, + HY_PD139_LASTING_TIME_OF_SLEEP_FREQUENCY, + HY_PD140, + HY_PD141_RATED_MOTOR_VOLTAGE, + HY_PD142_RATED_MOTOR_CURRENT, + HY_PD143_MOTOR_POLE_NUMBER, + HY_PD144_RATED_MOTOR_RPM, + HY_PD145_AUTO_TORQUE_COMPENSATION, + HY_PD146_MOTOR_NO_LOAD_CURRENT, + HY_PD147_MOTOR_SLIP_COMPENSATION, + HY_PD148, + HY_PD149, + HY_PD150_AUTO_VOLTAGE_REGULATION, + HY_PD151_AUTO_ENERGY_SAVING, + HY_PD152_FAULT_RESTART_TIME, + HY_PD153_RESTART_AFTER_INSTANTANEOUS_STOP, + HY_PD154_ALLOWABLE_POWER_BREAKDOWN_TIME, + HY_PD155_NUMBER_OF_ABNORMAL_RESTART, + HY_PD156_PROPORTIONAL_CONSTANT, + HY_PD157_INTEGRAL_TIME, + HY_PD158_DIFFERENTIAL_TIME, + HY_PD159_TARGET_VALUE, + HY_PD160_PID_TARGET_VALUE, + HY_PD161_PID_UPPER_LIMIT, + HY_PD162_PID_LOWER_LIMIT, + HY_PD163_COMMUNICATION_ADDRESSES, + HY_PD164_COMMUNICATION_BAUD_RATE, + HY_PD165_COMMUNICATION_DATA_METHOD, + HY_PD166, + HY_PD167, + HY_PD168, + HY_PD169, + HY_PD170_DISPLAY_ITEMS, + HY_PD171_DISPLAY_ITEMS_OPEN, + HY_PD172_FAULT_CLEAR, + HY_PD173, + HY_PD174_RATED_CURRENT_OF_INVERTER, + HY_PD175_INVERTER_MODEL, + HY_PD176_INVERTER_FREQUENCY_STANDARD, + HY_PD177_FAULT_RECORD_1, + HY_PD178_FAULT_RECORD_2, + HY_PD179_FAULT_RECORD_3, + HY_PD180_FAULT_RECORD_4, + HY_PD181_SOFTWARE_VERSION, + HY_PD182_MANUFACTURE_DATE, + HY_PD183_SERIAL_NO, +} hy_func_addr_t; diff --git a/src/avr/src/lcd.h b/src/avr/src/lcd.h index 188bf81..b7369f0 100644 --- a/src/avr/src/lcd.h +++ b/src/avr/src/lcd.h @@ -27,7 +27,7 @@ #pragma once -#include +#include "pgmspace.h" #include diff --git a/src/avr/src/line.c b/src/avr/src/line.c index 826686d..d7c131e 100644 --- a/src/avr/src/line.c +++ b/src/avr/src/line.c @@ -55,16 +55,18 @@ typedef struct { static struct { line_t line; + int section; + bool stop_section; + float current_time; + float offset_time; int seg; - bool stop_seg; - float current_t; - float iD; // Initial segment distance - float iV; // Initial segment velocity - float iA; // Initial segment acceleration + float iD; // Initial section distance + float iV; // Initial section velocity + float iA; // Initial section acceleration float jerk; float dist; -} l = {.current_t = SEGMENT_TIME}; +} l = {.current_time = SEGMENT_TIME}; static void _segment_target(float target[AXES], float d) { @@ -88,21 +90,21 @@ static float _segment_accel(float t) { } -static bool _segment_next() { - while (++l.seg < 7) { - float seg_t = l.line.times[l.seg]; - if (!seg_t) continue; +static bool _section_next() { + while (++l.section < 7) { + float section_time = l.line.times[l.section]; + if (!section_time) continue; - // Check if last seg - bool last_seg = true; - for (int i = l.seg + 1; i < 7; i++) - if (l.line.times[i]) last_seg = false; + // Check if last section + bool last_section = true; + for (int i = l.section + 1; i < 7; i++) + if (l.line.times[i]) last_section = false; - // Check if stop seg - l.stop_seg = last_seg && !l.line.target_vel; + // Check if stop section + l.stop_section = last_section && !l.line.target_vel; // Jerk - switch (l.seg) { + switch (l.section) { case 0: case 6: l.jerk = l.line.max_jerk; break; case 2: case 4: l.jerk = -l.line.max_jerk; break; default: l.jerk = 0; @@ -110,21 +112,25 @@ static bool _segment_next() { exec_set_jerk(l.jerk); // Acceleration - switch (l.seg) { + switch (l.section) { case 1: case 2: l.iA = l.line.max_jerk * l.line.times[0]; break; case 5: case 6: l.iA = -l.line.max_jerk * l.line.times[4]; break; default: l.iA = 0; } exec_set_acceleration(l.iA); - // Skip segs which do not land on a SEGMENT_TIME - if (seg_t < l.current_t && !l.stop_seg) { - l.current_t -= l.line.times[l.seg]; - l.iD = _segment_distance(seg_t); - l.iV = _segment_velocity(seg_t); + // Skip sections which do not land on a SEGMENT_TIME + if (section_time < l.current_time && !l.stop_section) { + l.current_time -= l.line.times[l.section]; + l.iD = _segment_distance(section_time); + l.iV = _segment_velocity(section_time); continue; } + // Setup section time offset and segment counter + l.offset_time = l.current_time; + l.seg = 0; + return true; } @@ -149,7 +155,7 @@ static stat_t _move(float t, float target[AXES], float v, float a) { static stat_t _pause() { - float t = SEGMENT_TIME - l.current_t; + float t = SEGMENT_TIME - l.current_time; float v = exec_get_velocity(); float a = exec_get_acceleration(); float j = l.line.max_jerk; @@ -176,10 +182,9 @@ static stat_t _pause() { l.dist += v * t; if (l.line.length < l.dist) { - // Compute time left in current segment - l.current_t = t - (l.dist - l.line.length) / v; + // Compute time left in current section + l.current_time = t - (l.dist - l.line.length) / v; - exec_set_velocity(l.line.target_vel); exec_set_acceleration(0); exec_set_jerk(0); _done(); @@ -191,7 +196,7 @@ static stat_t _pause() { float target[AXES]; _segment_target(target, l.dist); - l.current_t = 0; + l.current_time = 0; exec_set_jerk(j); return _move(SEGMENT_TIME, target, v, a); @@ -199,64 +204,70 @@ static stat_t _pause() { static stat_t _line_exec() { - if (state_get() == STATE_STOPPING && (l.seg < 4 || l.line.target_vel)) { - if (SEGMENT_TIME < l.current_t) l.current_t = 0; + // Pause if requested. If we are already stopping, just continue. + if (state_get() == STATE_STOPPING && (l.section < 4 || l.line.target_vel)) { + if (SEGMENT_TIME < l.current_time) l.current_time = 0; exec_set_cb(_pause); return _pause(); } - float seg_t = l.line.times[l.seg]; + float section_time = l.line.times[l.section]; - // Adjust time if near a stopping point - float delta = SEGMENT_TIME; - if (l.stop_seg && seg_t - l.current_t < SEGMENT_TIME) { - delta += seg_t - l.current_t; - l.current_t = seg_t; + // Adjust segment time if near a stopping point + float seg_time = SEGMENT_TIME; + if (l.stop_section && section_time - l.current_time < SEGMENT_TIME) { + seg_time += section_time - l.current_time; + l.offset_time += section_time - l.current_time; + l.current_time = section_time; } - // Compute distance and velocity (Must be computed before changing time) - float d = _segment_distance(l.current_t); - float v = _segment_velocity(l.current_t); - float a = _segment_accel(l.current_t); + // Compute distance and velocity. Must be computed before advancing time. + float d = _segment_distance(l.current_time); + float v = _segment_velocity(l.current_time); + float a = _segment_accel(l.current_time); - // Advance time - l.current_t += SEGMENT_TIME; + // Advance time. This is the start time for the next segment. + l.current_time = l.offset_time + ++l.seg * SEGMENT_TIME; - // Check if segment complete - bool lastSeg = false; - if (seg_t < l.current_t) { - l.current_t -= seg_t; - l.iD = _segment_distance(seg_t); - l.iV = _segment_velocity(seg_t); + // Check if section complete + bool lastSection = false; + if (section_time < l.current_time) { + l.current_time -= section_time; + l.iD = _segment_distance(section_time); + l.iV = _segment_velocity(section_time); - // Next segment - lastSeg = !_segment_next(); + // Next section + lastSection = !_section_next(); } // Do move & update exec stat_t status; - if (lastSeg && l.stop_seg) + if (lastSection && l.stop_section) // Stop exactly on target to correct for floating-point errors - status = _move(delta, l.line.target, 0, 0); + status = _move(seg_time, l.line.target, 0, 0); else { // Compute target position from distance float target[AXES]; _segment_target(target, d); - status = _move(delta, target, v, a); + status = _move(seg_time, target, v, a); l.dist = d; } // Release exec if we are done - if (lastSeg) _done(); + if (lastSection) { + if (state_get() == STATE_STOPPING) state_holding(); + exec_set_velocity(l.line.target_vel); + _done(); + } return status; } -void _print_vector(const char *name, float v[AXES]) { +void _print_vector(const char *name, float v[4]) { printf("%s %f %f %f %f\n", name, v[0], v[1], v[2], v[3]); } @@ -290,18 +301,18 @@ stat_t command_line(char *cmd) { bool has_time = false; while (*cmd) { if (*cmd < '0' || '6' < *cmd) break; - int seg = *cmd - '0'; + int section = *cmd - '0'; cmd++; float time; if (!decode_float(&cmd, &time)) return STAT_BAD_FLOAT; - if (time < 0) return STAT_BAD_SEG_TIME; - line.times[seg] = time; + if (time < 0) return STAT_NEGATIVE_SCURVE_TIME; + line.times[section] = time; if (time) has_time = true; } - if (!has_time) return STAT_BAD_SEG_TIME; + if (!has_time) return STAT_ALL_ZERO_SCURVE_TIMES; // Check for end of command if (*cmd) return STAT_INVALID_ARGUMENTS; @@ -338,9 +349,22 @@ void command_line_exec(void *data) { l.iD = l.dist = 0; l.iV = exec_get_velocity(); - // Find first segment - l.seg = -1; - if (!_segment_next()) return; + // Find first section + l.section = -1; + if (!_section_next()) return; + + // Compare start position to actual position + float diff[AXES]; + bool report = false; + exec_get_position(diff); + for (int i = 0; i < AXES; i++) { + diff[i] -= l.line.start[i]; + if (0.1 < fabs(diff[i])) report = true; + } + + if (report) + STATUS_DEBUG("diff: %.4f %.4f %.4f %.4f", + diff[0], diff[1], diff[2], diff[3]); // Set callback exec_set_cb(_line_exec); diff --git a/src/avr/src/main.c b/src/avr/src/main.c index 3ddd612..94b7948 100644 --- a/src/avr/src/main.c +++ b/src/avr/src/main.c @@ -73,13 +73,12 @@ int main() { sei(); // enable interrupts // Splash - fprintf_P(stdout, PSTR("\n{\"firmware\":\"Buildbotics AVR\"," - "\"version\":\"" VERSION "\"}\n")); + fprintf_P(stdout, PSTR("\n{\"firmware\":\"Buildbotics AVR\"}\n")); // Main loop while (true) { hw_reset_handler(); // handle hard reset requests - if (!estop_triggered()) state_callback(); + state_callback(); // manage state command_callback(); // process next command report_callback(); // report changes wdt_reset(); diff --git a/src/avr/src/messages.def b/src/avr/src/messages.def index cd3efbd..ca8bd05 100644 --- a/src/avr/src/messages.def +++ b/src/avr/src/messages.def @@ -25,28 +25,29 @@ \******************************************************************************/ -STAT_MSG(OK, "OK") -STAT_MSG(AGAIN, "Run command again") -STAT_MSG(NOP, "No op") -STAT_MSG(PAUSE, "Pause") -STAT_MSG(INTERNAL_ERROR, "Internal error") -STAT_MSG(ESTOP_USER, "User triggered EStop") -STAT_MSG(ESTOP_SWITCH, "Switch triggered EStop") -STAT_MSG(UNRECOGNIZED_NAME, "Unrecognized command or variable name") -STAT_MSG(INVALID_COMMAND, "Invalid command") -STAT_MSG(INVALID_ARGUMENTS, "Invalid argument(s) to command") -STAT_MSG(TOO_MANY_ARGUMENTS, "Too many arguments to command") -STAT_MSG(TOO_FEW_ARGUMENTS, "Too few arguments to command") -STAT_MSG(COMMAND_NOT_ACCEPTED, "Command not accepted at this time") -STAT_MSG(MACHINE_ALARMED, "Machine alarmed - Command not processed") -STAT_MSG(EXPECTED_MOVE, "A move was expected but none was queued") -STAT_MSG(QUEUE_FULL, "Queue full") -STAT_MSG(QUEUE_EMPTY, "Queue empty") -STAT_MSG(BAD_FLOAT, "Failed to parse float") -STAT_MSG(INVALID_VARIABLE, "Invalid variable") -STAT_MSG(INVALID_VALUE, "Invalid value") -STAT_MSG(READ_ONLY, "Variable is read only") -STAT_MSG(BUFFER_OVERFLOW, "Buffer overflow") -STAT_MSG(BAD_SEG_TIME, "Bad s-curve segment time") -STAT_MSG(SEEK_NOT_ENABLED, "Switch not enabled") -STAT_MSG(SEEK_NOT_FOUND, "Switch not found") +STAT_MSG(OK, "OK") +STAT_MSG(AGAIN, "Run command again") +STAT_MSG(NOP, "No op") +STAT_MSG(PAUSE, "Pause") +STAT_MSG(INTERNAL_ERROR, "Internal error") +STAT_MSG(ESTOP_USER, "User triggered EStop") +STAT_MSG(ESTOP_SWITCH, "Switch triggered EStop") +STAT_MSG(UNRECOGNIZED_NAME, "Unrecognized command or variable name") +STAT_MSG(INVALID_COMMAND, "Invalid command") +STAT_MSG(INVALID_ARGUMENTS, "Invalid argument(s) to command") +STAT_MSG(TOO_MANY_ARGUMENTS, "Too many arguments to command") +STAT_MSG(TOO_FEW_ARGUMENTS, "Too few arguments to command") +STAT_MSG(COMMAND_NOT_ACCEPTED, "Command not accepted at this time") +STAT_MSG(MACHINE_ALARMED, "Machine alarmed - Command not processed") +STAT_MSG(EXPECTED_MOVE, "A move was expected but none was queued") +STAT_MSG(QUEUE_FULL, "Queue full") +STAT_MSG(QUEUE_EMPTY, "Queue empty") +STAT_MSG(BAD_FLOAT, "Failed to parse float") +STAT_MSG(INVALID_VARIABLE, "Invalid variable") +STAT_MSG(INVALID_VALUE, "Invalid value") +STAT_MSG(READ_ONLY, "Variable is read only") +STAT_MSG(BUFFER_OVERFLOW, "Buffer overflow") +STAT_MSG(ALL_ZERO_SCURVE_TIMES, "All zero s-curve times") +STAT_MSG(NEGATIVE_SCURVE_TIME, "Negative s-curve time") +STAT_MSG(SEEK_NOT_ENABLED, "Switch not enabled") +STAT_MSG(SEEK_NOT_FOUND, "Switch not found") diff --git a/src/avr/src/motor.c b/src/avr/src/motor.c index d791d43..3484a56 100644 --- a/src/avr/src/motor.c +++ b/src/avr/src/motor.c @@ -298,15 +298,12 @@ void motor_prep_move(int motor, float time, float target) { // Error correction int16_t correction = abs(m->error); if (MIN_HALF_STEP_CORRECTION <= correction) { - // Allowed step correction is proportional to velocity - int24_t positive_half_steps = half_steps < 0 ? -half_steps : half_steps; - int16_t max_correction = (positive_half_steps >> 5) + 1; - if (max_correction < correction) correction = max_correction; + // Dampen correction oscillation + correction >>= 2; + // Make correction if (m->error < 0) correction = -correction; - half_steps += correction; - m->error -= correction; } // Positive steps from here on @@ -425,11 +422,14 @@ void set_power_mode(int motor, uint8_t value) { char get_motor_axis(int motor) {return motors[motor].axis;} + void set_motor_axis(int motor, uint8_t axis) { if (MOTORS <= motor || AXES <= axis || axis == motors[motor].axis) return; motors[motor].axis = axis; axis_map_motors(); - exec_reset_encoder_counts(); // Reset encoder counts + + // Reset encoder + motor_set_position(motor, exec_get_axis_position(axis)); // Check if this is now a slave motor motors[motor].slave = false; diff --git a/src/avr/src/state.c b/src/avr/src/state.c index ee6016e..ddbf2a8 100644 --- a/src/avr/src/state.c +++ b/src/avr/src/state.c @@ -31,6 +31,7 @@ #include "command.h" #include "stepper.h" #include "spindle.h" +#include "estop.h" #include "report.h" #include @@ -157,6 +158,8 @@ void state_estop() {_set_state(STATE_ESTOPPED);} * - when stopped is honored and starts to run anything in the queue */ void state_callback() { + if (estop_triggered()) return; + if (s.pause_requested || s.flush_requested) { if (s.pause_requested) _set_hold_reason(HOLD_REASON_USER_PAUSE); s.pause_requested = false; diff --git a/src/avr/test/Makefile b/src/avr/test/Makefile index 9425111..06ece7a 100644 --- a/src/avr/test/Makefile +++ b/src/avr/test/Makefile @@ -1,7 +1,7 @@ TESTS=planner-test PLANNER_TEST_SRC = status.c util.c axis.c report.c type.c exec.c base64.c \ - command.c commands.c vars.c state.c line.c + command.c commands.c vars.c state.c line.c scurve.c seek.c PLANNER_TEST_SRC := $(patsubst %,../src/%,$(PLANNER_TEST_SRC)) PLANNER_TEST_SRC += $(wildcard ../src/plan/*.c) planner-test.c hal.c diff --git a/src/avr/test/hal.c b/src/avr/test/hal.c index 8903759..3c3b1b6 100644 --- a/src/avr/test/hal.c +++ b/src/avr/test/hal.c @@ -29,7 +29,6 @@ #include "spindle.h" #include "i2c.h" #include "type.h" -#include "exec.h" #include "cpp_magic.h" #include @@ -154,12 +153,6 @@ stat_t st_prep_line(float time, const float target[]) { ASSERT(-maxTarget < target[i] && target[i] < maxTarget); } - static int32_t line = -1; - if (exec_get_line() != line) { - line = exec_get_line(); - printf("line=%d\n", line); - } - printf("%0.10f, %0.10f, %0.10f, %0.10f\n", time, target[0], target[1], target[2]); diff --git a/src/avr/test/planner-test.c b/src/avr/test/planner-test.c index c5e78d9..ae51a31 100644 --- a/src/avr/test/planner-test.c +++ b/src/avr/test/planner-test.c @@ -60,12 +60,7 @@ int main(int argc, char *argv[]) { switch (status) { case STAT_NOP: break; // No command executed case STAT_AGAIN: continue; // No command executed, try again - - case STAT_OK: // Move executed - //if (!st.move_queued) ALARM(STAT_EXPECTED_MOVE); // No move was queued - //st.move_queued = false; - //st.move_ready = true; - continue; + case STAT_OK: continue; // Move executed default: printf("ERROR: %s\n", status_to_pgmstr(status)); diff --git a/src/jade/templates/console.jade b/src/jade/templates/console.jade index 57993fd..1e5747c 100644 --- a/src/jade/templates/console.jade +++ b/src/jade/templates/console.jade @@ -32,17 +32,18 @@ script#console-template(type="text/x-template") .fa.fa-trash |  Clear - table - tr - th Level - th Source - th Location - th Repeat - th Message + .console-wrapper + table + tr + th Level + th Source + th Location + th Repeat + th Message - tr(v-for="msg in messages", :class="msg.level || 'info'") - td {{msg.level || 'info'}} - td {{msg.source || ''}} - td {{msg.where || ''}} - td {{msg.repeat}} - td {{msg.msg}} + tr(v-for="msg in messages", class="log-{{msg.level || 'info'}}") + td {{msg.level || 'info'}} + td {{msg.source || ''}} + td {{msg.where || ''}} + td {{msg.repeat}} + td {{msg.msg}} diff --git a/src/jade/templates/control-view.jade b/src/jade/templates/control-view.jade index d867a52..02ed565 100644 --- a/src/jade/templates/control-view.jade +++ b/src/jade/templates/control-view.jade @@ -170,11 +170,12 @@ script#control-view-template(type="text/x-template") .fa.fa-stop button.pure-button(title="Pause program at next optional stop (M1).", - @click="optional_pause") + @click="optional_pause", v-if="false") .fa.fa-stop-circle-o button.pure-button(title="Execute one program step.", @click="step", - :disabled="(state.xx != 'READY' && state.xx != 'HOLDING') || !file") + :disabled="(state.xx != 'READY' && state.xx != 'HOLDING') || !file", + v-if="false") .fa.fa-step-forward .tabs diff --git a/src/js/console.js b/src/js/console.js index b29f738..f10b442 100644 --- a/src/js/console.js +++ b/src/js/console.js @@ -63,6 +63,7 @@ module.exports = { else { msg.repeat = 1; messages.unshift(msg); + while (256 < messages.length) messages.pop(); } msg.ts = Date.now(); diff --git a/src/py/bbctrl/AVR.py b/src/py/bbctrl/AVR.py index af60741..ab7c8df 100644 --- a/src/py/bbctrl/AVR.py +++ b/src/py/bbctrl/AVR.py @@ -220,14 +220,14 @@ class AVR(): # AVR logging if 'msg' in msg: level = msg.get('level', 'info') - if 'where' in msg: extra = {'where': msg} + if 'where' in msg: extra = {'where': msg['where']} else: extra = None msg = msg['msg'] - if level == 'info': log.info(msg, extra) - elif level == 'debug': log.debug(msg, extra) - elif level == 'warning': log.warning(msg, extra) - elif level == 'error': log.error(msg, extra) + if level == 'info': log.info(msg, extra = extra) + elif level == 'debug': log.debug(msg, extra = extra) + elif level == 'warning': log.warning(msg, extra = extra) + elif level == 'error': log.error(msg, extra = extra) continue @@ -372,8 +372,7 @@ class AVR(): def unpause(self): - if self.ctrl.state.get('xx', '') != 'HOLDING' or not self._is_busy(): - return + if self.ctrl.state.get('xx', '') != 'HOLDING': return self._i2c_command(Cmd.FLUSH) self._queue_command(Cmd.RESUME) diff --git a/src/py/bbctrl/Messages.py b/src/py/bbctrl/Messages.py index 9ae1bf7..930b628 100644 --- a/src/py/bbctrl/Messages.py +++ b/src/py/bbctrl/Messages.py @@ -35,11 +35,14 @@ log = logging.getLogger('Msgs') class Messages(logging.Handler): def __init__(self, ctrl): - logging.Handler.__init__(self, logging.WARNING) + logging.Handler.__init__(self) self.ctrl = ctrl self.listeners = [] + debug = os.path.exists('/etc/bbctrl-dev-mode') + self.setLevel(logging.DEBUG if debug else logging.WARNING) + logging.getLogger().addHandler(self) @@ -49,10 +52,11 @@ class Messages(logging.Handler): # From logging.Handler def emit(self, record): - msg = dict( - level = record.levelname.lower(), - source = record.name, - msg = record.getMessage()) + if record.levelno == logging.INFO: return + + msg = dict(level = record.levelname.lower(), + source = record.name, + msg = record.getMessage()) if hasattr(record, 'where'): msg['where'] = record.where else: msg['where'] = '%s:%d' % (record.filename, record.lineno) diff --git a/src/py/bbctrl/Planner.py b/src/py/bbctrl/Planner.py index 20a1408..7b6b960 100644 --- a/src/py/bbctrl/Planner.py +++ b/src/py/bbctrl/Planner.py @@ -58,7 +58,7 @@ class Planner(): # Axis mapping for enabled motors axis2motor = {} - for i in range(3): + for i in range(4): if state.get('%dpm' % i, False): axis = 'xyzabc'[int(state.get('%dan' % i))] axis2motor[axis] = i diff --git a/src/py/bbctrl/__init__.py b/src/py/bbctrl/__init__.py index c850668..398000b 100644 --- a/src/py/bbctrl/__init__.py +++ b/src/py/bbctrl/__init__.py @@ -95,14 +95,17 @@ def run(): # Init logging root = logging.getLogger() - root.setLevel(logging.DEBUG if args.verbose else logging.INFO) + level = logging.DEBUG if args.verbose else logging.INFO + root.setLevel(logging.NOTSET) f = logging.Formatter('{levelname[0]}:{name}:{message}', style = '{') - h = logging.StreamHandler() + h = logging.StreamHandler(level) + h.setLevel(level) h.setFormatter(f) root.addHandler(h) if args.log: h = logging.FileHandler(args.log) + h.setLevel(level) h.setFormatter(f) root.addHandler(h) diff --git a/src/stylus/style.styl b/src/stylus/style.styl index ab85243..2b0b06b 100644 --- a/src/stylus/style.styl +++ b/src/stylus/style.styl @@ -369,6 +369,10 @@ body margin 1em .console + .console-wrapper + max-height 400px + overflow-y auto + table width 100% margin 0.5em 0 @@ -383,13 +387,13 @@ body margin 0 0.125em background-color #fff - &.error td + &.log-error td color red - &.warning td + &.log-warning td color orange - &.debug td + &.log-debug td color green .indicators @@ -587,6 +591,10 @@ label.file-upload transform scale(0.75) margin-top -30px + .console + margin-bottom 1em + clear both + @media only screen and (max-width 48em) .header -- 2.27.0