diff --git a/2020-08_psu-breakout/2020-08_psu-breakout.brd b/2020-08_psu-breakout/2020-08_psu-breakout.brd
index 839e1c55767dcdfcd87489d7aeb7b9c4bcc8d1f9..875f50688377118c762b348e8437fd0ad161f4f9 100644
--- a/2020-08_psu-breakout/2020-08_psu-breakout.brd
+++ b/2020-08_psu-breakout/2020-08_psu-breakout.brd
@@ -1170,7 +1170,7 @@ design rules under a new name.</description>
 <attribute name="PRECISION" value="" x="36.5" y="17" size="1.778" layer="27" rot="R90" display="off"/>
 <attribute name="VALUE" x="50.294" y="31.603" size="1.016" layer="27" rot="R90"/>
 </element>
-<element name="R6" library="passives" package="1206" value="470R" x="54" y="39" smashed="yes" rot="R270">
+<element name="R6" library="passives" package="1206" value="1K" x="54" y="39" smashed="yes" rot="R270">
 <attribute name="NAME" x="55.143" y="40.27" size="1.016" layer="25" rot="R270"/>
 <attribute name="PACKAGE" value="1206" x="60" y="39" size="1.778" layer="27" rot="R270" display="off"/>
 <attribute name="PRECISION" value="" x="60" y="39" size="1.778" layer="27" rot="R270" display="off"/>
diff --git a/2020-08_psu-breakout/2020-08_psu-breakout.sch b/2020-08_psu-breakout/2020-08_psu-breakout.sch
index 7d589fc8e7378aa39d5966fff6a8473539ddc561..a9a7f4faa95a77d81b51f08f5df63eaaed1279bc 100644
--- a/2020-08_psu-breakout/2020-08_psu-breakout.sch
+++ b/2020-08_psu-breakout/2020-08_psu-breakout.sch
@@ -6368,7 +6368,7 @@ chip</description>
 <part name="GND16" library="supply1" deviceset="GND" device=""/>
 <part name="GND21" library="supply1" deviceset="GND" device=""/>
 <part name="R5" library="passives" deviceset="RESISTOR" device="1206" value="1k"/>
-<part name="R6" library="passives" deviceset="RESISTOR" device="1206" value="470R"/>
+<part name="R6" library="passives" deviceset="RESISTOR" device="1206" value="1K"/>
 <part name="D8" library="lights" deviceset="LED" device="1206" value="LED1206"/>
 <part name="GND22" library="supply1" deviceset="GND" device=""/>
 <part name="P+3" library="supply1" deviceset="+5V" device=""/>
@@ -6411,6 +6411,7 @@ chip</description>
 <sheets>
 <sheet>
 <plain>
+<text x="152.4" y="104.14" size="1.778" layer="91">^ this is an error, should be +24v</text>
 </plain>
 <instances>
 <instance part="U1" gate="G$1" x="35.56" y="63.5" smashed="yes"/>
diff --git a/2020-08_psu-breakout/eagle.epf b/2020-08_psu-breakout/eagle.epf
index a2531fdcf2f0a0e9e7cea3795e9aea20bf786a62..b1a7d4be82b90753765bcd0231c4ac131c0581b9 100644
--- a/2020-08_psu-breakout/eagle.epf
+++ b/2020-08_psu-breakout/eagle.epf
@@ -19,7 +19,7 @@ UsedLibrary="C:/Dropbox/CBA/circuits/eagle/parts/SparkFun-Eagle-Libraries/SparkF
 Type="Schematic Editor"
 Number=1
 File="2020-08_psu-breakout.sch"
-View="191.998 139.609 359.952 189.822"
+View="69.5535 84.1823 359.778 170.95"
 WireWidths=" 0.0762 0.1016 0.127 0.15 0.2 0.2032 0.254 0.3048 0.4064 0.508 0.6096 0.8128 1.016 1.27 2.54 0.1524"
 PadDiameters=" 0.254 0.3048 0.4064 0.6096 0.8128 1.016 1.27 1.4224 1.6764 1.778 1.9304 2.1844 2.54 3.81 6.4516 0"
 PadDrills=" 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.65 0.7 0.75 0.8 0.85 0.9 1 0.6"
@@ -58,14 +58,14 @@ ArcDirection=0
 AddLevel=2
 PadsSameType=0
 Layer=91
-Views=" 1: 191.998 139.609 359.952 189.822"
+Views=" 1: 69.5535 84.1823 359.778 170.95"
 Sheet="1"
 
 [Win_2]
 Type="Board Editor"
 Number=2
 File="2020-08_psu-breakout.brd"
-View="22.6761 -7.9544 114.036 68.529"
+View="-10.2873 -48.3803 179.157 110.216"
 WireWidths=" 0.1016 0.15 0.2 2.54 0 0.508 0.2032 0.254 0.3048 0.4064 0.1524 1.016 1.27 0.127 0.6096 0.8128"
 PadDiameters=" 0.254 0.3048 0.4064 0.6096 0.8128 1.016 1.27 1.4224 1.6764 1.778 1.9304 2.1844 2.54 3.81 6.4516 0"
 PadDrills=" 0.2 0.25 0.3 0.35 0.4 0.5 0.55 0.65 0.7 0.75 0.8 0.85 0.9 1 0.6 0.45"
diff --git a/firmware/motion-head/src/indicators.h b/firmware/motion-head/src/indicators.h
index 5de5ba9fb781ee179d87d937e937fcf6afbc3750..24d74a0c73094630b5cc48797ba1b85c2be3102a 100644
--- a/firmware/motion-head/src/indicators.h
+++ b/firmware/motion-head/src/indicators.h
@@ -26,12 +26,12 @@
 #define DEBUG1PIN_TOGGLE PIN_TGL(0, 13)
 #define DEBUG1PIN_SETUP PIN_SETUP_OUTPUT(0, 13); PIN_HI(0, 13)
 
-#define DEBUG2PIN_ON PIN_LO(0, 13)
-#define DEBUG2PIN_OFF PIN_HI(0, 13)
-#define DEBUG2PIN_HI PIN_HI(0, 13)
-#define DEBUG2PIN_LO PIN_LO(0, 13)
-#define DEBUG2PIN_TOGGLE PIN_TGL(0, 13)
-#define DEBUG2PIN_SETUP PIN_SETUP_OUTPUT(0, 13); PIN_HI(0, 13)
+#define DEBUG2PIN_ON PIN_LO(0, 12)
+#define DEBUG2PIN_OFF PIN_HI(0, 12)
+#define DEBUG2PIN_HI PIN_HI(0, 12)
+#define DEBUG2PIN_LO PIN_LO(0, 12)
+#define DEBUG2PIN_TOGGLE PIN_TGL(0, 12)
+#define DEBUG2PIN_SETUP PIN_SETUP_OUTPUT(0, 12); PIN_HI(0, 12)
 
 #define DEBUG3PIN_ON PIN_LO(1, 15)
 #define DEBUG3PIN_OFF PIN_HI(1, 15)
diff --git a/firmware/motion-head/src/main.cpp b/firmware/motion-head/src/main.cpp
index 7df92b750df60481e32e22e3a513a5d0dd823727..42d44d5063659ede8d2de40d5d9afb564257b38e 100644
--- a/firmware/motion-head/src/main.cpp
+++ b/firmware/motion-head/src/main.cpp
@@ -181,6 +181,102 @@ EP_ONDATA_RESPONSES onRateSettingsData(uint8_t* data, uint16_t len){
 
 endpoint_t* rateSettingsEp = osapBuildEndpoint("rateSettings", onRateSettingsData);
 
+// -------------------------------------------------------- SPU SETTINGS 
+
+EP_ONDATA_RESPONSES onSPUData(uint8_t* data, uint16_t len){
+  // also 4 floats, steps-per-unit... 
+  uint16_t ptr = 0;
+  chunk_float32 targetChunks[4];
+  targetChunks[0] = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] } };
+  targetChunks[1] = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] } };
+  targetChunks[2] = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] } };
+  targetChunks[3] = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] } };
+  // more motor stuff 
+  for(uint8_t m = 0; m < SR_NUM_MOTORS; m ++){
+    smoothieRoll->actuators[m]->set_steps_per_mm(targetChunks[m].f);
+  }
+  // recheck max rates 
+  smoothieRoll->checkMaxRates();
+  // probably all OK 
+  return EP_ONDATA_ACCEPT;
+}
+
+endpoint_t* spuEp = osapBuildEndpoint("stepsPerUnitSettings", onSPUData);
+
+// -------------------------------------------------------- POWER MODES 
+
+#define V5_ON PIN_HI(0, 11)
+#define V5_OFF PIN_LO(0, 11)
+#define V5_SETUP PIN_SETUP_OUTPUT(0, 11); PIN_LO(0, 11)
+#define V24_ON PIN_HI(0, 10)
+#define V24_OFF PIN_LO(0, 10)
+#define V24_SETUP PIN_SETUP_OUTPUT(0, 10); PIN_LO(0, 10)
+
+// 5V Switch on PA11, 24V Switch on PA10
+/*  5v  | 24v | legal 
+    0   | 0   | yes
+    1   | 0   | yes 
+    0   | 1   | no 
+    1   | 1   | yes 
+
+lol, pretty easy I guess: just no 24v when no 5v...
+we also want to turn on in-order though: 5v first, then 24v, and 24v off, then 5v 
+*/
+
+// track states 
+boolean state5V = false;
+boolean state24V = false;
+
+void publishPowerStates(void);
+
+// make changes 
+void powerStateUpdate(boolean st5V, boolean st24V){
+  // guard against bad state
+  if(st24V && !st5V) st24V = false;
+  // check order-of-flip... if 5v is turning off, we will turn 24v first, 
+  // in all other scenarios, we flip 5v first 
+  if(state5V && !st5V){
+    state24V = st24V; state5V = st5V;
+    // publish, 24v first, and allow charge to leave... 
+    state24V ? V24_ON : V24_OFF;
+    delay(50);
+    state5V ? V5_ON : V5_OFF;
+  } else {
+    state24V = st24V; state5V = st5V;
+    // publish, 5v first, and allow some bring-up... 
+    state5V ? V5_ON : V5_OFF;
+    delay(10);
+    state24V ? V24_ON : V24_OFF;
+  }
+  // now ... would like to write to the endpoint 
+  publishPowerStates();
+}
+
+EP_ONDATA_RESPONSES onPowerData(uint8_t* data, uint16_t len){
+  // read requested states out 
+  boolean st5V, st24V;
+  uint16_t rptr = 0;
+  ts_readBoolean(&st5V, data, &rptr);
+  ts_readBoolean(&st24V, data, &rptr);
+  // run the update against our statemachine 
+  powerStateUpdate(st5V, st24V);
+  // here's a case where we'll never want to let senders to 
+  // update our internal state, so we just return 
+  return EP_ONDATA_REJECT;
+  // this means that the endpoint's data store will remain unchanged (from the write) 
+  // but remains true to what was written in when we updated w/ the powerStateUpdate fn... 
+}
+
+endpoint_t* powerEp = osapBuildEndpoint("powerSwitches", onPowerData);
+
+void publishPowerStates(void){
+  uint8_t powerData[2];
+  uint16_t wptr = 0;
+  ts_writeBoolean(state5V, powerData, &wptr);
+  ts_writeBoolean(state24V, powerData, &wptr);
+  endpointWrite(powerEp, powerData, 2);
+}
+
 // -------------------------------------------------------- SETUP 
 
 void setup() {
@@ -191,6 +287,10 @@ void setup() {
   DEBUG3PIN_SETUP;
   DEBUG4PIN_SETUP;
   DEBUG5PIN_SETUP;
+  // setup the power stuff 
+  V5_SETUP;
+  V24_SETUP;
+  powerStateUpdate(false, false);
   // osap
   osapSetup("modularMotionHead");
   // ports 
@@ -212,13 +312,20 @@ void setup() {
   osapAddEndpoint(accelSettingsEp); // 7 
   // r8 settings 
   osapAddEndpoint(rateSettingsEp);  // 8 
+  // steps-per-unit settings 
+  osapAddEndpoint(spuEp);           // 9
+  // power settings 
+  osapAddEndpoint(powerEp);         // 10 
   // smoothie (and frequency of loop below)
-  smoothieRoll->init(10000);
+  smoothieRoll->init(SR_TICK_FREQ);
+  smoothieRoll->checkMaxRates();
   // 25kHz base (40us period) or 
   // 20kHz base (50us period)
   // 10kHz base (100us period) 
   // 5kHz base (200us period)
-  d51ClockBoss->start_ticker_a(100); 
+  d51ClockBoss->start_ticker_a(1000000/SR_TICK_FREQ); 
+  // test... 
+  // powerStateUpdate(true, false);
 }
 
 unsigned long epUpdateInterval = 100; // ms 
@@ -228,7 +335,7 @@ void loop() {
   // main recursive osap loop:
   osapLoop();
   // smoothie checks / etc:
-  //conveyor->on_idle(nullptr);
+  conveyor->on_idle(nullptr);
   // run 10Hz endpoint update:
   if(millis() > lastUpdate + epUpdateInterval){
     DEBUG5PIN_TOGGLE;
@@ -237,12 +344,16 @@ void loop() {
     updateSpeeds();
     updateMotionState();
   }
-
 } // end loop 
 
 // runs on period defined by timer_a setup: 
 volatile uint32_t timeTick = 0;
 volatile uint64_t timeBlink = 0;
+
+
+volatile uint8_t cachePtr = 0;
+uint8_t stepCache[2];             // xyze: step & dir (8 bit) for two cycles 
+
 uint16_t blinkTime = 1000;
 
 uint8_t motion_packet[64]; // three floats bb, space 
@@ -258,6 +369,20 @@ void TC0_Handler(void){
 
   // do step tick 
   smoothieRoll->step_tick();
+  // cache ticks 
+  stepCache[cachePtr] = smoothieRoll->actuators[3]->get_step_mask() << 6 | 
+                        smoothieRoll->actuators[2]->get_step_mask() << 4 |
+                        smoothieRoll->actuators[1]->get_step_mask() << 2 |
+                        smoothieRoll->actuators[0]->get_step_mask();
+  cachePtr ++;
+
+  if(cachePtr > 1){
+    DEBUG2PIN_TOGGLE;
+    ucBusHead_transmitA(stepCache, 2);
+    cachePtr = 0;
+  }
+
+  /*
   // every n ticks, ship position? 
   // each of these ticks drops 10 data bytes, so if we have 17 byte packet, can do every 2nd packet 
   // which would occupy the full bus - notgood - or we can do every 3rd... I'll pick every 4th. 
@@ -281,6 +406,7 @@ void TC0_Handler(void){
     ucBusHead_transmitA(motion_packet, 17);
     DEBUG2PIN_LO;
   }
+  */
   
   // do blinking, lol
   timeBlink ++;
diff --git a/firmware/motion-head/src/osape-d51 b/firmware/motion-head/src/osape-d51
index acbff5f3f0333d072780d32246ac15a6aa7f1a62..34b5c2d86fd126bc0074418404bea77e96d3dcae 160000
--- a/firmware/motion-head/src/osape-d51
+++ b/firmware/motion-head/src/osape-d51
@@ -1 +1 @@
-Subproject commit acbff5f3f0333d072780d32246ac15a6aa7f1a62
+Subproject commit 34b5c2d86fd126bc0074418404bea77e96d3dcae
diff --git a/firmware/motion-head/src/smoothie/SmoothieConfig.h b/firmware/motion-head/src/smoothie/SmoothieConfig.h
index 517fbea28721890a7afc5e2e894d745afdf89f4c..eb43cba9a654b8a1fc19bf50398fc0989491755c 100644
--- a/firmware/motion-head/src/smoothie/SmoothieConfig.h
+++ b/firmware/motion-head/src/smoothie/SmoothieConfig.h
@@ -8,6 +8,8 @@
 
 // default accel 
 #define SR_DEFAULT_ACCEL 5000.0F
+// and tick period, in us 
+#define SR_TICK_FREQ 10000 
 
 // Keep MAX_ROBOT_ACTUATORS as small as practical it impacts block size and therefore free memory.
 const size_t k_max_actuators = SR_NUM_MOTORS;
diff --git a/firmware/motion-head/src/smoothie/SmoothieRoll.cpp b/firmware/motion-head/src/smoothie/SmoothieRoll.cpp
index 8591ae9a4b2afcece445246ed14bddc3fc84b609..127de94f2f85d2ab96e08f8f4727e811b5c5bccd 100644
--- a/firmware/motion-head/src/smoothie/SmoothieRoll.cpp
+++ b/firmware/motion-head/src/smoothie/SmoothieRoll.cpp
@@ -42,4 +42,15 @@ void SmoothieRoll::init(float frequency){
 
 void SmoothieRoll::step_tick(void){
     stepTicker->step_tick();
+}
+
+void SmoothieRoll::checkMaxRates(void){
+    // we have frequency, SR_TICK_FREQ, and period which is 1000000/SR_TICK_FREQ 
+    // we also have per-axis steps per unit, and max rates, 
+    // if rate * spu exceeds the tick frequency, we are in trouble:
+    for(uint8_t m = 0; m < SR_NUM_MOTORS; m ++){
+        if(actuators[m]->get_max_rate() * actuators[m]->get_steps_per_mm() > SR_TICK_FREQ){
+            sysError("motor " + String(m) + " exceeds max rate");
+        }
+    }
 }
\ No newline at end of file
diff --git a/firmware/motion-head/src/smoothie/SmoothieRoll.h b/firmware/motion-head/src/smoothie/SmoothieRoll.h
index 7fff37932177d3f7d6c8ff226e45406238e0573c..f5d8e42f49dfd20afed30df5c2c7ea0677365e63 100644
--- a/firmware/motion-head/src/smoothie/SmoothieRoll.h
+++ b/firmware/motion-head/src/smoothie/SmoothieRoll.h
@@ -31,6 +31,7 @@ class SmoothieRoll{
         static SmoothieRoll* getInstance(void);
         void init(float frequency);
         void step_tick(void);
+        void checkMaxRates(void);
 
         StepInterface* actuators[SR_NUM_MOTORS];
 
diff --git a/firmware/motion-head/src/smoothie/modules/robot/StepInterface.cpp b/firmware/motion-head/src/smoothie/modules/robot/StepInterface.cpp
index bfb318d3e287ed77f8e7c57ee17a88a1c3f30a5c..defb0de02a3354675b371abb841f0209dc299f89 100644
--- a/firmware/motion-head/src/smoothie/modules/robot/StepInterface.cpp
+++ b/firmware/motion-head/src/smoothie/modules/robot/StepInterface.cpp
@@ -55,6 +55,15 @@ void StepInterface::set_accel(float acc){
     accel = fabsf(acc);
 }
 
+void StepInterface::set_steps_per_mm(float spu){
+    steps_per_mm = spu;
+    mm_per_step = 1 / steps_per_mm;
+}
+
+float StepInterface::get_steps_per_mm(void){
+    return steps_per_mm;
+}
+
 float StepInterface::get_current_speed(void){
     if(!moving){
         return 0.0F;
@@ -75,10 +84,23 @@ boolean StepInterface::step(void){
     now = micros();
     current_speed = (mm_per_step * 1000000) / (now - last_tick);
     last_tick = now;
-
+    // upd8 step mask, is step-dir: 
+    if(direction){
+        step_mask = 0b00000011;
+    } else {
+        step_mask = 0b00000010;
+    }
     return moving;
 }
 
+uint8_t StepInterface::get_step_mask(void){
+    // stash the return 
+    uint8_t mask = step_mask;
+    // reset this, 
+    step_mask = 0;
+    return mask;
+}
+
 void StepInterface::set_direction(boolean dir){
     direction = dir;
 }
diff --git a/firmware/motion-head/src/smoothie/modules/robot/StepInterface.h b/firmware/motion-head/src/smoothie/modules/robot/StepInterface.h
index 5e4813d1881a182dd41dfa0a895b2b7a5f151bd5..bed0a6123988f3f069f6563e31f44de41562b549 100644
--- a/firmware/motion-head/src/smoothie/modules/robot/StepInterface.h
+++ b/firmware/motion-head/src/smoothie/modules/robot/StepInterface.h
@@ -25,6 +25,8 @@ class StepInterface {
         void set_max_rate(float rate);
         float get_accel(void);
         void set_accel(float acc);
+        void set_steps_per_mm(float spu);
+        float get_steps_per_mm(void);
 
         // util to track speed per motor:
         float get_current_speed(void);
@@ -36,6 +38,10 @@ class StepInterface {
         boolean is_moving(void);
         // could also use this structure to setup steps / mm, max accel, max rate per actuator 
 
+        // yonder awkward step-mask-getter for network step-mask 
+        volatile uint8_t step_mask = 0;
+        uint8_t get_step_mask(void);
+
         // for net interface, 
         volatile int32_t stepwise_position = 0;
         volatile float floating_position = 0.0F;
diff --git a/log/ucbus-psu-breakout-log.md b/log/modular-motion-head-log.md
similarity index 88%
rename from log/ucbus-psu-breakout-log.md
rename to log/modular-motion-head-log.md
index c4d84a9a8b743d33d8e7854894d7b98ed018791f..25e3d5f0014d99f884f2996f3353af8bfa7d83bc 100644
--- a/log/ucbus-psu-breakout-log.md
+++ b/log/modular-motion-head-log.md
@@ -109,7 +109,19 @@ God bless, just a recursive overloaded function that was calling itself, when I
 
 OK I can try a 5v turn-on-off code. I guess I'll build my little one-motor-single-page-demo controller as well, sheesh. 
 
-- 5v src / sinks ? 
+OK these look setup, I'm going to build an example controller here... or in another repo?
+
+The 5v switch works, so I want a little demo-test for the 24v. 
+
+Also at the control head... some tiny distributed statemachine w/ a front end. I have been thinking about this kind of structure - a UI coupled virtual machine. It'd be a good stopgap, but I think I should focus on the typeset OSAP work & what would be a more complete version of this type of thing. 
+
+In any case, the 24v stress testing. I'll solder one of these heat beds up. This provides 2.3 Ohms, at 24v that's just about 250 watts, 10 amps: the PSU is rated for 350W. I could butcher one of these 30-pin ribbons, or just solder a few leads to the BFC pinout. #2, I think. 
+
+Alright well here it goes ffs. Seems like it works, though I suppose that shouldn't be too surprising, the FETS are rated to like 50A each, there's two, and this is 10A. I think I'll stick some little fets on there anyways. 
+
+- test power draw, heat buildup... 
+- watch power on scope, is it chill? 
+- test 24v w/ no usb power... 
 
 ## Part Purchase