diff --git a/examples/example.json b/examples/example.json index 65b65d1..36ce5d7 100644 --- a/examples/example.json +++ b/examples/example.json @@ -1,7 +1,7 @@ { "app": "wireup", "version": 2, - "savedAt": "2026-06-15T03:07:08.505Z", + "savedAt": "2026-06-23T15:11:06.815Z", "projectName": "Swerve Robot (Example)", "nodes": [ { @@ -30,6 +30,7 @@ "gauge": "6 AWG", "fitting": "Anderson SB50", "breaker": null, + "slot": null, "requiredFittings": [ "Anderson SB50", "Ring Terminal" @@ -64,6 +65,7 @@ "gauge": "6 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -77,6 +79,7 @@ "gauge": "6 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -110,6 +113,7 @@ "gauge": "6 AWG", "fitting": "Anderson SB50", "breaker": null, + "slot": null, "requiredFittings": [ "Anderson SB50", "Ring Terminal" @@ -124,6 +128,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire" @@ -138,6 +143,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire" @@ -152,6 +158,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -166,6 +173,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -180,6 +188,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -194,6 +203,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -208,6 +218,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -222,6 +233,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -236,6 +248,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -250,6 +263,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -264,6 +278,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -278,6 +293,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -292,6 +308,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -306,6 +323,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -320,6 +338,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -334,6 +353,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -348,6 +368,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -362,6 +383,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -376,6 +398,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -390,6 +413,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -404,6 +428,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -418,6 +443,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": 40, + "slot": "breaker", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -429,9 +455,10 @@ "label": "CH20", "side": "left", "order": 10, - "gauge": "12 AWG", + "gauge": "18 AWG", "fitting": "Ferrule", "breaker": 10, + "slot": "fuse", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -443,9 +470,10 @@ "label": "CH21", "side": "left", "order": 11, - "gauge": "12 AWG", + "gauge": "18 AWG", "fitting": "Ferrule", "breaker": 10, + "slot": "fuse", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -457,9 +485,10 @@ "label": "CH22", "side": "left", "order": 12, - "gauge": "12 AWG", + "gauge": "18 AWG", "fitting": "Ferrule", "breaker": 10, + "slot": "fuse", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -471,9 +500,10 @@ "label": "CH23", "side": "left", "order": 13, - "gauge": "12 AWG", + "gauge": "18 AWG", "fitting": "Ferrule", - "breaker": 40, + "breaker": 10, + "slot": "fuse", "requiredFittings": [ "Ferrule", "Bare Wire" @@ -508,6 +538,7 @@ "gauge": "12 AWG", "fitting": "Ferrule", "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire" @@ -522,6 +553,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire" @@ -536,29 +568,36 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": null }, { "id": "roborio2-p-37", "type": "USB", - "label": "USB1", + "label": "USB-A", "side": "right", "order": 0, "gauge": null, "fitting": null, "breaker": null, - "requiredFittings": null + "slot": null, + "requiredFittings": [ + "USB-A" + ] }, { "id": "roborio2-p-38", "type": "USB", - "label": "USB2", + "label": "USB-A", "side": "right", "order": 1, "gauge": null, "fitting": null, "breaker": null, - "requiredFittings": null + "slot": null, + "requiredFittings": [ + "USB-A" + ] }, { "id": "roborio2-p-39", @@ -569,6 +608,7 @@ "gauge": "18 AWG", "fitting": "Ferrule", "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire" @@ -603,6 +643,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": null }, { @@ -614,6 +655,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": null }, { @@ -625,6 +667,7 @@ "gauge": "18 AWG", "fitting": "Ferrule", "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire" @@ -639,6 +682,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": null }, { @@ -650,6 +694,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": null } ] @@ -681,6 +726,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -694,6 +740,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -709,6 +756,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -744,6 +792,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -757,6 +806,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -772,6 +822,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -807,10 +858,11 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ + "Molex SL", "Ferrule", - "Bare Wire", - "JST" + "Bare Wire" ] } ] @@ -842,6 +894,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -855,6 +908,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -870,6 +924,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -905,6 +960,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -918,6 +974,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -933,6 +990,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -968,10 +1026,11 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ + "Molex SL", "Ferrule", - "Bare Wire", - "JST" + "Bare Wire" ] } ] @@ -1003,6 +1062,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -1016,6 +1076,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1031,6 +1092,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1066,6 +1128,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -1079,6 +1142,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1094,6 +1158,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1129,10 +1194,11 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ + "Molex SL", "Ferrule", - "Bare Wire", - "JST" + "Bare Wire" ] } ] @@ -1164,6 +1230,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -1177,6 +1244,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1192,6 +1260,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1227,6 +1296,7 @@ "gauge": "12 AWG", "fitting": "Ring Terminal", "breaker": null, + "slot": null, "requiredFittings": [ "Ring Terminal" ] @@ -1240,6 +1310,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1255,6 +1326,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ "Ferrule", "Bare Wire", @@ -1290,10 +1362,11 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": [ + "Molex SL", "Ferrule", - "Bare Wire", - "JST" + "Bare Wire" ] } ] @@ -1325,6 +1398,7 @@ "gauge": null, "fitting": null, "breaker": null, + "slot": null, "requiredFittings": null } ] @@ -1406,7 +1480,7 @@ "layerId": "power", "color": null, "color2": null, - "wireGauge": "12 AWG", + "wireGauge": "18 AWG", "wireFittingFrom": "Ferrule", "wireFittingTo": "Ferrule", "label": "PWR003", @@ -1429,7 +1503,7 @@ "layerId": "power", "color": null, "color2": null, - "wireGauge": "12 AWG", + "wireGauge": "18 AWG", "wireFittingFrom": "Ferrule", "wireFittingTo": "Ferrule", "label": "PWR004", diff --git a/src/components/canvas/ComponentNode.jsx b/src/components/canvas/ComponentNode.jsx index 931ea69..da00d69 100644 --- a/src/components/canvas/ComponentNode.jsx +++ b/src/components/canvas/ComponentNode.jsx @@ -25,15 +25,20 @@ const SIDE_POSITION = { left: Position.Left, }; +const FUSE_RING = '#67e8f9'; // cyan — marks a miniature blade-fuse slot + function handleStyle(port, f) { const pct = `${f * 100}%`; const color = typeColor(port.type); + // Miniature fuse slots (PDH ch20–23, MPM) render as a square cyan-ringed dot + // so they read distinctly from the round full-size breaker/signal ports. + const isFuse = port.slot === 'fuse'; const base = { - width: 8, - height: 8, + width: isFuse ? 9 : 8, + height: isFuse ? 9 : 8, background: color, - border: '1px solid #111113', - borderRadius: '50%', + border: isFuse ? `1px solid ${FUSE_RING}` : '1px solid #111113', + borderRadius: isFuse ? 2 : '50%', }; if (port.side === 'left') return { ...base, left: -4, top: pct }; if (port.side === 'right') return { ...base, right: -4, top: pct }; @@ -170,11 +175,26 @@ function ComponentNode({ id, data, selected }) { {p.label} - {p.type === 'PWR' && p.breaker != null && ( - - {p.breaker}A - - )} + {p.type === 'PWR' && p.breaker != null && + (p.slot === 'fuse' ? ( + + {p.breaker}A + + ) : ( + + {p.breaker}A + + ))} ))} diff --git a/src/components/modal/ComponentConfigModal.jsx b/src/components/modal/ComponentConfigModal.jsx index b7e7c46..15c12dc 100644 --- a/src/components/modal/ComponentConfigModal.jsx +++ b/src/components/modal/ComponentConfigModal.jsx @@ -9,11 +9,11 @@ import { FITTING_OPTIONS, typeHasGaugeFitting, typeGroup, + slotRatings, } from '../../data/wireTypes'; const SIDES = ['top', 'right', 'bottom', 'left']; -const BREAKER_OPTIONS = [10, 20, 30, 40]; // legal FRC branch breaker/fuse ratings (R619) -// Only power-distribution devices expose per-output breaker selection. +// Only power-distribution devices expose per-output breaker/fuse selection. const BREAKER_DEFS = new Set(['pdh', 'pdp2', 'pdp_legacy', 'mpm']); const uuid = () => crypto.randomUUID(); @@ -197,36 +197,52 @@ export default function ComponentConfigModal({ nodeId, onClose, onSelectEdge }) )} - {/* branch-breaker grid — power-distribution outputs only (PDH/PDP/MPM). - Excludes the main PWR input; covers CH* (PDH/PDP) and A–D (MPM). */} + {/* branch breaker / fuse grid — power-distribution outputs only + (PDH/PDP/MPM). Excludes the main PWR input. Each channel offers the + rating set for its slot: full-size ATO breakers (10–40 A) or + miniature ATM blade fuses (≤15 A, PDH ch20–23 + every MPM channel). */} {(() => { if (!BREAKER_DEFS.has(def.id)) return null; - const channels = data.ports.filter((p) => p.type === 'PWR' && p.label !== 'PWR'); + const channels = data.ports.filter( + (p) => p.type === 'PWR' && p.label !== 'PWR' && p.label !== 'PWR IN' + ); if (!channels.length) return null; + const hasFuse = channels.some((p) => p.slot === 'fuse'); + const hasBreaker = channels.some((p) => (p.slot ?? 'breaker') !== 'fuse'); + const heading = + hasFuse && hasBreaker ? 'Output breakers / fuses' : hasFuse ? 'Output fuses' : 'Output breakers'; return (

- 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 = {