diff --git a/firmware/fab-step/src/drivers/step_a4950.h b/firmware/fab-step/src/drivers/step_a4950.h index 63ec2304a0e1c22238dcc08a2421fd036f51c69d..2e5747583ec74a56b24b76c274c1039e58e9273c 100644 --- a/firmware/fab-step/src/drivers/step_a4950.h +++ b/firmware/fab-step/src/drivers/step_a4950.h @@ -15,7 +15,7 @@ is; no warranty is provided, and users accept all liability. #ifndef STEP_A4950_H_ #define STEP_A4950_H_ -#include <arduino.h> +#include <Arduino.h> // AIN1 PA14 // AIN2 PA15 diff --git a/firmware/fab-step/src/homing.cpp b/firmware/fab-step/src/homing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7896d5025c3745c31e25950541637e2770b1af3d --- /dev/null +++ b/firmware/fab-step/src/homing.cpp @@ -0,0 +1,92 @@ +/* +homing.cpp + +tiny homing routine for fab-step + +Jake Read at the Center for Bits and Atoms +(c) Massachusetts Institute of Technology 2022 + +This work may be reproduced, modified, distributed, performed, and +displayed for any purpose, but must acknowledge the OSAP project. +Copyright is retained and must be preserved. The work is provided as +is; no warranty is provided, and users accept all liability. +*/ + +#include "homing.h" +#include "drivers/step_a4950.h" + +endpoint_t* _homeStateEP; +uint8_t homeState = HOMESTATE_NONE; +uint32_t homeBackoffStepsTaken = 0; + +// home settings +boolean homeDir = true; +unsigned long lastHomeOperation = 0; +unsigned long homeOperationPeriod = 1000; // in us +uint32_t homeBackoffDistance = 100; + +void homeSetup(endpoint_t* homeStateEP){ + // stash this + _homeStateEP = homeStateEP; + // make an input + PORT->Group[LIMIT_PORT].DIRCLR.reg = (1 << LIMIT_PIN); + PORT->Group[LIMIT_PORT].PINCFG[LIMIT_PIN].bit.INEN = 1; + // pullup + PORT->Group[LIMIT_PORT].OUTSET.reg = (1 << LIMIT_PIN); +} + +// return true if limit switch is hit +boolean limitHit(void){ + return (PORT->Group[LIMIT_PORT].IN.reg & (1 << LIMIT_PIN)); +} + +void writeHomeSettings(boolean dir, uint32_t stepsPerSecond, uint32_t offset){ + homeDir = dir; + homeOperationPeriod = 1000000 / stepsPerSecond; + homeBackoffDistance = offset; +} + +uint8_t getHomeState(void){ + return homeState; +} + +void startHomingRoutine(void){ + homeState = HOMESTATE_APPROACH; + endpointWrite(_homeStateEP, &homeState, 1); +} + +void runHomingRoutine(void){ + // run this at a rate... + if(lastHomeOperation + homeOperationPeriod > micros()) return; + lastHomeOperation = micros(); + // state switch; + switch(homeState){ + case HOMESTATE_NONE: + break; + case HOMESTATE_APPROACH: + // check for contact, + if(limitHit()){ + homeState = HOMESTATE_BACKOFF; + endpointWrite(_homeStateEP, &homeState, 1); + homeBackoffStepsTaken = 0; + } else { + step_a4950_dir(homeDir); + step_a4950_step(); + } + break; + case HOMESTATE_BACKOFF: + step_a4950_dir(!homeDir); + step_a4950_step(); + homeBackoffStepsTaken ++; + if(homeBackoffStepsTaken > homeBackoffDistance){ + homeState = HOMESTATE_NONE; + endpointWrite(_homeStateEP, &homeState, 1); + } + break; + default: + // broken, + homeState = HOMESTATE_NONE; + endpointWrite(_homeStateEP, &homeState, 1); + break; + } +} \ No newline at end of file diff --git a/firmware/fab-step/src/homing.h b/firmware/fab-step/src/homing.h new file mode 100644 index 0000000000000000000000000000000000000000..1b56e633c4f06d27c4179fb8d8bb6e42d7f49dc7 --- /dev/null +++ b/firmware/fab-step/src/homing.h @@ -0,0 +1,37 @@ +/* +homing.h + +tiny homing routine for fab-step + +Jake Read at the Center for Bits and Atoms +(c) Massachusetts Institute of Technology 2022 + +This work may be reproduced, modified, distributed, performed, and +displayed for any purpose, but must acknowledge the OSAP project. +Copyright is retained and must be preserved. The work is provided as +is; no warranty is provided, and users accept all liability. +*/ + +#ifndef HOMING_H_ +#define HOMING_H_ + +#include <Arduino.h> +#include "osape-d21/osape/osap/endpoint.h" + +// limit +#define LIMIT_PORT 0 +#define LIMIT_PIN 3 + +// home states +#define HOMESTATE_NONE 0 +#define HOMESTATE_APPROACH 1 +#define HOMESTATE_BACKOFF 2 + +void homeSetup(endpoint_t* homeStateEP); +boolean limitHit(void); +uint8_t getHomeState(void); +void writeHomeSettings(boolean dir, uint32_t stepsPerSecond, uint32_t offset); +void startHomingRoutine(void); +void runHomingRoutine(void); + +#endif \ No newline at end of file diff --git a/firmware/fab-step/src/main.cpp b/firmware/fab-step/src/main.cpp index d15ba6a0f07f85dfc84cc1ca5b1240fc4afeef4a..a2ab555edd0764c649a7dcaccaab49b0f73397dc 100644 --- a/firmware/fab-step/src/main.cpp +++ b/firmware/fab-step/src/main.cpp @@ -3,6 +3,7 @@ #include "config.h" #include "drivers/step_a4950.h" +#include "homing.h" #include "osape-d21/osape/osap/osap.h" #include "osape-d21/vertices/vt_usbSerial.h" @@ -70,6 +71,20 @@ endpoint_t* cScaleEp = osapBuildEndpoint("CScale", onCScaleData); // -------------------------------------------------------- HOME ROUTINE EP_ONDATA_RESPONSES onHomeData(uint8_t* data, uint16_t len){ + chunk_int32 rate = { .bytes = { data[0], data[1], data[2], data[3] } }; + chunk_uint32 offset = { .bytes = { data[4], data[5], data[6], data[7] } }; + // sign of rate is dir, + boolean hdir; + uint32_t hrate; + if(rate.i < 0) { + hdir = false; + hrate = -1 * rate.i; + } else { + hdir = true; + hrate = rate.i; + } + writeHomeSettings(hdir, hrate, offset.u); + startHomingRoutine(); return EP_ONDATA_ACCEPT; } @@ -86,7 +101,9 @@ endpoint_t* homeStateEp = osapBuildEndpoint("HomeState"); void setup() { CLKLIGHT_SETUP; BUSLIGHT_SETUP; - DEBUG1PIN_SETUP; + // debug1pin is the limit pin: we can have one or the other + //DEBUG1PIN_SETUP; + homeSetup(homeStateEp); // osap setup... osapSetup("fab-step"); vt_usbSerial_setup(); @@ -119,6 +136,9 @@ unsigned long last_tick = 0; void loop() { // do osap things, osapLoop(); + limitHit() ? BUSLIGHT_ON : BUSLIGHT_OFF; + // do homing things, if need be: + if(getHomeState() != HOMESTATE_NONE) runHomingRoutine(); // blink if(millis() > last_tick + CLK_TICK){ // step_a4950_step(); @@ -141,6 +161,8 @@ void ucBusDrop_onPacketARx(uint8_t* inBufferA, volatile uint16_t len){ void ucBusDrop_onRxISR(void){ // if we dont' have valid steps, bail if(!stepValid) return; + // if we're currently homing the motor, bail + if(getHomeState() != HOMESTATE_NONE) return; // extract our step mask stepMask = 0b00000011 & (stepCache[cachePtr] >> (axisPick * 2)); // mask -> step api: diff --git a/log/fab-step-log.md b/log/fab-step-log.md index 9e8e8ec038da5eb9060dc930f024fb641ab00ce2..df4fc87af2a7ea0b0fb3e2ed3c296490e1433606 100644 --- a/log/fab-step-log.md +++ b/log/fab-step-log.md @@ -205,6 +205,8 @@ I think I need a config / setup on the js side. OK this is almost jogging - I need some motor config, then I think I actually have some driver level debug to do, not unlikely with the VREF stuff. +### H-Bridge : Code Alignment + It has come to my attention that I changed the pins on all of these things, and hadn't re-written to use the timer-counter rc filters, whoops. Looking a lot better now that I sorted that haha - looks like I still need to scope the pwm'd lines, I am maybe flipping a phase improperly. @@ -219,12 +221,108 @@ Now I'm just not seeing it hold while it's microstepping... OK it's all up, and jogs around w/ the motion system, rad. -- check that 'microstep' config does what it claims -- microstep image -- bring motor config back to JS side -- we need a homing routine still, write this little statemachine pls ! +### Homing Routine + +Next thing I need is a little homing routine... I think I will do `homingRate` in steps / second... rather than keep any other info in the motor. + +This is still kind of a pain. + +Great, homing works. It's stateful, that's why it's such a pain - and has to work all asynchronously; + +```cpp +#include "homing.h" +#include "drivers/step_a4950.h" + +endpoint_t* _homeStateEP; +uint8_t homeState = HOMESTATE_NONE; +uint32_t homeBackoffStepsTaken = 0; + +// home settings +boolean homeDir = true; +unsigned long lastHomeOperation = 0; +unsigned long homeOperationPeriod = 1000; // in us +uint32_t homeBackoffDistance = 100; + +void homeSetup(endpoint_t* homeStateEP){ + // stash this + _homeStateEP = homeStateEP; + // make an input + PORT->Group[LIMIT_PORT].DIRCLR.reg = (1 << LIMIT_PIN); + PORT->Group[LIMIT_PORT].PINCFG[LIMIT_PIN].bit.INEN = 1; + // pullup + PORT->Group[LIMIT_PORT].OUTSET.reg = (1 << LIMIT_PIN); +} + +// return true if limit switch is hit +boolean limitHit(void){ + return (PORT->Group[LIMIT_PORT].IN.reg & (1 << LIMIT_PIN)); +} + +void writeHomeSettings(boolean dir, uint32_t stepsPerSecond, uint32_t offset){ + homeDir = dir; + homeOperationPeriod = 1000000 / stepsPerSecond; + homeBackoffDistance = offset; +} + +uint8_t getHomeState(void){ + return homeState; +} + +void startHomingRoutine(void){ + homeState = HOMESTATE_APPROACH; + endpointWrite(_homeStateEP, &homeState, 1); +} + +void runHomingRoutine(void){ + // run this at a rate... + if(lastHomeOperation + homeOperationPeriod > micros()) return; + lastHomeOperation = micros(); + // state switch; + switch(homeState){ + case HOMESTATE_NONE: + break; + case HOMESTATE_APPROACH: + // check for contact, + if(limitHit()){ + homeState = HOMESTATE_BACKOFF; + endpointWrite(_homeStateEP, &homeState, 1); + homeBackoffStepsTaken = 0; + } else { + step_a4950_dir(homeDir); + step_a4950_step(); + } + break; + case HOMESTATE_BACKOFF: + step_a4950_dir(!homeDir); + step_a4950_step(); + homeBackoffStepsTaken ++; + if(homeBackoffStepsTaken > homeBackoffDistance){ + homeState = HOMESTATE_NONE; + endpointWrite(_homeStateEP, &homeState, 1); + } + break; + default: + // broken, + homeState = HOMESTATE_NONE; + endpointWrite(_homeStateEP, &homeState, 1); + break; + } +} +``` + +Now I just want to touch up the motor APIs in JS, and add the steps-per-unit adjust stuff in the motion-head, etc... I should be pretty close now. + +### Power State API + +- do need this, and it needs to be part of the 'setup' routine + +### New Motor API and JS Config + +- check that 'microstep' config does what it claims (?) - now ... we need to reconsider how / whomst makes SPU / dir configs, etc - inversion is per-motor - so is microstepping - so is the axis pick - - spu is per-axis in the head \ No newline at end of file + - spu is per-axis in the head + +A final treat would be reconfiguring the ucbus-stepper firmware to match this. Another treat would be a tiny demo video for Donny. \ No newline at end of file