- Output breakers
+ {heading}
- {channels.map((p) => (
-
- ))}
+ {channels.map((p) => {
+ const isFuse = p.slot === 'fuse';
+ return (
+
+ );
+ })}
);
diff --git a/src/data/componentLibrary.js b/src/data/componentLibrary.js
index 74dfaa5..7251db7 100644
--- a/src/data/componentLibrary.js
+++ b/src/data/componentLibrary.js
@@ -16,7 +16,11 @@ const WAGO = 'Wago Lever Nut';
const RING = 'Ring Terminal';
const APP = 'Anderson Powerpole';
const MOLEX_SL = 'Molex SL';
+const BARREL = 'Barrel Jack';
+const USB_A = 'USB-A';
+const USB_C = 'USB-C';
const BARE = 'Bare Wire';
+const BULLET = 'Bullet';
// Allowed-fitting sets per physical termination style. `requiredFittings` on a
// port is the list a wire end may legally use; the DRC connector-mismatch rule
@@ -28,6 +32,9 @@ const APP_LEADS = [APP, BARE]; // flying power/motor leads (Powerpole or
const APP_IN = [APP, FERRULE, BARE]; // controller power input (Powerpole or into a PD terminal)
const CAN_WEID = [FERRULE, BARE]; // REV-style CAN terminal
const CAN_CTRE = [FERRULE, BARE, 'JST']; // CTRE CAN cable: keyed connector or terminal
+const CAN_MOLEX = [MOLEX_SL, FERRULE, BARE]; // locking Molex SL CAN (MitoCANdria/ThriftyBot)
+const PHASE = [RING, BARE]; // brushless 3-phase motor lead
+const PHASE_BULLET = [BULLET, BARE]; // NEO Vortex bullet-connector phases (→ SPARK Flex dock)
// single unified power wire
const pwr = (label, side, gauge = null, fitting = null, requiredFittings = null) => [
@@ -38,7 +45,10 @@ const can = (label = 'CAN', side = 'bottom', requiredFittings = null) => [
{ type: 'CAN', label, side, requiredFittings },
];
const eth = (label = 'ETH', side = 'top') => [{ type: 'ETH', label, side }];
-const usb = (label = 'USB', side = 'top') => [{ type: 'USB', label, side }];
+// USB ports carry a connector variant so USB-A host ports and USB-C
+// power/config ports read distinctly in the diagram and the DRC.
+const usbA = (label = 'USB-A', side = 'top') => [{ type: 'USB', label, side, requiredFittings: [USB_A] }];
+const usbC = (label = 'USB-C', side = 'top') => [{ type: 'USB', label, side, requiredFittings: [USB_C] }];
const data = (label = 'Data', side = 'top') => [{ type: 'DATA', label, side }];
// Build a definition; assigns per-definition port ids and per-side order.
@@ -55,14 +65,20 @@ function def(id, name, category, icon, width, height, trackedFields, portSpecs)
gauge: p.gauge ?? null,
fitting: p.fitting ?? null,
breaker: p.breaker ?? null,
+ slot: p.slot ?? null, // 'breaker' | 'fuse' | null — branch protection type
requiredFittings: p.requiredFittings ?? null,
};
});
return { id, name, category, width: snapDim(width), height: snapDim(height), icon, defaultPorts, trackedFields };
}
-// PDH/PDP shape: PWR IN (6 AWG/SB50), 2x CAN, N output channels (12 AWG/Ferrule).
-function powerDistPorts(numChannels) {
+// PDH/PDP shape: PWR IN (6 AWG/SB50), 2x CAN, N output channels.
+// `miniFrom` = index of the first low-current MINIATURE fuse channel. On the
+// REV PDH channels 20–23 are 15 A mini-fuse slots (20–22 non-switchable, used
+// for the roboRIO/radio on a 10 A fuse per R615); channels 0–19 are full-size
+// 40 A ATO breaker slots. Pass `null` (CTRE PDP 2.0) for all-breaker, every
+// channel 40 A — the PDP has no miniature tier.
+function powerDistPorts(numChannels, miniFrom = null) {
const ports = [
...pwr('PWR', 'bottom', '6 AWG', SB50, MAIN),
...can('CAN IN', 'bottom', CAN_WEID),
@@ -70,10 +86,12 @@ function powerDistPorts(numChannels) {
];
for (let i = 0; i < numChannels; i++) {
const side = i <= 9 ? 'right' : 'left';
- // PDH channels 20–22 are the non-switchable 10 A roboRIO/radio channels
- // (R615); default the rest to a 40 A breaker.
- const breaker = i >= 20 && i <= 22 ? 10 : 40;
- ports.push({ type: 'PWR', label: `CH${i}`, side, gauge: '12 AWG', fitting: FERRULE, breaker, requiredFittings: WEID });
+ const isMini = miniFrom != null && i >= miniFrom;
+ ports.push(
+ isMini
+ ? { type: 'PWR', label: `CH${i}`, side, gauge: '18 AWG', fitting: FERRULE, slot: 'fuse', breaker: 10, requiredFittings: WEID }
+ : { type: 'PWR', label: `CH${i}`, side, gauge: '12 AWG', fitting: FERRULE, slot: 'breaker', breaker: 40, requiredFittings: WEID }
+ );
}
return ports;
}
@@ -84,36 +102,38 @@ export const COMPONENT_LIBRARY = [
...pwr('PWR', 'top', '12 AWG', FERRULE, WEID),
...can('CAN', 'left', CAN_WEID),
...eth('ETH', 'top'),
- ...usb('USB', 'right'),
- ...usb('USB', 'right'),
+ ...usbA('USB-A', 'right'),
+ ...usbA('USB-A', 'right'),
...pwr('RSL', 'bottom', '18 AWG', FERRULE, WEID),
]),
def('orangepi5', 'Orange Pi 5', 'Controllers', 'pi', 160, 80, ['ipAddress'], [
- ...usb('USBC - PWR', 'left'),
+ ...usbC('USB-C PWR', 'left'),
...eth('ETH', 'top'),
- ...usb('USB', 'right'),
- ...usb('USB', 'right'),
+ ...usbA('USB-A', 'right'),
+ ...usbA('USB-A', 'right'),
]),
def('raspberrypi5', 'Raspberry Pi 5', 'Controllers', 'pi', 160, 80, ['ipAddress'], [
- ...usb('USBC - PWR', 'left'),
+ ...usbC('USB-C PWR', 'left'),
...eth('ETH', 'top'),
- ...usb('USB', 'right'),
- ...usb('USB', 'right'),
- ]),
- def('jetsonorinnano', 'Jetson Orin Nano', 'Controllers', 'pi', 160, 80, ['ipAddress'], [
- ...pwr('PWR', 'left'), // Barrel Jack
- ...usb('USBC - PWR', 'top'),
+ ...usbA('USB-A', 'right'),
+ ...usbA('USB-A', 'right'),
+ ]),
+ // Jetson Orin Nano — primary power is the DC barrel jack (USB-C is an
+ // alternate input); 4× USB-A host ports + 1× USB-C + Gigabit Ethernet.
+ def('jetsonorinnano', 'Jetson Orin Nano', 'Controllers', 'pi', 160, 90, ['ipAddress'], [
+ ...pwr('PWR (Barrel)', 'left', null, BARREL, [BARREL]),
+ ...usbC('USB-C', 'top'),
...eth('ETH', 'top'),
- ...usb('USB', 'bottom'),
- ...usb('USB', 'bottom'),
- ...usb('USB', 'bottom'),
- ...usb('USB', 'bottom'),
+ ...usbA('USB-A', 'bottom'),
+ ...usbA('USB-A', 'bottom'),
+ ...usbA('USB-A', 'bottom'),
+ ...usbA('USB-A', 'bottom'),
]),
def('beelink', 'Beelink Mini PC', 'Controllers', 'pi', 160, 80, ['ipAddress'], [
- ...pwr('PWR', 'left'),
+ ...pwr('PWR (Barrel)', 'left', null, BARREL, [BARREL]),
...eth('ETH', 'top'),
- ...usb('USB', 'right'),
- ...usb('USB', 'right'),
+ ...usbA('USB-A', 'right'),
+ ...usbA('USB-A', 'right'),
]),
// ---------------- Power ----------------
@@ -124,7 +144,9 @@ export const COMPONENT_LIBRARY = [
{ type: 'PWR', label: 'IN', side: 'left', gauge: '6 AWG', fitting: RING, requiredFittings: STUD },
{ type: 'PWR', label: 'OUT', side: 'right', gauge: '6 AWG', fitting: RING, requiredFittings: STUD },
]),
- def('pdh', 'PDH (REV)', 'Power', 'powerdist', 240, 320, ['canId'], powerDistPorts(24)),
+ // PDH: 20 full-size breaker channels (0–19) + 4 miniature fuse channels (20–23).
+ def('pdh', 'PDH (REV)', 'Power', 'powerdist', 240, 320, ['canId'], powerDistPorts(24, 20)),
+ // PDP 2.0 / legacy PDP: 24 identical full-size channels, all default 40 A.
def('pdp2', 'PDP 2.0 (CTRE)', 'Power', 'powerdist', 240, 320, ['canId'], powerDistPorts(24)),
def('pdp_legacy', 'PDP (CTRE, legacy)', 'Power', 'powerdist', 240, 320, ['canId'], powerDistPorts(24)),
def('vrm', 'VRM', 'Power', 'vrm', 160, 80, [], [
@@ -138,30 +160,29 @@ export const COMPONENT_LIBRARY = [
...pwr('5V/500mA', 'right', '18 AWG', FERRULE, WEID),
...pwr('5V/500mA', 'right', '18 AWG', FERRULE, WEID),
]),
- def('rpm', 'Radio Power Module (REV RPM)', 'Power', 'radioPower', 140, 80, [], [
- ...pwr('PWR', 'left', '18 AWG', FERRULE, WEID),
- ...eth('ETH IN', 'top'),
- ...eth('ETH OUT', 'top'),
- ...pwr('AUX', 'right', '18 AWG', FERRULE, WEID),
- ]),
- def('mpm', 'Mini Power Module (CTRE MPM)', 'Power', 'vrm', 120, 160, [], [
- ...pwr('PWR', 'bottom', '18 AWG', FERRULE, WEID),
- ...pwr('CH0', 'right', '18 AWG', FERRULE, WEID),
- ...pwr('CH1', 'right', '18 AWG', FERRULE, WEID),
- ...pwr('CH2', 'right', '18 AWG', FERRULE, WEID),
- ...pwr('CH3', 'right', '18 AWG', FERRULE, WEID),
- ...pwr('CH4', 'right', '18 AWG', FERRULE, WEID),
- ...pwr('CH5', 'right', '18 AWG', FERRULE, WEID),
- ]),
- def('mitocandria', 'MitoCANDria (ThriftyBot)', 'Power', 'vrm', 160, 80, ['canId'], [
- ...pwr('PWR', 'left', '18 AWG', FERRULE, WEID),
- ...can('CAN', 'bottom', CAN_WEID),
- ...can('CAN', 'bottom', CAN_WEID),
- ...usb('5V USBC', 'top'),
- ...usb('5V USBC', 'top'),
- ...pwr('BOOST', 'right', '20 AWG', FERRULE, WEID),
- ...pwr('5VA', 'right', '20 AWG', FERRULE, WEID),
- ...pwr('5VB', 'right', '20 AWG', FERRULE, WEID),
+ // REV Mini Power Module — fed from one 40 A PDH channel, fans out to 6
+ // low-current outputs each protected by an ATM mini blade FUSE (15 A max),
+ // sized per peripheral. Same miniature-fuse picker as the PDH mini channels.
+ def('mpm', 'Mini Power Module (REV MPM)', 'Power', 'vrm', 120, 160, [], [
+ ...pwr('PWR', 'bottom', '12 AWG', FERRULE, WEID),
+ { type: 'PWR', label: 'CH0', side: 'right', gauge: '18 AWG', fitting: FERRULE, slot: 'fuse', requiredFittings: WEID },
+ { type: 'PWR', label: 'CH1', side: 'right', gauge: '18 AWG', fitting: FERRULE, slot: 'fuse', requiredFittings: WEID },
+ { type: 'PWR', label: 'CH2', side: 'right', gauge: '18 AWG', fitting: FERRULE, slot: 'fuse', requiredFittings: WEID },
+ { type: 'PWR', label: 'CH3', side: 'right', gauge: '18 AWG', fitting: FERRULE, slot: 'fuse', requiredFittings: WEID },
+ { type: 'PWR', label: 'CH4', side: 'right', gauge: '18 AWG', fitting: FERRULE, slot: 'fuse', requiredFittings: WEID },
+ { type: 'PWR', label: 'CH5', side: 'right', gauge: '18 AWG', fitting: FERRULE, slot: 'fuse', requiredFittings: WEID },
+ ]),
+ // MitoCANdria — 4.5–14 V in via locking Molex SL; 4× 5 V USB-C outputs +
+ // one adjustable 15–24 V boost; CAN over locking Molex SL.
+ def('mitocandria', 'MitoCANdria (ThriftyBot)', 'Power', 'vrm', 160, 96, ['canId'], [
+ ...pwr('PWR IN', 'left', '18 AWG', MOLEX_SL, [MOLEX_SL]),
+ ...can('CAN', 'bottom', CAN_MOLEX),
+ ...can('CAN', 'bottom', CAN_MOLEX),
+ ...usbC('5V USB-C', 'top'),
+ ...usbC('5V USB-C', 'top'),
+ ...usbC('5V USB-C', 'top'),
+ ...usbC('5V USB-C', 'top'),
+ ...pwr('15–24V BOOST', 'right', '20 AWG', FERRULE, WEID),
]),
def('canjunction', 'CANJunction (ThriftyBot)', 'Power', 'canjunction', 120, 60, [], [
...can('CAN', 'left', MOLEX_SL),
@@ -169,25 +190,35 @@ export const COMPONENT_LIBRARY = [
]),
// ---------------- Motor Controllers ----------------
- def('sparkmax', 'SPARK MAX', 'Motor Controllers', 'motorController', 160, 80, ['canId'], [
- ...pwr('PWR', 'left', '12 AWG', APP, APP_IN),
+ // SPARK MAX/Flex drive brushless motors over 3 phase leads (A/B/C flying
+ // leads); brushed motors use A/B only. Power in is V+/V- (red/black leads).
+ def('sparkmax', 'SPARK MAX', 'Motor Controllers', 'motorController', 160, 100, ['canId'], [
+ ...pwr('V+/V−', 'left', '12 AWG', APP, APP_IN),
...can('CAN', 'bottom', CAN_WEID),
...can('CAN', 'bottom', CAN_WEID),
- ...pwr('MOTOR', 'right', '12 AWG', APP, APP_LEADS),
+ { type: 'PWR', label: 'A', side: 'right', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'B', side: 'right', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'C', side: 'right', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
...data('Encoder', 'top'),
]),
- def('sparkflex', 'SPARK Flex', 'Motor Controllers', 'motorController', 160, 80, ['canId'], [
- ...pwr('PWR', 'left', '12 AWG', APP, APP_IN),
+ def('sparkflex', 'SPARK Flex', 'Motor Controllers', 'motorController', 160, 100, ['canId'], [
+ ...pwr('V+/V−', 'left', '12 AWG', APP, APP_IN),
...can('CAN', 'bottom', CAN_WEID),
...can('CAN', 'bottom', CAN_WEID),
- ...pwr('MOTOR', 'right', '12 AWG', APP, APP_LEADS),
+ { type: 'PWR', label: 'A', side: 'right', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'B', side: 'right', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'C', side: 'right', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
...data('Encoder', 'top'),
]),
- def('talonfxs', 'Talon FXS', 'Motor Controllers', 'motorController', 120, 70, ['canId'], [
- ...pwr('PWR', 'left', '12 AWG', APP, APP_IN),
+ // Talon FXS — brushless 3-phase out on 3 ring-terminal stator leads (U/V/W);
+ // brushed uses 2 of them. Power in is V+/V- ring terminals (6-32 studs).
+ def('talonfxs', 'Talon FXS', 'Motor Controllers', 'motorController', 140, 100, ['canId'], [
+ ...pwr('V+/V−', 'left', '12 AWG', RING, STUD),
...can('CAN', 'bottom', CAN_CTRE),
- ...pwr('MOTOR', 'right', '12 AWG', APP, APP_LEADS),
- ...data('Data port', 'top'),
+ { type: 'PWR', label: 'U', side: 'right', gauge: '12 AWG', fitting: RING, requiredFittings: PHASE },
+ { type: 'PWR', label: 'V', side: 'right', gauge: '12 AWG', fitting: RING, requiredFittings: PHASE },
+ { type: 'PWR', label: 'W', side: 'right', gauge: '12 AWG', fitting: RING, requiredFittings: PHASE },
+ ...data('Sensor (JST)', 'top'),
]),
def('generic_mc', 'Generic Motor Controller', 'Motor Controllers', 'motorController', 120, 70, ['canId'], [
...pwr('PWR', 'left', '12 AWG', FERRULE),
@@ -217,73 +248,98 @@ export const COMPONENT_LIBRARY = [
{ type: 'CAN', label: 'CAN IN', side: 'right', requiredFittings: CAN_CTRE },
{ type: 'CAN', label: 'CAN OUT', side: 'right', requiredFittings: CAN_CTRE },
]),
- def('minion', 'Minion', 'Motors', 'motor', 120, 70, [], [
- ...pwr('PWR', 'left', '12 AWG', RING, STUD),
- ...data('Hall', 'top'),
- ]),
- def('neo', 'NEO', 'Motors', 'motor', 120, 70, [], [
- ...pwr('PWR', 'left', '12 AWG', APP, APP_LEADS),
- ...data('Encoder', 'top'),
- ]),
- def('neo550', 'NEO 550', 'Motors', 'motor', 120, 70, [], [
- ...pwr('PWR', 'left', '12 AWG', APP, APP_LEADS),
- ...data('Encoder', 'top'),
- ]),
- def('neovortex', 'NEO Vortex', 'Motors', 'motor', 120, 70, [], [
- ...pwr('PWR', 'left', '12 AWG', APP, APP_LEADS),
- ...data('Encoder', 'top'),
+ // Minion — bare 3-phase brushless motor driven by a Talon FXS. 3 ring-terminal
+ // phase leads (U/V/W) + a 6-pin JST hall/temp sensor cable.
+ def('minion', 'Minion', 'Motors', 'motor', 130, 104, [], [
+ { type: 'PWR', label: 'U', side: 'left', gauge: '12 AWG', fitting: RING, requiredFittings: PHASE },
+ { type: 'PWR', label: 'V', side: 'left', gauge: '12 AWG', fitting: RING, requiredFittings: PHASE },
+ { type: 'PWR', label: 'W', side: 'left', gauge: '12 AWG', fitting: RING, requiredFittings: PHASE },
+ ...data('Sensor (6-pin JST)', 'top'),
+ ]),
+ // NEO / NEO 550 — bare 3-phase brushless motors driven by a SPARK MAX. 3
+ // bare/tinned flying-lead phases (A/B/C) + a 6-pin JST-PH encoder cable.
+ def('neo', 'NEO', 'Motors', 'motor', 130, 104, [], [
+ { type: 'PWR', label: 'A', side: 'left', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'B', side: 'left', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'C', side: 'left', gauge: '12 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ ...data('Encoder (6-pin JST)', 'top'),
+ ]),
+ def('neo550', 'NEO 550', 'Motors', 'motor', 130, 104, [], [
+ { type: 'PWR', label: 'A', side: 'left', gauge: '14 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'B', side: 'left', gauge: '14 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ { type: 'PWR', label: 'C', side: 'left', gauge: '14 AWG', fitting: BARE, requiredFittings: APP_LEADS },
+ ...data('Encoder (6-pin JST)', 'top'),
+ ]),
+ // NEO Vortex — 3-phase brushless that docks directly to a SPARK Flex via
+ // bullet connectors (or breaks out to flying leads on the Solo Adapter).
+ def('neovortex', 'NEO Vortex', 'Motors', 'motor', 130, 104, [], [
+ { type: 'PWR', label: 'A', side: 'left', gauge: '12 AWG', fitting: BULLET, requiredFittings: PHASE_BULLET },
+ { type: 'PWR', label: 'B', side: 'left', gauge: '12 AWG', fitting: BULLET, requiredFittings: PHASE_BULLET },
+ { type: 'PWR', label: 'C', side: 'left', gauge: '12 AWG', fitting: BULLET, requiredFittings: PHASE_BULLET },
+ ...data('Encoder (6-pin JST)', 'top'),
]),
def('generic_motor', 'Generic Motor', 'Motors', 'motor', 120, 70, [], [
...pwr('PWR', 'left', '12 AWG', FERRULE),
]),
// ---------------- Sensors ----------------
+ // CTRE CANcoder — flying leads: a separate power pair plus a CAN pair (newer
+ // units use a keyed 6-pin Molex SL). Power and CAN are separate conductors.
def('cancoder', 'CANcoder', 'Sensors', 'canSensor', 100, 60, ['canId'], [
- ...pwr('PWR', 'left', '18 AWG', FERRULE, CAN_CTRE),
- ...can('CAN', 'bottom', CAN_CTRE),
+ ...pwr('PWR', 'left', '22 AWG', BARE, [FERRULE, BARE, MOLEX_SL]),
+ ...can('CAN', 'bottom', CAN_MOLEX),
]),
+ // CTRE Pigeon 2.0 IMU — separate power and CAN flying leads (22 AWG).
def('pigeon2', 'Pigeon 2', 'Sensors', 'canSensor', 100, 60, ['canId'], [
- ...pwr('PWR', 'left', '18 AWG', FERRULE, CAN_CTRE),
+ ...pwr('PWR', 'left', '22 AWG', BARE, [FERRULE, BARE]),
...can('CAN', 'bottom', CAN_CTRE),
]),
- def('candle', 'CANdle', 'Sensors', 'canSensor', 100, 60, ['canId'], [
+ // CTRE CANdle — Weidmuller push-in for VBat power + CAN; LED data out on a
+ // 3-pin JST. The power feed is the heavy lead (it drives the LED strip).
+ def('candle', 'CANdle', 'Sensors', 'canSensor', 110, 70, ['canId'], [
...pwr('PWR', 'left', '18 AWG', FERRULE, WEID),
- ...can('CAN', 'bottom', CAN_CTRE),
- ...data('LED out', 'top'),
+ ...can('CAN', 'bottom', CAN_WEID),
+ ...data('LED out (3-pin JST)', 'top'),
]),
+ // CTRE CANrange / CANdi — Weidmuller push-in terminals for separate power +
+ // CAN (the CANdi adds two signal inputs).
def('canrange', 'CANrange', 'Sensors', 'canSensor', 100, 60, ['canId'], [
- ...pwr('PWR', 'left', '18 AWG', FERRULE, CAN_CTRE),
- ...can('CAN', 'bottom', CAN_CTRE),
+ ...pwr('PWR', 'left', '22 AWG', FERRULE, WEID),
+ ...can('CAN', 'bottom', CAN_WEID),
]),
- def('candi', 'CANdi', 'Sensors', 'canSensor', 100, 60, ['canId'], [
- ...pwr('PWR', 'left', '18 AWG', FERRULE, CAN_CTRE),
- ...can('CAN', 'bottom', CAN_CTRE),
+ def('candi', 'CANdi', 'Sensors', 'canSensor', 110, 80, ['canId'], [
+ ...pwr('PWR', 'left', '22 AWG', FERRULE, WEID),
+ ...can('CAN', 'bottom', CAN_WEID),
...data('S1', 'top'),
...data('S2', 'top'),
]),
- def('limelight4', 'Limelight 4', 'Sensors', 'camera', 120, 70, ['ipAddress'], [
+ // Limelight 4 — 12 V via Weidmuller (or passive PoE), RJ45 Ethernet + USB-C.
+ def('limelight4', 'Limelight 4', 'Sensors', 'camera', 120, 80, ['ipAddress'], [
...pwr('PWR', 'left', '18 AWG', FERRULE, WEID),
...eth('ETH', 'top'),
+ ...usbC('USB-C', 'right'),
]),
def('limelight3g', 'Limelight 3G', 'Sensors', 'camera', 120, 70, ['ipAddress'], [
...pwr('PWR', 'left', '18 AWG', FERRULE, WEID),
...eth('ETH', 'top'),
]),
+ // Grapple LaserCAN — soldered pads / optional flying leads; separate power
+ // and CAN conductors (bare wire).
def('lasercan', 'LaserCAN (Grapple)', 'Sensors', 'canSensor', 120, 80, ['canId'], [
- ...pwr('PWR', 'bottom', '22 AWG', FERRULE, WEID),
- ...pwr('PWR', 'top', '22 AWG', FERRULE, WEID),
- { type: 'CAN', label: 'CAN IN', side: 'left', requiredFittings: CAN_WEID },
- { type: 'CAN', label: 'CAN OUT', side: 'right', requiredFittings: CAN_WEID },
+ ...pwr('PWR', 'top', '22 AWG', BARE, [BARE, FERRULE]),
+ { type: 'CAN', label: 'CAN IN', side: 'left', requiredFittings: [BARE, FERRULE] },
+ { type: 'CAN', label: 'CAN OUT', side: 'right', requiredFittings: [BARE, FERRULE] },
]),
def('thriftycam', 'ThriftyCAM (ThriftyBot)', 'Sensors', 'camera', 120, 70, [], [
- ...usb('USB', 'left'),
+ ...usbA('USB-A', 'left'),
]),
def('usbcamera', 'Generic USB Camera', 'Sensors', 'camera', 120, 70, [], [
- ...usb('USB', 'left'),
+ ...usbA('USB-A', 'left'),
]),
- def('throughboreencoder', 'REV Through Bore Encoder', 'Sensors', 'canSensor', 100, 64, [], [
- ...pwr('PWR', 'left', '18 AWG', FERRULE, WEID),
- ...data('Data', 'left'),
+ // REV Through Bore Encoder — a single 6-pin JST-PH cable carries power +
+ // absolute + ABI quadrature (it is NOT a CAN device).
+ def('throughboreencoder', 'REV Through Bore Encoder', 'Sensors', 'sensor', 110, 64, [], [
+ ...data('Output (6-pin JST)', 'left'),
]),
def('generic_sensor', 'Generic Sensor', 'Sensors', 'sensor', 100, 60, [], [
...pwr('PWR', 'left', '18 AWG', FERRULE),
@@ -308,7 +364,7 @@ export const COMPONENT_LIBRARY = [
...eth('5', 'top'),
]),
def('canivore', 'CANivore (CTRE)', 'Networking', 'canjunction', 120, 80, [], [
- ...usb('USB', 'left'),
+ ...usbA('USB-A', 'left'),
...can('CAN', 'right', CAN_CTRE),
...pwr('V+/V-', 'bottom', '22 AWG', FERRULE, WEID),
]),
diff --git a/src/data/wireTypes.js b/src/data/wireTypes.js
index 018b6eb..f61f672 100644
--- a/src/data/wireTypes.js
+++ b/src/data/wireTypes.js
@@ -60,9 +60,26 @@ export const FITTING_OPTIONS = [
'Ferrule',
'Wago Lever Nut',
'JST',
+ 'Bullet',
+ 'Barrel Jack',
+ 'USB-A',
+ 'USB-C',
'Bare Wire',
];
+// Power-distribution branch protection. Full-size channels (PDH ch 0–19, PDP)
+// take ATO blade circuit breakers; miniature/low-current channels (PDH ch
+// 20–23, REV MPM) take small ATM blade fuses. The valid amp ratings differ, so
+// the per-channel editor offers the right set based on each port's `slot`.
+export const BREAKER_RATINGS = [10, 20, 30, 40]; // ATO breaker (40 A branch max, R619)
+export const FUSE_RATINGS = [1, 2, 3, 5, 7.5, 10, 15]; // ATM mini blade fuse (15 A max/ch)
+
+// Valid amp ratings for a port's protection slot ('fuse' → mini fuses, else
+// full-size breakers). Defaults to breaker ratings for legacy/undefined slots.
+export function slotRatings(slot) {
+ return slot === 'fuse' ? FUSE_RATINGS : BREAKER_RATINGS;
+}
+
// Approximate continuous current capacity (amps) per gauge for chassis/robot
// power wiring. Advisory values used by the DRC gauge-vs-current check.
export const GAUGE_AMPACITY = {