diff --git a/STEP800_firmware/STEP800_firmware.ino b/STEP800_firmware/STEP800_firmware.ino index 2b44baa..4b32af8 100644 --- a/STEP800_firmware/STEP800_firmware.ino +++ b/STEP800_firmware/STEP800_firmware.ino @@ -33,8 +33,8 @@ const char *firmwareName = "STEP800_PROTO_BLACK"; #else const char *firmwareName = "STEP800_R1"; #endif -const uint8_t firmwareVersion[3] = {1,0,0}; -const uint8_t applicableConfigVersion[2] = {1,0}; +const uint8_t firmwareVersion[3] = {1,0,1}; +const uint8_t applicableConfigVersion[2] = {1,1}; // L6470vh #ifdef PROTOTYPE_BLACK @@ -357,7 +357,7 @@ void updateServo(uint32_t currentTimeMicros) { integral[i] += ((error + eZ1[i]) / 2.0f); if (integral[i] > 1500.0f) integral[i] = 1500.0f; else if (integral[i] < -1500.0f) integral[i] = -1500.0f; - if (abs(error) > position_tolerance) { + if (fabsf(error) > position_tolerance) { double diff = error - eZ1[i]; spd = error * kP[i] + integral[i] * kI[i] + diff * kD[i]; diff --git a/STEP800_firmware/diagnosis.cpp b/STEP800_firmware/diagnosis.cpp index cc12e82..d4b4f73 100644 --- a/STEP800_firmware/diagnosis.cpp +++ b/STEP800_firmware/diagnosis.cpp @@ -283,6 +283,7 @@ void printConfigurations() { printAllData(F("dec"), dec); printAllData(F("maxSpeed"), maxSpeed); printAllData(F("fullStepSpeed"), fullStepSpeed); + printAllData("minSpeed", minSpeed); printHeader(F("Voltage mode")); printAllData(F("kvalHold"), kvalHold); @@ -294,7 +295,8 @@ void printConfigurations() { printAllData(F("accFinalSlope"), accFinalSlope); printAllData(F("decFinalSlope"), decFinalSlope); printAllData(F("stallThreshold"), stallThreshold); - printAllData(F("lowSpeedOptimize"), lowSpeedOptimize); + showAllBools("lowSpeedOptimizeEnable", lowSpeedOptimizeEnable); + printAllData("lowSpeedOptimizeThreshold", lowSpeedOptimizeThreshold); printHeader(F("Servo mode")); printAllData(F("kP"), kP); diff --git a/STEP800_firmware/globals.cpp b/STEP800_firmware/globals.cpp index 9d59fe9..3a8dc26 100644 --- a/STEP800_firmware/globals.cpp +++ b/STEP800_firmware/globals.cpp @@ -119,7 +119,8 @@ uint8_t microStepMode[NUM_OF_MOTOR]; // STEP_MODE uint16_t slewRate[NUM_OF_MOTOR]; // GATECFG1 uint8_t slewRateNum[NUM_OF_MOTOR]; // [0]114, [1]220, [2]400, [3]520, [4]790, [5]980. -float lowSpeedOptimize[NUM_OF_MOTOR]; +bool lowSpeedOptimizeEnable[NUM_OF_MOTOR]; +float lowSpeedOptimizeThreshold[NUM_OF_MOTOR]; bool electromagnetBrakeEnable[NUM_OF_MOTOR]; uint16_t brakeTransitionDuration[NUM_OF_MOTOR]; @@ -127,6 +128,7 @@ float acc[NUM_OF_MOTOR], dec[NUM_OF_MOTOR], maxSpeed[NUM_OF_MOTOR], + minSpeed[NUM_OF_MOTOR], fullStepSpeed[NUM_OF_MOTOR]; // Servo mode diff --git a/STEP800_firmware/globals.h b/STEP800_firmware/globals.h index 9853524..12c6fa2 100644 --- a/STEP800_firmware/globals.h +++ b/STEP800_firmware/globals.h @@ -255,13 +255,15 @@ extern uint8_t microStepMode[NUM_OF_MOTOR]; // STEP_MODE extern uint16_t slewRate[NUM_OF_MOTOR]; // GATECFG1 extern uint8_t slewRateNum[NUM_OF_MOTOR]; // [0]114, [1]220, [2]400, [3]520, [4]790, [5]980. -extern float lowSpeedOptimize[NUM_OF_MOTOR]; +extern float lowSpeedOptimizeThreshold[NUM_OF_MOTOR]; +extern bool lowSpeedOptimizeEnable[NUM_OF_MOTOR]; extern bool electromagnetBrakeEnable[NUM_OF_MOTOR]; extern uint16_t brakeTransitionDuration[NUM_OF_MOTOR]; extern float acc[NUM_OF_MOTOR], dec[NUM_OF_MOTOR], maxSpeed[NUM_OF_MOTOR], + minSpeed[NUM_OF_MOTOR], fullStepSpeed[NUM_OF_MOTOR]; // Servo mode diff --git a/STEP800_firmware/loadConfig.cpp b/STEP800_firmware/loadConfig.cpp index e4e3458..aac5054 100644 --- a/STEP800_firmware/loadConfig.cpp +++ b/STEP800_firmware/loadConfig.cpp @@ -147,11 +147,13 @@ void loadConfig() { JsonArray speedProfile_dec = speedProfile["dec"]; JsonArray speedProfile_maxSpeed = speedProfile["maxSpeed"]; JsonArray speedProfile_fullStepSpeed = speedProfile["fullStepSpeed"]; + JsonArray speedProfile_minSpeed = speedProfile["minSpeed"]; for (i = 0; i < NUM_OF_MOTOR; i++) { acc[i] = speedProfile_acc[i] | 1000.; dec[i] = speedProfile_dec[i] | 1000.; maxSpeed[i] = speedProfile_maxSpeed[i] | 650.; fullStepSpeed[i] = speedProfile_fullStepSpeed[i] | 15610.; + minSpeed[i] = speedProfile_minSpeed[i] | 0.; } // Voltage mode @@ -165,6 +167,7 @@ void loadConfig() { JsonArray voltageMode_FN_SLP_ACC = voltageMode["FN_SLP_ACC"]; JsonArray voltageMode_FN_SLP_DEC = voltageMode["FN_SLP_DEC"]; JsonArray voltageMode_STALL_TH = voltageMode["STALL_TH"]; + JsonArray voltageMode_lowSpeedOptimizeEnable = voltageMode["lowSpeedOptimizeEnable"]; JsonArray voltageMode_lowSpeedOptimize = voltageMode["lowSpeedOptimize"]; for (i = 0; i < NUM_OF_MOTOR; i++) { kvalHold[i] = voltageMode_KVAL_HOLD[i] | 0; @@ -177,7 +180,8 @@ void loadConfig() { decFinalSlope[i] = voltageMode_FN_SLP_DEC[i] | 0x29; // stallThreshold[i] = voltageMode_STALL_TH[i] | 0x1F; stallThreshold[i] = voltageMode_STALL_TH[i] | 0x7F; - lowSpeedOptimize[i] = voltageMode_lowSpeedOptimize[i] | 20.; + lowSpeedOptimizeEnable[i] = voltageMode_lowSpeedOptimizeEnable[i] | false; + lowSpeedOptimizeThreshold[i] = voltageMode_lowSpeedOptimize[i] | 20.; } // Current mode diff --git a/STEP800_firmware/oscListeners.cpp b/STEP800_firmware/oscListeners.cpp index 1e2ff6d..7fa644a 100644 --- a/STEP800_firmware/oscListeners.cpp +++ b/STEP800_firmware/oscListeners.cpp @@ -52,6 +52,7 @@ void OSCMsgReceive() { // speed bMsgRouted |= msgIN.route("/setSpeedProfile", setSpeedProfile); bMsgRouted |= msgIN.route("/setMaxSpeed", setMaxSpeed); + bMsgRouted |= msgIN.route("/setMinSpeed", setMinSpeed); bMsgRouted |= msgIN.route("/setFullstepSpeed", setFullstepSpeed); bMsgRouted |= msgIN.route("/getFullstepSpeed", getFullstepSpeed); bMsgRouted |= msgIN.route("/setAcc", setAcc); @@ -116,6 +117,7 @@ void OSCMsgReceive() { bMsgRouted |= msgIN.route("/getStallThreshold", getStallThreshold); bMsgRouted |= msgIN.route("/setOverCurrentThreshold", setOverCurrentThreshold); bMsgRouted |= msgIN.route("/getOverCurrentThreshold", getOverCurrentThreshold); + bMsgRouted |= msgIN.route("/enableLowSpeedOptimize", enableLowSpeedOptimize); bMsgRouted |= msgIN.route("/setLowSpeedOptimizeThreshold", setLowSpeedOptimizeThreshold); bMsgRouted |= msgIN.route("/getLowSpeedOptimizeThreshold", getLowSpeedOptimizeThreshold); @@ -732,16 +734,18 @@ void getOverCurrentThreshold(OSCMessage& msg, int addrOffset) { void setLowSpeedOptimizeThreshold(OSCMessage& msg, int addrOffset) { uint8_t motorID = getInt(msg, 0); - float _minSpeed = getFloat(msg,1); + float _lowSpdOptThreshold = getFloat(msg,1); if(isCorrectMotorId(motorID)) { motorID -= MOTOR_ID_FIRST; - stepper[motorID].setMinSpeed(_minSpeed); - lowSpeedOptimize[motorID] = _minSpeed; + lowSpeedOptimizeThreshold[motorID] = _lowSpdOptThreshold; + if (lowSpeedOptimizeEnable[motorID]) + stepper[motorID].setMinSpeed(_lowSpdOptThreshold); } else if (motorID == MOTOR_ID_ALL) { for (uint8_t i = 0; i < NUM_OF_MOTOR; i++) { - stepper[i].setMinSpeed(_minSpeed); - lowSpeedOptimize[i] = _minSpeed; + lowSpeedOptimizeThreshold[i] = _lowSpdOptThreshold; + if (lowSpeedOptimizeEnable[i]) + stepper[i].setMinSpeed(_lowSpdOptThreshold); } } } @@ -762,7 +766,7 @@ void getLowSpeedOptimizeThreshold(uint8_t motorId) { bool optimizationEnabled = (stepper[motorId].getParam(MIN_SPEED) & (1 << 12)) > 0; OSCMessage newMes("/lowSpeedOptimizeThreshold"); newMes.add((int32_t)motorId + MOTOR_ID_FIRST); - newMes.add(stepper[motorId].getMinSpeed()); + newMes.add(lowSpeedOptimizeEnable[motorId]); newMes.add(optimizationEnabled); Udp.beginPacket(destIp, outPort); newMes.send(Udp); @@ -771,6 +775,32 @@ void getLowSpeedOptimizeThreshold(uint8_t motorId) { turnOnTXL(); } +void enableLowSpeedOptimize(OSCMessage& msg, int addrOffset) { + uint8_t motorID = getInt(msg, 0); + bool state = getBool(msg, 1); + if(isCorrectMotorId(motorID)) { + motorID -= MOTOR_ID_FIRST; + stepper[motorID].setLoSpdOpt(state); + lowSpeedOptimizeEnable[motorID] = state; + if (state) { + stepper[motorID].setMinSpeed(lowSpeedOptimizeThreshold[motorID]); + } else { + stepper[motorID].setMinSpeed(minSpeed[motorID]); + } + } + else if (motorID == MOTOR_ID_ALL) { + for (uint8_t i = 0; i < NUM_OF_MOTOR; i++) { + stepper[i].setLoSpdOpt(state); + lowSpeedOptimizeEnable[i] = state; + if (state) { + stepper[i].setMinSpeed(lowSpeedOptimizeThreshold[i]); + } else { + stepper[i].setMinSpeed(minSpeed[i]); + } + } + } +} + void setBemfParam(OSCMessage& msg, int addrOffset) { uint8_t motorID = getInt(msg, 0); uint16_t intSpeed = constrain(getInt(msg, 1), 0, 0x3FFF); @@ -1429,7 +1459,26 @@ void setMaxSpeed(OSCMessage& msg, int addrOffset) { } } } -// MIN_SPEED register is set by setLowSpeedOptimizeThreshold function. + +void setMinSpeed(OSCMessage& msg, int addrOffset) { + uint8_t motorID = getInt(msg, 0); + float _minSpeed = getFloat(msg, 1); + if(isCorrectMotorId(motorID)) { + motorID -= MOTOR_ID_FIRST; + minSpeed[motorID] = _minSpeed; + if (!lowSpeedOptimizeEnable[motorID]) { + stepper[motorID].setMinSpeed(_minSpeed); + } + } + else if (motorID == MOTOR_ID_ALL) { + for (uint8_t i = 0; i < NUM_OF_MOTOR; i++) { + minSpeed[i] = _minSpeed; + if (!lowSpeedOptimizeEnable[motorID]) { + stepper[i].setMinSpeed(_minSpeed); + } + } + } +} void setFullstepSpeed(OSCMessage& msg, int addrOffset) { uint8_t motorID = getInt(msg, 0); diff --git a/STEP800_firmware/oscListeners.h b/STEP800_firmware/oscListeners.h index bab861a..d033a54 100644 --- a/STEP800_firmware/oscListeners.h +++ b/STEP800_firmware/oscListeners.h @@ -72,6 +72,7 @@ void getOverCurrentThreshold(OSCMessage& msg, int addrOffset); void setLowSpeedOptimizeThreshold(OSCMessage& msg, int addrOffset); void getLowSpeedOptimizeThreshold(OSCMessage& msg, int addrOffset); void getLowSpeedOptimizeThreshold(uint8_t motorId); +void enableLowSpeedOptimize(OSCMessage& msg, int addrOffset); void setBemfParam(OSCMessage& msg, int addrOffset); void getBemfParam(OSCMessage& msg, int addrOffset); void getBemfParam(uint8_t motorId); @@ -119,6 +120,8 @@ void getKval(uint8_t motorId); // speed_commands_osc_listener void setSpeedProfile(OSCMessage& msg, int addrOffset); void setMaxSpeed(OSCMessage& msg, int addrOffset); +void setMinSpeed(OSCMessage& msg, int addrOffset); +void getMinSpeed(OSCMessage& msg, int addrOffset); void setFullstepSpeed(OSCMessage& msg, int addrOffset); void getFullstepSpeed(OSCMessage& msg, int addrOffset); void setAcc(OSCMessage& msg, int addrOffset); diff --git a/STEP800_firmware/utils.cpp b/STEP800_firmware/utils.cpp index e65402f..c2ef366 100644 --- a/STEP800_firmware/utils.cpp +++ b/STEP800_firmware/utils.cpp @@ -75,8 +75,12 @@ void resetMotorDriver(uint8_t deviceID) { stepper[deviceID].resetDev(); stepper[deviceID].configStepMode(microStepMode[deviceID]); stepper[deviceID].setMaxSpeed(maxSpeed[deviceID]); - stepper[deviceID].setLoSpdOpt(true); - stepper[deviceID].setMinSpeed(lowSpeedOptimize[deviceID]); // Low speed optimization threshold + stepper[deviceID].setLoSpdOpt(lowSpeedOptimizeEnable[deviceID]); + if (lowSpeedOptimizeEnable[deviceID]) { + stepper[deviceID].setMinSpeed(lowSpeedOptimizeThreshold[deviceID]); // Low speed optimization threshold + } else { + stepper[deviceID].setMinSpeed(minSpeed[deviceID]); + } stepper[deviceID].setFullSpeed(fullStepSpeed[deviceID]); stepper[deviceID].setAcc(acc[deviceID]); stepper[deviceID].setDec(dec[deviceID]); diff --git a/configTool/css/temp.css b/configTool/css/temp.css deleted file mode 100644 index e9c4ab3..0000000 --- a/configTool/css/temp.css +++ /dev/null @@ -1,10 +0,0 @@ -input[disabled="disabled"] { - display: none; -} -select[disabled="disabled"] { - display: none; -} - -div.rowLabel p[disabled="disabled"] { - display: none; -} \ No newline at end of file diff --git a/configTool/index.html b/configTool/index.html index 8b45fa6..3440526 100644 --- a/configTool/index.html +++ b/configTool/index.html @@ -12,7 +12,7 @@
-

STEP800 configuration tool rev 1.0

+

STEP800 configuration tool rev 1.1

@@ -41,7 +41,7 @@

Information

- +
  • @@ -62,7 +62,7 @@

    Network

  • -

    IP address of STEP400.

    +

    IP address of STEP800.

    @@ -83,7 +83,7 @@

    Network

  • -

    Specify where STEP400 responses have to be sent.

    +

    Specify where STEP800 responses have to be sent.

    @@ -131,14 +131,14 @@

    Network

  • -

    Port number for the communication from PC to STEP400.

    +

    Port number for the communication from PC to STEP800.

  • -

    Port number for the communication from STEP400 to PC.

    +

    Port number for the communication from STEP800 to PC.

  • @@ -152,7 +152,7 @@

    Network

  • -

    MAC address of STEP400.

    +

    MAC address of STEP800.

    @@ -174,21 +174,21 @@

    Network

  • -

    Send /booted message when STEP400 is booted or restarted.

    +

    Send /booted message when STEP800 is booted or restarted.

  • -

    If this box is checked, STEP400 can send response messages even before receiving the /setDestIp message.

    +

    If this box is checked, STEP800 can send response messages even before receiving the /setDestIp message.

  • -

    Enable error messages from STEP400.

    +

    Enable error messages from STEP800.

  • @@ -1033,6 +1033,25 @@

    Speed Profile

    step/s/s
    +
  • +
    + +

    This value defines a minimum speed of the motor, and also releaseSw speed which is a part of the homing procedure.

    +
    +
    + + + + + + + + + + step/s +
    +
  • +
    @@ -1221,7 +1240,25 @@

    Voltage Mode

  • - + +

    Reduce the phase current distortion at a very low speed using a small driving voltage. When this optimization is enabled, speed profile minimum speed is forced to zero.

    +
    +
    + + + + + + + + + + +
    +
  • +
  • +
    +

    The speed threshold below which the low speed compensation works.

    diff --git a/configTool/js/main.js b/configTool/js/main.js index 389b31b..c5ea54a 100644 --- a/configTool/js/main.js +++ b/configTool/js/main.js @@ -56,7 +56,8 @@ window.addEventListener('DOMContentLoaded', function() { acc: document.querySelectorAll("input[name='acc']"), dec: document.querySelectorAll("input[name='dec']"), maxSpeed: document.querySelectorAll("input[name='maxSpeed']"), - fullStepSpeed: document.querySelectorAll("input[name='fullStepSpeed']") + fullStepSpeed: document.querySelectorAll("input[name='fullStepSpeed']"), + minSpeed: document.querySelectorAll("input[name='minSpeed']") }, voltageMode: { KVAL_HOLD: document.querySelectorAll("input[name='KVAL_HOLD']"), @@ -68,6 +69,7 @@ window.addEventListener('DOMContentLoaded', function() { FN_SLP_ACC: document.querySelectorAll("input[name='FN_SLP_ACC']"), FN_SLP_DEC: document.querySelectorAll("input[name='FN_SLP_DEC']"), STALL_TH: document.querySelectorAll("input[name='STALL_TH']"), + lowSpeedOptimizeEnable: document.querySelectorAll("input[name='lowSpeedOptimizeEnable']"), lowSpeedOptimize: document.querySelectorAll("input[name='lowSpeedOptimize']") }, servoMode: { diff --git a/configTool/v1.0/css/styles.css b/configTool/v1.0/css/styles.css new file mode 100644 index 0000000..e1b98f1 --- /dev/null +++ b/configTool/v1.0/css/styles.css @@ -0,0 +1,77 @@ +@charset 'utf-8'; + +/* base +--------------------------------------------------- */ +* { margin: 0; padding: 0; } +html { box-sizing: border-box; } +img { max-width: 100%; height: auto; } +h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: normal; } +ul, ol { list-style: none; } +i, em { font-style: normal; } +@media screen and (max-width:59.99em) { + html { font-size: 56.25%; } +} +@media screen and (min-width:60em) { + html { font-size: 62.5%; } +} +body { font-family: BlinkMacSystemFont, -apple-system, "Helvetica Neue", Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif; font-size: 1.6rem; line-height: 1; color: #363636; } +@media (-webkit-min-device-pixel-ratio:2) { + body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } +} +::-moz-selection { background: #363636; color: #fff; text-shadow: none; } +::selection { background: #363636; color: #fff; text-shadow: none; } + +/* content +--------------------------------------------------- */ +.container { margin: 8rem auto; width: 92.19%; max-width: 96rem; min-width: 88rem; } +.line-ponoor { position: relative; width: 100%; height: 0.4rem; border: 0; background-color: #8d3f2b; background-image: linear-gradient(117deg, #8d3f2b 0% 55%, #363636 55% 70%, #e6e6e6 70% 82%, #ff6720 82% 95%, #fbde40 95% 100%); } +h1 { display: -webkit-flex; display: flex; -webkit-align-items: flex-end; align-items: flex-end; margin-bottom: 6.4rem; font-weight: 600; font-size: 4.8rem; } +h1 > span { display: inline-block; margin-bottom: 0.5rem; margin-left: 1.6rem; padding: 0.4rem 1.2rem; background-color: #eee; border-radius: 2.4rem; font-size: 1.6rem; } +.heading-wrap { margin-top: 6.4rem; margin-bottom: 4rem; display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; } +.heading-wrap > h2 { margin-right: 3.2rem; font-weight: 600; font-size: 3.2rem; } +.file-input input[type="file"] { display: none; } +.file-input label { display: inline-block; position: relative; cursor: pointer; padding: 1rem 2rem; border-radius: 0.2rem; margin-right: 0.8rem; background-color: #ff6720; color: #fff; font-weight: 600; font-size: 1.4rem; transition: opacity 0.2s ease-out; } +.file-input label:after { content: "No file selected"; color: #808080; font-size: 1.4rem; height: 2rem; line-height: 2rem; position: absolute; right: -12.4rem; top: calc(50% - 1rem); } +.file-input label:hover { opacity: 0.8; } +.file-input label.changed:after { content: ""; } +.file-input .filename { font-size: 1.4rem; } +.file-export { margin-top: 8rem; width: 100%; } +.file-export > input[type="submit"] { width: 28rem; height: 100%; border: 0; outline: none; padding: 2rem 0; background-color: #ff6720; border-radius: 0.2rem; font-weight: 600; font-size: 2rem; color: #fff; text-align: center; cursor: pointer; transition: opacity 0.2s ease-out; } +.file-export > input[type="submit"]:hover { opacity: 0.8; } +.input-setting { padding: 0.8rem 1.2rem; border: 1px solid #eee; border-radius: 0.2rem; } +.input-setting > .label { display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; font-weight: 600; } +.input-setting > .label input { margin-left: 0.8rem; } +.input-list { border-bottom: 1px solid #eee; } +.input-list > li { display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; } +.input-list > li > .input-label { width: calc(100% - 66rem); padding-right: 0.5rem; } +.input-list > li > .input-items { width: 66rem; } +.input-list > li.heading { padding-bottom: 0.8rem; border-bottom: 1px solid #eee; font-weight: 600; font-size: 1.4rem; } +.input-list > li:not(.heading) { padding: 1.2rem 0; border-top: 1px solid #eee; } +.input-label { position: relative; font-weight: 600; } +.input-label > .hint { border-bottom: 1px dotted rgba(54, 54, 54, 0.6); cursor: pointer; position: relative; } +.input-label > .hint:hover + .tooltip { display: block; } +.input-label > .tooltip { display: none; position: absolute; left: 0.8rem; top: 3.2rem; z-index: 9999; max-width: 80%; padding: 1.2rem 1.6rem; color: #fff; background-color: #555; border-radius: 0.2rem; font-size: 1.4rem; line-height: 1.5; } +.input-label > .tooltip::after { width: 100%; content: ""; display: block; position: absolute; left: 0.8rem; top: -8px; border-top: 8px solid transparent; border-left: 8px solid #555; } +.input-items { display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; } +.input-items > p, .input-items > select, .input-items > input[type="text"], .input-items > input[type="number"] { margin-right: 0.2rem; } +.input-items > p, .input-items > select { width: 12rem; } +.input-items > input[type="text"] { width: 22.8rem; } +.input-items > input[type="number"] { width: 11rem; } +.input-items > input[type="text"], .input-items > input[type="number"] { outline: none; padding: 0.5rem 0.2rem 0.5rem 0.6rem; background-color: #fff; border: 0.1rem solid #d3d3d3; border-radius: 0.2rem; font-size: 1.4rem; } +.input-items > input[type="text"]:focus, .input-items > input[type="number"]:focus { box-shadow: inset 0 0 2px 0 #ff6720; } +.input-items > input[type="checkbox"] { width: 1.6rem; margin-right: 6.6rem; } +.input-items > input[disabled="disabled"], .input-items > select[disabled="disabled"], .input-items > p[disabled="disabled"] { display: none; } +.input-items > input[readonly="readonly"] { outline: 0; background-color: #eee; cursor: not-allowed; } +.input-items > input[readonly="readonly"]:focus { box-shadow: none; } +.input-items > .btn { display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; margin-left: 1.2rem; font-size: 1.4rem; line-height: 1.6rem; } +.input-items > .btn > input { margin-right: 0.6rem; } +.input-items.-sm > input[type="text"], .input-items.-sm > input[type="number"] { width: 4.8rem; } +.input-list.-motor .input-items > .unit { display: block; font-size: 0.8em; } +.input-list.-motor .input-items > p, .input-list.-motor .input-items > select, .input-list.-motor .input-items > input[type="text"], .input-list.-motor .input-items > input[type="number"] { margin-right: 0.4rem; } +.input-list.-motor .input-items > p, .input-list.-motor .input-items > select { width: 7.2rem; } +.input-list.-motor .input-items > input[type="number"] { width: 6.2rem; } +.input-list.-motor .input-items > input[type="checkbox"] { width: 1.6rem; margin-right: 6rem; } + +/* IE */ +_:-ms-lang(x), .file-input > label { display: none; } +_:-ms-lang(x), .file-input > input[type="file"] { width: auto; } diff --git a/configTool/v1.0/index.html b/configTool/v1.0/index.html new file mode 100644 index 0000000..8b45fa6 --- /dev/null +++ b/configTool/v1.0/index.html @@ -0,0 +1,1332 @@ + + + + + + STEP800 configuration tool + + + + +
    +
    + + +

    STEP800 configuration tool rev 1.0

    + +
    + + +
    + +
    + +
    +

    Information

    +
    +
      +
    • +
      + +

      The name of this configuration for your reference.

      +
      +
      + +
      +
    • +
    • +
      + +

      The version number of the loaded config file. Read only.

      +
      +
      + + +
      +
    • +
    • +
      + +

      Target product name of the loaded config file. Read only.

      +
      +
      + +
      +
    • +
    + +
    +

    Network

    +
    +
      +
    • +
      + +

      IP address of STEP400.

      +
      +
      + + + + +
      +
    • +
    • +
      + +

      If this box is checked, ID is added to the last byte of the IP address. ID is set by the DIP switch.

      +
      +
      + +
      +
    • +
    • +
      + +

      Specify where STEP400 responses have to be sent.

      +
      +
      + + + + +
      +
    • +
    • +
      + +

      Usually first 3 bytes are same as myIp, and the last byte is 1.

      +
      +
      + + + + +
      +
    • +
    • +
      + +

      Usually first 3 bytes are same as myIp, and the last byte is 1.

      +
      +
      + + + + +
      +
    • +
    • +
      + +

      This defines the scope of the network. If you're not sure, specify 255.255.255.0.

      +
      +
      + + + + +
      +
    • +
    • +
      + +

      Port number for the communication from PC to STEP400.

      +
      +
      +
    • +
    • +
      + +

      Port number for the communication from STEP400 to PC.

      +
      +
      +
    • +
    • +
      + +

      If this box is checked, ID is added to Outgoing port number. ID is set by the DIP switch.

      +
      +
      +
    • +
    • +
      + +

      MAC address of STEP400.

      +
      +
      + + + + + + + +
      +
    • +
    • +
      + +

      If this box is checked, ID is added to the last byte of the MAC address. ID is set by the DIP switch.

      +
      +
      +
    • +
    • +
      + +

      Send /booted message when STEP400 is booted or restarted.

      +
      +
      +
    • +
    • +
      + +

      If this box is checked, STEP400 can send response messages even before receiving the /setDestIp message.

      +
      +
      +
    • +
    • +
      + +

      Enable error messages from STEP400.

      +
      +
      +
    • +
    + +
    +

    Alarm and Report

    +
    + +
    +
    +
      +
    • +
      Parameter
      +
      +

      motor 1-8

      +

      motor 1

      +

      motor 2

      +

      motor 3

      +

      motor 4

      +

      motor 5

      +

      motor 6

      +

      motor 7

      +

      motor 8

      + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the BUSY status changes.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the HiZ status changes.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the home sensor input changes.

      +
      +
      + + + + + + + + + + +
      +
    • + +
    • +
      + +

      A notification message will be sent automatically when the motor direction changes.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the motor status changes.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the home sensor input trigger event (falling edge) happens.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the under voltage lock out happens.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the thermal status of the driver chip changes.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the over current shutdown happens.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      A notification message will be sent automatically when the motor stalling detected.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      Threshold of the over current detection.

      +
      +
      + + + + + + + + + + +
      +
    • +
    + +
    +

    Driver Settings

    +
    + +
    +
    +
      +
    • +
      Parameter
      +
      +

      motor 1-8

      +

      motor 1

      +

      motor 2

      +

      motor 3

      +

      motor 4

      +

      motor 5

      +

      motor 6

      +

      motor 7

      +

      motor 8

      + +
      +
    • +
    • +
      + +

      Start a homing procedure when the system booted.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      The initial homing direction. This depends on the mechanical structure and the motor wiring.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      The initial homing speed.

      +
      +
      + + + + + + + + + + step/s +
      +
    • +
    • +
      + +

      If this box is not checked, the home sensor input causes hard stop of the motor.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      Prohibit motion commands for the homing direction when the home switch activating.

      +
      +
      + + + + + + + + + + +
      +
    • + +
    • +
      + +

      A timeout duration for the "/goUntil" command. Set 0 for disable the timeout.

      +
      +
      + + + + + + + + + + ms +
      +
    • +
    • +
      + +

      A timeout duration for the "/releaseSw" command. Set 0 for disable the timeout.

      +
      +
      + + + + + + + + + + ms +
      +
    • +
    • +
      + +

      Specifies the number of microstep divisions.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      Check this box if you are using a optional electromagnetic brake board.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      The overlap duration between activating the motor and engaging the brake.

      +
      +
      + + + + + + + + + + ms +
      +
    • +
    + +
    +

    Speed Profile

    +
    + +
    +
    +
      +
    • +
      Parameter
      +
      +

      motor 1-8

      +

      motor 1

      +

      motor 2

      +

      motor 3

      +

      motor 4

      +

      motor 5

      +

      motor 6

      +

      motor 7

      +

      motor 8

      + +
      +
    • +
    • +
      + +

      Acceleration of the motor

      +
      +
      + + + + + + + + + + step/s/s +
      +
    • +
    • +
      + +

      Deceleration of the motor

      +
      +
      + + + + + + + + + + step/s/s +
      +
    • +
    • +
      + +

      Max speed of the motor

      +
      +
      + + + + + + + + + + step/s/s +
      +
    • +
    • +
      + +

      Threshold speed to transit from microstep to fullstep.

      +
      +
      + + + + + + + + + + step/s/s +
      +
    • +
    + +
    +

    Voltage Mode

    +
    + +
    +
    +
      +
    • +
      Parameter
      +
      +

      motor 1-8

      +

      motor 1

      +

      motor 2

      +

      motor 3

      +

      motor 4

      +

      motor 5

      +

      motor 6

      +

      motor 7

      +

      motor 8

      + +
      +
    • +
    • +
      + +

      KVAL_HOLD register contains the KVAL value that is assigned to the PWM modulators when the motor is stopped.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      KVAL_RUN register contains the KVAL value that is assigned to the PWM modulators when the motor is running at constant speed.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      KVAL_ACC register contains the starting KVAL value that can be assigned to the PWM modulators during acceleration.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      KVAL_DEC register contains the starting KVAL value that can be assigned to the PWM modulators during deceleration.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      INT_SPEED register contains the speed value at which the BEMF compensation curve changes slope.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      ST_SLP register contains the BEMF compensation curve slope that is used when the speed is lower than the intersect speed.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      FN_SLP_ACC register contains the BEMF compensation curve slope that is used when the speed is greater than the intersect speed during acceleration.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      FN_SLP_DEC register contains the BEMF compensation curve slope that is used when the speed is greater than the intersect speed during deceleration.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      Threshold current for the stall detection.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      The speed threshold below which the low speed compensation works.

      +
      +
      + + + + + + + + + + step/s +
      +
    • +
    + +
    +

    Servo Mode

    +
    + +
    +
    +
      +
    • +
      Parameter
      +
      +

      motor 1-8

      +

      motor 1

      +

      motor 2

      +

      motor 3

      +

      motor 4

      +

      motor 5

      +

      motor 6

      +

      motor 7

      +

      motor 8

      + +
      +
    • +
    • +
      + +

      The coefficients for the proportional term of the PID controller of the servo mode.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + +

      The coefficients for the integral term of the PID controller of the servo mode.

      +
      +
      + + + + + + + + + + +
      +
    • +
    • +
      + kD +

      The coefficients for the derivative term of the PID controller of the servo mode.

      +
      +
      + + + + + + + + + + +
      +
    • +
    + +
    + +
    + +
    + + +
    +
    + + + + \ No newline at end of file diff --git a/configTool/v1.0/js/main.js b/configTool/v1.0/js/main.js new file mode 100644 index 0000000..389b31b --- /dev/null +++ b/configTool/v1.0/js/main.js @@ -0,0 +1,255 @@ +window.addEventListener('DOMContentLoaded', function() { + var NUM_MOTOR = 8; + var inputElements = { + information: { + configName: document.querySelector("input[name='configName']"), + configVersion: document.querySelectorAll("input[name='configVersion']"), + targetProduct: document.querySelector("input[name='targetProduct']") + }, + network: { + myIp: document.querySelectorAll("input[name='myIp']"), + isMyIpAddId: document.querySelector("input[name='isMyIpAddId']"), + destIp: document.querySelectorAll("input[name='destIp']"), + dns: document.querySelectorAll("input[name='dns']"), + gateway: document.querySelectorAll("input[name='gateway']"), + subnet: document.querySelectorAll("input[name='subnet']"), + inPort: document.querySelector("input[name='inPort']"), + outPort: document.querySelector("input[name='outPort']"), + isOutPortAddId: document.querySelector("input[name='isOutPortAddId']"), + mac: document.querySelectorAll("input[name='mac']"), + isMacAddId: document.querySelector("input[name='isMacAddId']"), + bootedMsgEnable: document.querySelector("input[name='bootedMsgEnable']"), + canSendMsgBeforeDestIp: document.querySelector("input[name='canSendMsgBeforeDestIp']"), + reportError: document.querySelector("input[name='reportError']") + }, + alarmAndReport: { + reportBUSY: document.querySelectorAll("input[name='reportBUSY']"), + reportHiZ: document.querySelectorAll("input[name='reportHiZ']"), + reportHomeSwStatus: document.querySelectorAll("input[name='reportHomeSwStatus']"), + // reportLimitSwStatus: document.querySelectorAll("input[name='reportLimitSwStatus']"), + reportDir: document.querySelectorAll("input[name='reportDir']"), + reportMotorStatus: document.querySelectorAll("input[name='reportMotorStatus']"), + reportSwEvn: document.querySelectorAll("input[name='reportSwEvn']"), + reportUVLO: document.querySelectorAll("input[name='reportUVLO']"), + reportThermalStatus: document.querySelectorAll("input[name='reportThermalStatus']"), + reportOCD: document.querySelectorAll("input[name='reportOCD']"), + reportStall: document.querySelectorAll("input[name='reportStall']"), + OCThreshold: document.querySelectorAll("select[name='OCThreshold']") + }, + driverSettings: { + homingAtStartup : document.querySelectorAll("input[name='homingAtStartup']"), + homingDirection : document.querySelectorAll("select[name='homingDirection']"), + homingSpeed: document.querySelectorAll("input[name='homingSpeed']"), + homeSwMode: document.querySelectorAll("input[name='homeSwMode']"), + prohibitMotionOnHomeSw: document.querySelectorAll("input[name='prohibitMotionOnHomeSw']"), + // limitSwMode: document.querySelectorAll("input[name='limitSwMode']"), + // prohibitMotionOnLimitSw: document.querySelectorAll("input[name='prohibitMotionOnLimitSw']"), + goUntilTimeout: document.querySelectorAll("input[name='goUntilTimeout']"), + releaseSwTimeout: document.querySelectorAll("input[name='releaseSwTimeout']"), + stepMode: document.querySelectorAll("select[name='stepMode']"), + // isCurrentMode: document.querySelectorAll("input[name='isCurrentMode']"), + // slewRate: document.querySelectorAll("select[name='slewRate']"), + electromagnetBrakeEnable: document.querySelectorAll("input[name='electromagnetBrakeEnable']"), + brakeTransitionDuration: document.querySelectorAll("input[name='brakeTransitionDuration']") + }, + speedProfile: { + acc: document.querySelectorAll("input[name='acc']"), + dec: document.querySelectorAll("input[name='dec']"), + maxSpeed: document.querySelectorAll("input[name='maxSpeed']"), + fullStepSpeed: document.querySelectorAll("input[name='fullStepSpeed']") + }, + voltageMode: { + KVAL_HOLD: document.querySelectorAll("input[name='KVAL_HOLD']"), + KVAL_RUN: document.querySelectorAll("input[name='KVAL_RUN']"), + KVAL_ACC: document.querySelectorAll("input[name='KVAL_ACC']"), + KVAL_DEC: document.querySelectorAll("input[name='KVAL_DEC']"), + INT_SPEED: document.querySelectorAll("input[name='INT_SPEED']"), + ST_SLP: document.querySelectorAll("input[name='ST_SLP']"), + FN_SLP_ACC: document.querySelectorAll("input[name='FN_SLP_ACC']"), + FN_SLP_DEC: document.querySelectorAll("input[name='FN_SLP_DEC']"), + STALL_TH: document.querySelectorAll("input[name='STALL_TH']"), + lowSpeedOptimize: document.querySelectorAll("input[name='lowSpeedOptimize']") + }, + servoMode: { + kP: document.querySelectorAll("input[name='kP']"), + kI: document.querySelectorAll("input[name='kI']"), + kD: document.querySelectorAll("input[name='kD']") + } + }; + + var targetAllInputs = { + alarmAndReport: document.querySelector("input.alarmAndReport[name='targetAll']"), + driverSettings: document.querySelector("input.driverSettings[name='targetAll']"), + speedProfile: document.querySelector("input.speedProfile[name='targetAll']"), + voltageMode: document.querySelector("input.voltageMode[name='targetAll']"), + //currentMode: document.querySelector("input.currentMode[name='targetAll']"), + servoMode: document.querySelector("input.servoMode[name='targetAll']") + } + var rowLabelTexts = { + alarmAndReport: document.querySelectorAll("div.rowLabel.alarmAndReport p"), + driverSettings: document.querySelectorAll("div.rowLabel.driverSettings p"), + speedProfile: document.querySelectorAll("div.rowLabel.speedProfile p"), + voltageMode: document.querySelectorAll("div.rowLabel.voltageMode p"), + //currentMode: document.querySelectorAll("div.rowLabel.currentMode p"), + servoMode: document.querySelectorAll("div.rowLabel.servoMode p") + } + + var form = document.querySelector("form"); + var loadInput = document.querySelector("input[name='load']"); + + for (catName in targetAllInputs) { + targetAllInputs[catName].addEventListener('change', changeTargetAll, false); + targetAllInputs[catName].dispatchEvent(new Event('change', { 'bubbles': true })); + } + + function changeTargetAll(e) { + var catInputs = inputElements[e.target.className]; + + for(paramName in catInputs) { + var paramInputs = catInputs[paramName]; + if(e.target.checked) { + paramInputs[0].removeAttribute('disabled'); + for (var i = 0; i < NUM_MOTOR; i ++) { + paramInputs[i + 1].setAttribute('disabled', 'disabled'); + } + } else { + paramInputs[0].setAttribute('disabled', 'disabled'); + for (var i = 0; i < NUM_MOTOR; i ++) { + paramInputs[i + 1].removeAttribute('disabled'); + } + } + } + if (e.target.checked) { + rowLabelTexts[e.target.className][0].removeAttribute('disabled'); + for (var i = 0; i < NUM_MOTOR; i ++) { + rowLabelTexts[e.target.className][i + 1].setAttribute('disabled', 'disabled'); + } + } else { + rowLabelTexts[e.target.className][0].setAttribute('disabled', 'disabled'); + for (var i = 0; i < NUM_MOTOR; i ++) { + rowLabelTexts[e.target.className][i + 1].removeAttribute('disabled'); + } + } + } + + form.addEventListener('submit', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var configObject = {}; + for(catName in inputElements) { + configObject[catName] = {}; + for (paramName in inputElements[catName]) { + if (catName === 'network' || catName === 'information') { + if (0 < inputElements[catName][paramName].length) { + configObject[catName][paramName] = []; + for (var i = 0; i < inputElements[catName][paramName].length; i++) { + configObject[catName][paramName].push(getInputValue(inputElements[catName][paramName][i])); + } + } else { + configObject[catName][paramName] = getInputValue(inputElements[catName][paramName]); + } + } else { + var isTargetAll = targetAllInputs[catName].checked; + for (paramName in inputElements[catName]) { + configObject[catName][paramName] = []; + for (var i = 0; i < NUM_MOTOR; i ++) { + if (isTargetAll) { + configObject[catName][paramName].push(getInputValue(inputElements[catName][paramName][0])); + } else { + configObject[catName][paramName].push(getInputValue(inputElements[catName][paramName][i+1])); + } + } + } + } + } + } + function getInputValue(elm) { + if (elm.tagName === 'INPUT') { + + var type = elm.getAttribute("type"); + switch (type) { + case 'number': + return Number(elm.value); + break; + case 'text': + return elm.value; + break; + case 'checkbox': + return elm.checked; + break; + default: + return 0; + break; + } + } else if (elm.tagName === 'SELECT') { + return Number(elm.value); + } + } + + + var configJson = JSON.stringify(configObject, null, '\t'); + var configBlob = new Blob([configJson], {type: 'text/plain'}); + var a = document.createElement('a'); + a.href = URL.createObjectURL(configBlob); + a.download = 'config.txt'; + a.click(); + }, false); + + loadInput.addEventListener('change', function(e) { + var fileReader = new FileReader(); + fileReader.readAsText(e.target.files[0]); + + fileReader.onload = function(e) { + var jsonObject = JSON.parse(e.target.result); + + for(catName in inputElements) { + if (jsonObject[catName] !== undefined) { + for (paramName in inputElements[catName]) { + if (jsonObject[catName][paramName] !== undefined) { + if (catName === 'network' || catName === 'information') { + if (0 < inputElements[catName][paramName].length) { + for (var i = 0; i < inputElements[catName][paramName].length; i++) { + setInputValue(inputElements[catName][paramName][i], jsonObject[catName][paramName][i]); + } + } else { + setInputValue(inputElements[catName][paramName], jsonObject[catName][paramName]); + } + } else { + for (paramName in inputElements[catName]) { + for (var i = 0; i < NUM_MOTOR; i ++) { + setInputValue(inputElements[catName][paramName][i+1], jsonObject[catName][paramName][i]); + } + } + } + } + } + } + } + function setInputValue(elm, val) { + + if (elm.tagName === 'INPUT') { + + var type = elm.getAttribute('type'); + switch (type) { + case 'number': + elm.value = val; + break; + case 'text': + elm.value = val; + break; + case 'checkbox': + elm.checked = val; + break; + default: + return 0; + break; + } + } else if (elm.tagName === 'SELECT') { + elm.selectedIndex = val; + } + } + } + + }, false) +}); \ No newline at end of file diff --git a/configTool/v1.0/js/styles.js b/configTool/v1.0/js/styles.js new file mode 100644 index 0000000..54029ae --- /dev/null +++ b/configTool/v1.0/js/styles.js @@ -0,0 +1,54 @@ +// file-input +const formInputs = document.getElementsByClassName("file"); +const length = formInputs.length; +for (let i = 0; i < length; i++) { + formInputs[i].onchange = function () { + const file = this.files[0].name; + const label = this.nextElementSibling; + if (!label.classList.contains("changed")) { + const span = document.createElement("span"); + span.className = "filename"; + this.parentNode.appendChild(span); + label.classList.add("changed"); + } + label.nextElementSibling.innerHTML = file; + }; +} + +// mac address hexadecimal -> decimal +function dec() { + let val = document.querySelectorAll("input[name='mac']"); + val.forEach(function(elem){ + let hex = elem.value; + let decimal = parseInt(hex,16); + elem.value = decimal; + }); +} + +function hex() { + let val = document.querySelectorAll("input[name='mac']"); + val.forEach(function(elem){ + let decimal = parseInt(elem.value); + let hex = decimal.toString(16).toUpperCase(); + elem.value = hex; + }); +} + +window.onload = function () { + let elmbtn = document.getElementById('btn'); + elmbtn.onclick = function () { + if (this.checked == true) { + hex(); + } else { + dec(); + } + } + + let expbtn = document.getElementById('export'); + expbtn.onclick = function () { + if (elmbtn.checked == true) { + elmbtn.checked = false; + dec(); + } + } +} \ No newline at end of file diff --git a/firmware-platformIO/STEP800_firmware/src/diagnosis.cpp b/firmware-platformIO/STEP800_firmware/src/diagnosis.cpp index cc12e82..d4b4f73 100644 --- a/firmware-platformIO/STEP800_firmware/src/diagnosis.cpp +++ b/firmware-platformIO/STEP800_firmware/src/diagnosis.cpp @@ -283,6 +283,7 @@ void printConfigurations() { printAllData(F("dec"), dec); printAllData(F("maxSpeed"), maxSpeed); printAllData(F("fullStepSpeed"), fullStepSpeed); + printAllData("minSpeed", minSpeed); printHeader(F("Voltage mode")); printAllData(F("kvalHold"), kvalHold); @@ -294,7 +295,8 @@ void printConfigurations() { printAllData(F("accFinalSlope"), accFinalSlope); printAllData(F("decFinalSlope"), decFinalSlope); printAllData(F("stallThreshold"), stallThreshold); - printAllData(F("lowSpeedOptimize"), lowSpeedOptimize); + showAllBools("lowSpeedOptimizeEnable", lowSpeedOptimizeEnable); + printAllData("lowSpeedOptimizeThreshold", lowSpeedOptimizeThreshold); printHeader(F("Servo mode")); printAllData(F("kP"), kP); diff --git a/firmware-platformIO/STEP800_firmware/src/globals.cpp b/firmware-platformIO/STEP800_firmware/src/globals.cpp index 9d59fe9..3a8dc26 100644 --- a/firmware-platformIO/STEP800_firmware/src/globals.cpp +++ b/firmware-platformIO/STEP800_firmware/src/globals.cpp @@ -119,7 +119,8 @@ uint8_t microStepMode[NUM_OF_MOTOR]; // STEP_MODE uint16_t slewRate[NUM_OF_MOTOR]; // GATECFG1 uint8_t slewRateNum[NUM_OF_MOTOR]; // [0]114, [1]220, [2]400, [3]520, [4]790, [5]980. -float lowSpeedOptimize[NUM_OF_MOTOR]; +bool lowSpeedOptimizeEnable[NUM_OF_MOTOR]; +float lowSpeedOptimizeThreshold[NUM_OF_MOTOR]; bool electromagnetBrakeEnable[NUM_OF_MOTOR]; uint16_t brakeTransitionDuration[NUM_OF_MOTOR]; @@ -127,6 +128,7 @@ float acc[NUM_OF_MOTOR], dec[NUM_OF_MOTOR], maxSpeed[NUM_OF_MOTOR], + minSpeed[NUM_OF_MOTOR], fullStepSpeed[NUM_OF_MOTOR]; // Servo mode diff --git a/firmware-platformIO/STEP800_firmware/src/globals.h b/firmware-platformIO/STEP800_firmware/src/globals.h index 9853524..12c6fa2 100644 --- a/firmware-platformIO/STEP800_firmware/src/globals.h +++ b/firmware-platformIO/STEP800_firmware/src/globals.h @@ -255,13 +255,15 @@ extern uint8_t microStepMode[NUM_OF_MOTOR]; // STEP_MODE extern uint16_t slewRate[NUM_OF_MOTOR]; // GATECFG1 extern uint8_t slewRateNum[NUM_OF_MOTOR]; // [0]114, [1]220, [2]400, [3]520, [4]790, [5]980. -extern float lowSpeedOptimize[NUM_OF_MOTOR]; +extern float lowSpeedOptimizeThreshold[NUM_OF_MOTOR]; +extern bool lowSpeedOptimizeEnable[NUM_OF_MOTOR]; extern bool electromagnetBrakeEnable[NUM_OF_MOTOR]; extern uint16_t brakeTransitionDuration[NUM_OF_MOTOR]; extern float acc[NUM_OF_MOTOR], dec[NUM_OF_MOTOR], maxSpeed[NUM_OF_MOTOR], + minSpeed[NUM_OF_MOTOR], fullStepSpeed[NUM_OF_MOTOR]; // Servo mode diff --git a/firmware-platformIO/STEP800_firmware/src/loadConfig.cpp b/firmware-platformIO/STEP800_firmware/src/loadConfig.cpp index e4e3458..aac5054 100644 --- a/firmware-platformIO/STEP800_firmware/src/loadConfig.cpp +++ b/firmware-platformIO/STEP800_firmware/src/loadConfig.cpp @@ -147,11 +147,13 @@ void loadConfig() { JsonArray speedProfile_dec = speedProfile["dec"]; JsonArray speedProfile_maxSpeed = speedProfile["maxSpeed"]; JsonArray speedProfile_fullStepSpeed = speedProfile["fullStepSpeed"]; + JsonArray speedProfile_minSpeed = speedProfile["minSpeed"]; for (i = 0; i < NUM_OF_MOTOR; i++) { acc[i] = speedProfile_acc[i] | 1000.; dec[i] = speedProfile_dec[i] | 1000.; maxSpeed[i] = speedProfile_maxSpeed[i] | 650.; fullStepSpeed[i] = speedProfile_fullStepSpeed[i] | 15610.; + minSpeed[i] = speedProfile_minSpeed[i] | 0.; } // Voltage mode @@ -165,6 +167,7 @@ void loadConfig() { JsonArray voltageMode_FN_SLP_ACC = voltageMode["FN_SLP_ACC"]; JsonArray voltageMode_FN_SLP_DEC = voltageMode["FN_SLP_DEC"]; JsonArray voltageMode_STALL_TH = voltageMode["STALL_TH"]; + JsonArray voltageMode_lowSpeedOptimizeEnable = voltageMode["lowSpeedOptimizeEnable"]; JsonArray voltageMode_lowSpeedOptimize = voltageMode["lowSpeedOptimize"]; for (i = 0; i < NUM_OF_MOTOR; i++) { kvalHold[i] = voltageMode_KVAL_HOLD[i] | 0; @@ -177,7 +180,8 @@ void loadConfig() { decFinalSlope[i] = voltageMode_FN_SLP_DEC[i] | 0x29; // stallThreshold[i] = voltageMode_STALL_TH[i] | 0x1F; stallThreshold[i] = voltageMode_STALL_TH[i] | 0x7F; - lowSpeedOptimize[i] = voltageMode_lowSpeedOptimize[i] | 20.; + lowSpeedOptimizeEnable[i] = voltageMode_lowSpeedOptimizeEnable[i] | false; + lowSpeedOptimizeThreshold[i] = voltageMode_lowSpeedOptimize[i] | 20.; } // Current mode diff --git a/firmware-platformIO/STEP800_firmware/src/main.cpp b/firmware-platformIO/STEP800_firmware/src/main.cpp index 2b44baa..4b32af8 100644 --- a/firmware-platformIO/STEP800_firmware/src/main.cpp +++ b/firmware-platformIO/STEP800_firmware/src/main.cpp @@ -33,8 +33,8 @@ const char *firmwareName = "STEP800_PROTO_BLACK"; #else const char *firmwareName = "STEP800_R1"; #endif -const uint8_t firmwareVersion[3] = {1,0,0}; -const uint8_t applicableConfigVersion[2] = {1,0}; +const uint8_t firmwareVersion[3] = {1,0,1}; +const uint8_t applicableConfigVersion[2] = {1,1}; // L6470vh #ifdef PROTOTYPE_BLACK @@ -357,7 +357,7 @@ void updateServo(uint32_t currentTimeMicros) { integral[i] += ((error + eZ1[i]) / 2.0f); if (integral[i] > 1500.0f) integral[i] = 1500.0f; else if (integral[i] < -1500.0f) integral[i] = -1500.0f; - if (abs(error) > position_tolerance) { + if (fabsf(error) > position_tolerance) { double diff = error - eZ1[i]; spd = error * kP[i] + integral[i] * kI[i] + diff * kD[i]; diff --git a/firmware-platformIO/STEP800_firmware/src/oscListeners.cpp b/firmware-platformIO/STEP800_firmware/src/oscListeners.cpp index 1e2ff6d..7fa644a 100644 --- a/firmware-platformIO/STEP800_firmware/src/oscListeners.cpp +++ b/firmware-platformIO/STEP800_firmware/src/oscListeners.cpp @@ -52,6 +52,7 @@ void OSCMsgReceive() { // speed bMsgRouted |= msgIN.route("/setSpeedProfile", setSpeedProfile); bMsgRouted |= msgIN.route("/setMaxSpeed", setMaxSpeed); + bMsgRouted |= msgIN.route("/setMinSpeed", setMinSpeed); bMsgRouted |= msgIN.route("/setFullstepSpeed", setFullstepSpeed); bMsgRouted |= msgIN.route("/getFullstepSpeed", getFullstepSpeed); bMsgRouted |= msgIN.route("/setAcc", setAcc); @@ -116,6 +117,7 @@ void OSCMsgReceive() { bMsgRouted |= msgIN.route("/getStallThreshold", getStallThreshold); bMsgRouted |= msgIN.route("/setOverCurrentThreshold", setOverCurrentThreshold); bMsgRouted |= msgIN.route("/getOverCurrentThreshold", getOverCurrentThreshold); + bMsgRouted |= msgIN.route("/enableLowSpeedOptimize", enableLowSpeedOptimize); bMsgRouted |= msgIN.route("/setLowSpeedOptimizeThreshold", setLowSpeedOptimizeThreshold); bMsgRouted |= msgIN.route("/getLowSpeedOptimizeThreshold", getLowSpeedOptimizeThreshold); @@ -732,16 +734,18 @@ void getOverCurrentThreshold(OSCMessage& msg, int addrOffset) { void setLowSpeedOptimizeThreshold(OSCMessage& msg, int addrOffset) { uint8_t motorID = getInt(msg, 0); - float _minSpeed = getFloat(msg,1); + float _lowSpdOptThreshold = getFloat(msg,1); if(isCorrectMotorId(motorID)) { motorID -= MOTOR_ID_FIRST; - stepper[motorID].setMinSpeed(_minSpeed); - lowSpeedOptimize[motorID] = _minSpeed; + lowSpeedOptimizeThreshold[motorID] = _lowSpdOptThreshold; + if (lowSpeedOptimizeEnable[motorID]) + stepper[motorID].setMinSpeed(_lowSpdOptThreshold); } else if (motorID == MOTOR_ID_ALL) { for (uint8_t i = 0; i < NUM_OF_MOTOR; i++) { - stepper[i].setMinSpeed(_minSpeed); - lowSpeedOptimize[i] = _minSpeed; + lowSpeedOptimizeThreshold[i] = _lowSpdOptThreshold; + if (lowSpeedOptimizeEnable[i]) + stepper[i].setMinSpeed(_lowSpdOptThreshold); } } } @@ -762,7 +766,7 @@ void getLowSpeedOptimizeThreshold(uint8_t motorId) { bool optimizationEnabled = (stepper[motorId].getParam(MIN_SPEED) & (1 << 12)) > 0; OSCMessage newMes("/lowSpeedOptimizeThreshold"); newMes.add((int32_t)motorId + MOTOR_ID_FIRST); - newMes.add(stepper[motorId].getMinSpeed()); + newMes.add(lowSpeedOptimizeEnable[motorId]); newMes.add(optimizationEnabled); Udp.beginPacket(destIp, outPort); newMes.send(Udp); @@ -771,6 +775,32 @@ void getLowSpeedOptimizeThreshold(uint8_t motorId) { turnOnTXL(); } +void enableLowSpeedOptimize(OSCMessage& msg, int addrOffset) { + uint8_t motorID = getInt(msg, 0); + bool state = getBool(msg, 1); + if(isCorrectMotorId(motorID)) { + motorID -= MOTOR_ID_FIRST; + stepper[motorID].setLoSpdOpt(state); + lowSpeedOptimizeEnable[motorID] = state; + if (state) { + stepper[motorID].setMinSpeed(lowSpeedOptimizeThreshold[motorID]); + } else { + stepper[motorID].setMinSpeed(minSpeed[motorID]); + } + } + else if (motorID == MOTOR_ID_ALL) { + for (uint8_t i = 0; i < NUM_OF_MOTOR; i++) { + stepper[i].setLoSpdOpt(state); + lowSpeedOptimizeEnable[i] = state; + if (state) { + stepper[i].setMinSpeed(lowSpeedOptimizeThreshold[i]); + } else { + stepper[i].setMinSpeed(minSpeed[i]); + } + } + } +} + void setBemfParam(OSCMessage& msg, int addrOffset) { uint8_t motorID = getInt(msg, 0); uint16_t intSpeed = constrain(getInt(msg, 1), 0, 0x3FFF); @@ -1429,7 +1459,26 @@ void setMaxSpeed(OSCMessage& msg, int addrOffset) { } } } -// MIN_SPEED register is set by setLowSpeedOptimizeThreshold function. + +void setMinSpeed(OSCMessage& msg, int addrOffset) { + uint8_t motorID = getInt(msg, 0); + float _minSpeed = getFloat(msg, 1); + if(isCorrectMotorId(motorID)) { + motorID -= MOTOR_ID_FIRST; + minSpeed[motorID] = _minSpeed; + if (!lowSpeedOptimizeEnable[motorID]) { + stepper[motorID].setMinSpeed(_minSpeed); + } + } + else if (motorID == MOTOR_ID_ALL) { + for (uint8_t i = 0; i < NUM_OF_MOTOR; i++) { + minSpeed[i] = _minSpeed; + if (!lowSpeedOptimizeEnable[motorID]) { + stepper[i].setMinSpeed(_minSpeed); + } + } + } +} void setFullstepSpeed(OSCMessage& msg, int addrOffset) { uint8_t motorID = getInt(msg, 0); diff --git a/firmware-platformIO/STEP800_firmware/src/oscListeners.h b/firmware-platformIO/STEP800_firmware/src/oscListeners.h index bab861a..d033a54 100644 --- a/firmware-platformIO/STEP800_firmware/src/oscListeners.h +++ b/firmware-platformIO/STEP800_firmware/src/oscListeners.h @@ -72,6 +72,7 @@ void getOverCurrentThreshold(OSCMessage& msg, int addrOffset); void setLowSpeedOptimizeThreshold(OSCMessage& msg, int addrOffset); void getLowSpeedOptimizeThreshold(OSCMessage& msg, int addrOffset); void getLowSpeedOptimizeThreshold(uint8_t motorId); +void enableLowSpeedOptimize(OSCMessage& msg, int addrOffset); void setBemfParam(OSCMessage& msg, int addrOffset); void getBemfParam(OSCMessage& msg, int addrOffset); void getBemfParam(uint8_t motorId); @@ -119,6 +120,8 @@ void getKval(uint8_t motorId); // speed_commands_osc_listener void setSpeedProfile(OSCMessage& msg, int addrOffset); void setMaxSpeed(OSCMessage& msg, int addrOffset); +void setMinSpeed(OSCMessage& msg, int addrOffset); +void getMinSpeed(OSCMessage& msg, int addrOffset); void setFullstepSpeed(OSCMessage& msg, int addrOffset); void getFullstepSpeed(OSCMessage& msg, int addrOffset); void setAcc(OSCMessage& msg, int addrOffset); diff --git a/firmware-platformIO/STEP800_firmware/src/utils.cpp b/firmware-platformIO/STEP800_firmware/src/utils.cpp index e65402f..c2ef366 100644 --- a/firmware-platformIO/STEP800_firmware/src/utils.cpp +++ b/firmware-platformIO/STEP800_firmware/src/utils.cpp @@ -75,8 +75,12 @@ void resetMotorDriver(uint8_t deviceID) { stepper[deviceID].resetDev(); stepper[deviceID].configStepMode(microStepMode[deviceID]); stepper[deviceID].setMaxSpeed(maxSpeed[deviceID]); - stepper[deviceID].setLoSpdOpt(true); - stepper[deviceID].setMinSpeed(lowSpeedOptimize[deviceID]); // Low speed optimization threshold + stepper[deviceID].setLoSpdOpt(lowSpeedOptimizeEnable[deviceID]); + if (lowSpeedOptimizeEnable[deviceID]) { + stepper[deviceID].setMinSpeed(lowSpeedOptimizeThreshold[deviceID]); // Low speed optimization threshold + } else { + stepper[deviceID].setMinSpeed(minSpeed[deviceID]); + } stepper[deviceID].setFullSpeed(fullStepSpeed[deviceID]); stepper[deviceID].setAcc(acc[deviceID]); stepper[deviceID].setDec(dec[deviceID]);