diff --git a/.gitmodules b/.gitmodules
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..374612768599c4ed5b62e3cf97948d7c3d155f74 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -0,0 +1,12 @@
+[submodule "firmware/motion-head/src/osape"]
+	path = firmware/motion-head/src/osape
+	url = git@github.com:jakeread/osape.git
+[submodule "firmware/motion-head/src/osape_ucbus"]
+	path = firmware/motion-head/src/osape_ucbus
+	url = git@github.com:jakeread/osape_ucbus.git
+[submodule "firmware/motion-head/src/osape_arduino"]
+	path = firmware/motion-head/src/osape_arduino
+	url = git@github.com:jakeread/osape_arduino.git
+[submodule "firmware/motion-head/src/utils_samd51"]
+	path = firmware/motion-head/src/utils_samd51
+	url = git@github.com:jakeread/utils_samd51.git
diff --git a/firmware/motion-head/src/config.h b/firmware/motion-head/src/config.h
deleted file mode 100644
index 5afe6ea3c0832687c9314900a1fa843f951f7709..0000000000000000000000000000000000000000
--- a/firmware/motion-head/src/config.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// compile-time configur8or 
-#ifndef CONFIG_H_
-#define CONFIG_H_
-
-// for the bus: head, or drop? 
-#define UCBUS_IS_HEAD
-// genuine max is 63, drop for speed 
-#define UCBUS_MAX_DROPS 32 
-//#define UCBUS_IS_DROP
-// and D21 or D51?
-#define UCBUS_IS_D51
-//#define UCBUS_IS_D21 
-
-// 3, 2, or 1 MBaud 
-#define UCBUS_BAUD 2 
-
-// if you're using the 'module board' https://gitlab.cba.mit.edu/jakeread/ucbus-module
-// the first (og) revision has an SMT header, and some of the RS485 pins are varied, 
-// set this flag. otherwise, if you have thru-hole JTAG header, comment it out 
-//#define IS_OG_MODULE 
-
-#endif 
\ No newline at end of file
diff --git a/firmware/motion-head/src/main.cpp b/firmware/motion-head/src/main.cpp
index 42d44d5063659ede8d2de40d5d9afb564257b38e..6200902f027630c6e3a13cedc2082d9f2d78f0fe 100644
--- a/firmware/motion-head/src/main.cpp
+++ b/firmware/motion-head/src/main.cpp
@@ -1,15 +1,20 @@
 #include <Arduino.h>
 
 #include "indicators.h"
-#include "syserror.h"
-#include "osape-d51/d51ClockBoss.h"
+#include "utils_samd51/clock_utils.h"
+
+#include "osape/core/osap.h"
+#include "osape/vertices/endpoint.h"
+
+#include "osape_arduino/vp_arduinoSerial.h"
+
+#include "osape_ucbus/vb_ucBusHead.h"
+#include "osape_ucbus/ucBusHead.h"
+
+#include "osap_debug.h"
 
 #include "smoothie/SmoothieRoll.h"
 
-#include "osape-d51/osape/osap/osap.h"
-#include "osape-d51/vertices/vt_usbSerial.h"
-#include "osape-d51/vertices/ucbus/vt_ucBusHead.h"
-#include "osape-d51/vertices/ucbus/ucBusHead.h"
 // -------------------------------------------------------- SMOOTHIE HANDLES 
 // *should* go to smoothieRoll.h, duh 
 
@@ -27,6 +32,17 @@ boolean smoothie_is_moving(void){
 
 // -------------------------------------------------------- OSAP ENDPOINTS SETUP
 
+OSAP osap("motion-head");
+
+VPort_ArduinoSerial vpUSBSer(&osap, "arduinoUSBSerial", &Serial);
+
+VBus vb_ucBusHead(
+  &osap, "ucBusHead",
+  &vb_ucBusHead_loop,
+  &vb_ucBusHead_send,
+  &vb_ucBusHead_cts
+);
+
 // -------------------------------------------------------- MOVE QUEUE ENDPOINT 
 
 EP_ONDATA_RESPONSES onMoveData(uint8_t* data, uint16_t len){
@@ -45,7 +61,7 @@ EP_ONDATA_RESPONSES onMoveData(uint8_t* data, uint16_t len){
     targetChunks[3] = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] } };
     // check and load, 
     if(feedrateChunk.f < 0.01){
-      sysError("ZERO FR");
+      DEBUG("ZERO FR");
       return EP_ONDATA_ACCEPT; // ignore this & ack 
     } else {
       // do load 
@@ -60,7 +76,7 @@ EP_ONDATA_RESPONSES onMoveData(uint8_t* data, uint16_t len){
   }
 }
 
-endpoint_t* moveQueueEp = osapBuildEndpoint("moveQueue", onMoveData);  // 2
+Endpoint moveQueueEp(&osap, "moveQueue", onMoveData);
 
 // -------------------------------------------------------- POSITION ENDPOINT 
 
@@ -83,7 +99,7 @@ EP_ONDATA_RESPONSES onPositionSet(uint8_t* data, uint16_t len){
   }
 }
 
-endpoint_t* positionEp = osapBuildEndpoint("positions", onPositionSet); // 3
+Endpoint positionEp(&osap, "positions", onPositionSet);
 
 uint8_t posData[16];
 
@@ -94,12 +110,12 @@ void updatePositions(void){
   ts_writeFloat32(smoothieRoll->actuators[1]->floating_position, posData, &poswptr);
   ts_writeFloat32(smoothieRoll->actuators[2]->floating_position, posData, &poswptr);
   ts_writeFloat32(smoothieRoll->actuators[3]->floating_position, posData, &poswptr);
-  endpointWrite(positionEp, posData, 16);
+  positionEp.write(posData, 16);
 }
 
 // -------------------------------------------------------- CURRENT SPEEDS
 
-endpoint_t* speedEp = osapBuildEndpoint("speeds");
+Endpoint speedEp(&osap, "speeds");
 uint8_t speedData[16];
 
 void updateSpeeds(void){
@@ -109,12 +125,12 @@ void updateSpeeds(void){
   ts_writeFloat32(smoothieRoll->actuators[1]->get_current_speed(), speedData, &wptr);
   ts_writeFloat32(smoothieRoll->actuators[2]->get_current_speed(), speedData, &wptr);
   ts_writeFloat32(smoothieRoll->actuators[3]->get_current_speed(), speedData, &wptr);
-  endpointWrite(speedEp, speedData, 16);
+  speedEp.write(speedData, 16);
 }
 
 // -------------------------------------------------------- MOTION STATE EP 
 
-endpoint_t* motionStateEp = osapBuildEndpoint("motionState");  // 4
+Endpoint motionStateEp(&osap, "motionState");  // 4
 uint8_t motionData[1];
 
 void updateMotionState(void){
@@ -123,7 +139,7 @@ void updateMotionState(void){
   } else {
     motionData[0] = 0;
   }
-  endpointWrite(motionStateEp, motionData, 1);
+  motionStateEp.write(motionData, 1);
 }
 
 // -------------------------------------------------------- WAIT TIME EP 
@@ -139,7 +155,7 @@ EP_ONDATA_RESPONSES onWaitTimeData(uint8_t* data, uint16_t len){
   return EP_ONDATA_ACCEPT;
 }
 
-endpoint_t* waitTimeEp = osapBuildEndpoint("waitTime", onWaitTimeData);  // 5 
+Endpoint waitTimeEp(&osap, "waitTime", onWaitTimeData);  // 5 
 
 // -------------------------------------------------------- ACCEL SETTTINGS 
 
@@ -159,7 +175,7 @@ EP_ONDATA_RESPONSES onAccelSettingsData(uint8_t* data, uint16_t len){
   return EP_ONDATA_ACCEPT;
 }
 
-endpoint_t* accelSettingsEp = osapBuildEndpoint("accelSettings", onAccelSettingsData);
+Endpoint accelSettingsEp(&osap, "accelSettings", onAccelSettingsData);
 
 // -------------------------------------------------------- RATES SETTINGS 
 
@@ -179,7 +195,7 @@ EP_ONDATA_RESPONSES onRateSettingsData(uint8_t* data, uint16_t len){
   return EP_ONDATA_ACCEPT;
 }
 
-endpoint_t* rateSettingsEp = osapBuildEndpoint("rateSettings", onRateSettingsData);
+Endpoint rateSettingsEp(&osap, "rateSettings", onRateSettingsData);
 
 // -------------------------------------------------------- SPU SETTINGS 
 
@@ -201,7 +217,7 @@ EP_ONDATA_RESPONSES onSPUData(uint8_t* data, uint16_t len){
   return EP_ONDATA_ACCEPT;
 }
 
-endpoint_t* spuEp = osapBuildEndpoint("stepsPerUnitSettings", onSPUData);
+Endpoint spuEp(&osap, "stepsPerUnitSettings", onSPUData);
 
 // -------------------------------------------------------- POWER MODES 
 
@@ -267,14 +283,14 @@ EP_ONDATA_RESPONSES onPowerData(uint8_t* data, uint16_t len){
   // but remains true to what was written in when we updated w/ the powerStateUpdate fn... 
 }
 
-endpoint_t* powerEp = osapBuildEndpoint("powerSwitches", onPowerData);
+Endpoint powerEp(&osap, "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);
+  powerEp.write(powerData, 2);
 }
 
 // -------------------------------------------------------- SETUP 
@@ -292,30 +308,10 @@ void setup() {
   V24_SETUP;
   powerStateUpdate(false, false);
   // osap
-  osapSetup("modularMotionHead");
-  // ports 
-  vt_usbSerial_setup();
-  osapAddVertex(vt_usbSerial);    // 0
-  vt_ucBusHead_setup();
-  osapAddVertex(vt_ucBusHead);    // 1
-  // move to queue 
-  osapAddEndpoint(moveQueueEp);     // 2
-  // position 
-  osapAddEndpoint(positionEp);      // 3
-  // speed 
-  osapAddEndpoint(speedEp);         // 4 
-  // motion state 
-  osapAddEndpoint(motionStateEp);   // 5
-  // set wait time (ms)
-  osapAddEndpoint(waitTimeEp);      // 6
-  // acceler8 settings
-  osapAddEndpoint(accelSettingsEp); // 7 
-  // r8 settings 
-  osapAddEndpoint(rateSettingsEp);  // 8 
-  // steps-per-unit settings 
-  osapAddEndpoint(spuEp);           // 9
-  // power settings 
-  osapAddEndpoint(powerEp);         // 10 
+  vpUSBSer.begin();
+  /*
+  vb_ucBusHead_setup();
+  */
   // smoothie (and frequency of loop below)
   smoothieRoll->init(SR_TICK_FREQ);
   smoothieRoll->checkMaxRates();
@@ -323,7 +319,7 @@ void setup() {
   // 20kHz base (50us period)
   // 10kHz base (100us period) 
   // 5kHz base (200us period)
-  d51ClockBoss->start_ticker_a(1000000/SR_TICK_FREQ); 
+  d51ClockUtils->start_ticker_a(1000000/SR_TICK_FREQ); 
   // test... 
   // powerStateUpdate(true, false);
 }
@@ -333,7 +329,7 @@ unsigned long lastUpdate = 0;
 
 void loop() {
   // main recursive osap loop:
-  osapLoop();
+  osap.loop();
   // smoothie checks / etc:
   conveyor->on_idle(nullptr);
   // run 10Hz endpoint update:
diff --git a/firmware/motion-head/src/osap_config.h b/firmware/motion-head/src/osap_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..1898a3aeed748c8b1fdcbb2d78f3845c5705a844
--- /dev/null
+++ b/firmware/motion-head/src/osap_config.h
@@ -0,0 +1,33 @@
+/*
+osap_config.h
+
+config options for an osap-embedded build 
+
+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 OSAP_CONFIG_H_
+#define OSAP_CONFIG_H_
+
+// size of vertex stacks, lenght, then count,
+#define VT_SLOTSIZE 256
+#define VT_STACKSIZE 3  // must be >= 2 for ringbuffer operation 
+#define VT_MAXCHILDREN 16
+#define VT_MAXITEMSPERTURN 8
+
+// max # of endpoints that could be spawned here,
+#define MAX_CONTEXT_ENDPOINTS 64
+
+// count of routes each endpoint can have, 
+#define ENDPOINT_MAX_ROUTES 4
+
+// if this is defined, please also provide an osap_debug.h 
+#define OSAP_DEBUG 
+
+#endif 
\ No newline at end of file
diff --git a/firmware/motion-head/src/syserror.cpp b/firmware/motion-head/src/osap_debug.cpp
similarity index 52%
rename from firmware/motion-head/src/syserror.cpp
rename to firmware/motion-head/src/osap_debug.cpp
index bdf769f459f03e4d07a001a9192f9e33970002ae..dd93309f61e1235708d1bb28aa440187b068042c 100644
--- a/firmware/motion-head/src/syserror.cpp
+++ b/firmware/motion-head/src/osap_debug.cpp
@@ -1,10 +1,21 @@
-#include "syserror.h"
-#include "indicators.h"
-#include "osape-d51/osape/osap/ts.h"
-#include "osape-d51/vertices/ucbus/ucBusDrop.h"
-#include "osape-d51/osape/utils/cobs.h"
-#include "config.h"
+/*
+osap_debug.cpp
+
+optional escape hatches & indicators 
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2020
 
+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 "osap_debug.h"
+#include "./osape/core/ts.h"
+#include "./osape/utils/cobs.h"
+#include "indicators.h"
 
 uint8_t errBuf[1028];
 uint8_t errEncoded[1028];
@@ -43,39 +54,25 @@ void sysErrLightCheck(void){
   }
 }
 
-#ifdef UCBUS_IS_DROP 
-
-void sysError(String msg){
-  // noop 
-}
-
-#else 
-
 // config-your-own-ll-escape-hatch
-void sysError(String msg){
+void debugPrint(String msg){
   // whatever you want,
-  //ERRLIGHT_ON;
   uint32_t len = msg.length();
-  errBuf[0] = 0; // serport looks for acks in each msg, this is not one
-  errBuf[1] = PK_PTR; 
-  errBuf[2] = PK_LLESCAPE_KEY; // the ll-errmsg-key
-  errBuf[3] = len & 255;
-  errBuf[4] = (len >> 8) & 255;
-  errBuf[5] = (len >> 16) & 255;
-  errBuf[6] = (len >> 24) & 255;
-  msg.getBytes(&(errBuf[7]), len + 1);
-  size_t ecl = cobsEncode(errBuf, len + 7, errEncoded);
-  errEncoded[ecl] = 0;
+  errBuf[0] = len + 8;  // len, key, cobs start + end, strlen (4) 
+  errBuf[1] = 172;      // serialLink debug key 
+  errBuf[2] = len & 255;
+  errBuf[3] = (len >> 8) & 255;
+  errBuf[4] = (len >> 16) & 255;
+  errBuf[5] = (len >> 24) & 255;
+  msg.getBytes(&(errBuf[6]), len + 1);
+  size_t ecl = cobsEncode(&(errBuf[2]), len + 4, errEncoded);
+  memcpy(&(errBuf[2]), errEncoded, ecl);
+  errBuf[errBuf[0] - 1] = 0;
   // direct escape 
-  //if(Serial.availableForWrite() > (int64_t)ecl){
-    Serial.write(errEncoded, ecl + 1);
-    //Serial.flush();
-  //} else {
-  //  ERRLIGHT_ON;
-  //}
+  Serial.write(errBuf, errBuf[0]);
 }
 
-#endif 
+//#endif 
 
 void logPacket(uint8_t* pck, uint16_t len){
   String errmsg;
@@ -86,6 +83,5 @@ void logPacket(uint8_t* pck, uint16_t len){
     errmsg += String(pck[i]);
     errmsg += ", ";
   }
-  sysError(errmsg);
-}
-
+  debugPrint(errmsg);
+}
\ No newline at end of file
diff --git a/firmware/motion-head/src/osap_debug.h b/firmware/motion-head/src/osap_debug.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c2368003df9001013acab2d8547959d84d924c1
--- /dev/null
+++ b/firmware/motion-head/src/osap_debug.h
@@ -0,0 +1,34 @@
+/*
+osap_debug.h
+
+optional escape hatches & indicators 
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2020
+
+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 OSAP_DEBUG_H_
+#define OSAP_DEBUG_H_
+
+#include <Arduino.h>
+
+void debugPrint(String msg);
+void logPacket(uint8_t* pck, uint16_t len);
+//void sysError(uint8_t* bytes, uint16_t len);
+
+void sysErrLightFlash(uint8_t level);
+void sysErrLightCheck(void);
+
+#define ERROR(level, msg) sysErrLightFlash(level); debugPrint(msg)
+#define DEBUG(msg) debugPrint(msg)
+
+#define ERRLIGHT_ON digitalWrite(5, HIGH)
+#define ERRLIGHT_OFF digitalWrite(5, LOW)
+#define ERRLIGHT_TOGGLE digitalWrite(5, !digitalRead(5))
+
+#endif 
\ No newline at end of file
diff --git a/firmware/motion-head/src/osape b/firmware/motion-head/src/osape
new file mode 160000
index 0000000000000000000000000000000000000000..a2771aa431765b551018661f1fa9fbe6159287d5
--- /dev/null
+++ b/firmware/motion-head/src/osape
@@ -0,0 +1 @@
+Subproject commit a2771aa431765b551018661f1fa9fbe6159287d5
diff --git a/firmware/motion-head/src/osape_arduino b/firmware/motion-head/src/osape_arduino
new file mode 160000
index 0000000000000000000000000000000000000000..61f7d444836df19adb227a7150928c4abdd1ce16
--- /dev/null
+++ b/firmware/motion-head/src/osape_arduino
@@ -0,0 +1 @@
+Subproject commit 61f7d444836df19adb227a7150928c4abdd1ce16
diff --git a/firmware/motion-head/src/osape_ucbus b/firmware/motion-head/src/osape_ucbus
new file mode 160000
index 0000000000000000000000000000000000000000..994f7626eecf15d7db38949b309e2551411abe0d
--- /dev/null
+++ b/firmware/motion-head/src/osape_ucbus
@@ -0,0 +1 @@
+Subproject commit 994f7626eecf15d7db38949b309e2551411abe0d
diff --git a/firmware/motion-head/src/smoothie/SmoothieRoll.cpp b/firmware/motion-head/src/smoothie/SmoothieRoll.cpp
index ad2263195817d2dc7869a736db5031555345e131..eb403ca5dcfdfaabdff9d54bb7a51888e2384fe1 100644
--- a/firmware/motion-head/src/smoothie/SmoothieRoll.cpp
+++ b/firmware/motion-head/src/smoothie/SmoothieRoll.cpp
@@ -13,6 +13,10 @@ no warranty is provided, and users accept all liability.
 */
 
 #include "SmoothieRoll.h"
+#include "./osap_config.h"
+#ifdef OSAP_DEBUG
+#include "./osap_debug.h"
+#endif 
 
 SmoothieRoll* SmoothieRoll::instance = 0;
 
@@ -51,10 +55,12 @@ void SmoothieRoll::checkMaxRates(void){
     for(uint8_t m = 0; m < SR_NUM_MOTORS; m ++){
         float maxTick = actuators[m]->get_max_rate() * actuators[m]->get_steps_per_mm();
         if(maxTick > SR_TICK_FREQ){
-            sysError("motor " + String(m) + " exceeds max tick, " + String(maxTick));
             // new rate should be old rate * rate / 
             float newMax = actuators[m]->get_max_rate() * (SR_TICK_FREQ / maxTick);
-            sysError("old max velocity: " + String(actuators[m]->get_max_rate()) + " new: " + String(newMax));
+            #ifdef OSAP_DEBUG
+            DEBUG("motor " + String(m) + " exceeds max tick, " + String(maxTick));
+            DEBUG("old max velocity: " + String(actuators[m]->get_max_rate()) + " new: " + String(newMax));
+            #endif 
             actuators[m]->set_max_rate(newMax);
         }
     }
diff --git a/firmware/motion-head/src/smoothie/libs/HeapRing.h b/firmware/motion-head/src/smoothie/libs/HeapRing.h
index 5795609563a1bb6acd8e7526e8c5abfe063056d0..6842eb7ae95c0ff74126426d4a2f2bb1ca61c978 100644
--- a/firmware/motion-head/src/smoothie/libs/HeapRing.h
+++ b/firmware/motion-head/src/smoothie/libs/HeapRing.h
@@ -1,8 +1,6 @@
 #ifndef _HEAPRING_H
 #define _HEAPRING_H
 
-#include "../../syserror.h"
-
 template<class kind> class HeapRing {
 
     // smoothie-specific friend classes
diff --git a/firmware/motion-head/src/smoothie/modules/robot/Planner.cpp b/firmware/motion-head/src/smoothie/modules/robot/Planner.cpp
index 9e83530f7fc364d7ddd0b467c41e445aeefd1e21..f483599fec2357f84fbcfd6e6bc784cf5bf77667 100644
--- a/firmware/motion-head/src/smoothie/modules/robot/Planner.cpp
+++ b/firmware/motion-head/src/smoothie/modules/robot/Planner.cpp
@@ -10,6 +10,11 @@ using namespace std;
 
 #include "Planner.h"
 
+#include "./osap_config.h"
+#ifdef OSAP_DEBUG
+#include "./osap_debug.h"
+#endif 
+
 /*
 #include "mri.h"
 #include "nuts_bolts.h"
@@ -173,9 +178,11 @@ bool Planner::append_block( ActuatorCoordinates &actuator_pos, uint8_t n_motors,
             //sysError("add e steps " + String(steps));
         }
         if(i == 0 && false){
-            sysError("steps-x: " + String(steps)
+            #ifdef OSAP_DEBUG 
+            DEBUG("steps-x: " + String(steps)
                     + " t: " + String(actuator_pos[i], 6)
                     + " lm: " + String(smoothieRoll->actuators[i]->get_last_milestone_mm()));
+            #endif 
         }
         //THEROBOT->actuators[i]->steps_to_target(actuator_pos[i]);
         // Update current position
@@ -229,7 +236,9 @@ bool Planner::append_block( ActuatorCoordinates &actuator_pos, uint8_t n_motors,
         block->nominal_speed = rate_mm_s;           // (mm/s) Always > 0
         block->nominal_rate = block->steps_event_count * rate_mm_s / distance; // (step/s) Always > 0
     } else {
-        sysError("bad move call! rejecting");
+        #ifdef OSAP_DEBUG 
+        DEBUG("bad move call! rejecting");
+        #endif 
         return false;
         block->nominal_speed = 0.0F;
         block->nominal_rate  = 0;
diff --git a/firmware/motion-head/src/syserror.h b/firmware/motion-head/src/syserror.h
deleted file mode 100644
index 489173a78b43b8fb1dcf5fc6b4d310aae53438b2..0000000000000000000000000000000000000000
--- a/firmware/motion-head/src/syserror.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef SYSERROR_H_
-#define SYSERROR_H_
-
-#include <Arduino.h>
-
-void sysError(String msg);
-void logPacket(uint8_t* pck, uint16_t len);
-//void sysError(uint8_t* bytes, uint16_t len);
-
-void sysErrLightFlash(uint8_t level);
-void sysErrLightCheck(void);
-
-#define ERROR(level, msg) sysErrLightFlash(level); sysError(msg)
-
-#endif
diff --git a/firmware/motion-head/src/ucbus_config.h b/firmware/motion-head/src/ucbus_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..97f9c98e9a4b5d578db2307c6f40ec06b80d901c
--- /dev/null
+++ b/firmware/motion-head/src/ucbus_config.h
@@ -0,0 +1,27 @@
+/*
+ucbus_confi.h
+
+config options for an ucbus instance 
+
+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 UCBUS_CONFIG_H_
+#define UCBUS_CONFIG_H_
+
+#define UCBUS_MAX_DROPS 32 
+//#define UCBUS_IS_DROP 
+#define UCBUS_IS_HEAD 
+
+#define UCBUS_BAUD 2 
+
+#define UCBUS_IS_D51
+// #define UCBUS_IS_D21
+
+#endif 
\ No newline at end of file
diff --git a/firmware/motion-head/src/utils_samd51 b/firmware/motion-head/src/utils_samd51
new file mode 160000
index 0000000000000000000000000000000000000000..e5cc22d1e8b42bf78b1db64fa9f7d1d752560c72
--- /dev/null
+++ b/firmware/motion-head/src/utils_samd51
@@ -0,0 +1 @@
+Subproject commit e5cc22d1e8b42bf78b1db64fa9f7d1d752560c72