Created
January 24, 2026 08:22
-
-
Save aphexcx/e4521fb10b00e32dca5b57b607ca3319 to your computer and use it in GitHub Desktop.
M20 Relay Architecture Diagrams
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 500" fill="none"> | |
| <defs> | |
| <linearGradient id="browserGrad" x1="0%" y1="0%" x2="100%" y2="100%"> | |
| <stop offset="0%" style="stop-color:#3B82F6;stop-opacity:1" /> | |
| <stop offset="100%" style="stop-color:#1D4ED8;stop-opacity:1" /> | |
| </linearGradient> | |
| <linearGradient id="relayGrad" x1="0%" y1="0%" x2="100%" y2="100%"> | |
| <stop offset="0%" style="stop-color:#10B981;stop-opacity:1" /> | |
| <stop offset="100%" style="stop-color:#059669;stop-opacity:1" /> | |
| </linearGradient> | |
| <linearGradient id="ros2Grad" x1="0%" y1="0%" x2="100%" y2="100%"> | |
| <stop offset="0%" style="stop-color:#F59E0B;stop-opacity:1" /> | |
| <stop offset="100%" style="stop-color:#D97706;stop-opacity:1" /> | |
| </linearGradient> | |
| <linearGradient id="hwGrad" x1="0%" y1="0%" x2="100%" y2="100%"> | |
| <stop offset="0%" style="stop-color:#EF4444;stop-opacity:1" /> | |
| <stop offset="100%" style="stop-color:#DC2626;stop-opacity:1" /> | |
| </linearGradient> | |
| <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"> | |
| <feDropShadow dx="2" dy="4" stdDeviation="4" flood-opacity="0.15"/> | |
| </filter> | |
| </defs> | |
| <!-- Title --> | |
| <text x="450" y="35" text-anchor="middle" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" fill="#1F2937">M20 Relay Architecture</text> | |
| <text x="450" y="55" text-anchor="middle" font-family="system-ui, sans-serif" font-size="14" fill="#6B7280">Browser-to-Dog Communication</text> | |
| <!-- Browser Box --> | |
| <g filter="url(#shadow)"> | |
| <rect x="40" y="120" width="180" height="140" rx="12" fill="url(#browserGrad)"/> | |
| <text x="130" y="155" text-anchor="middle" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" fill="white">Browser</text> | |
| <text x="130" y="175" text-anchor="middle" font-family="system-ui, sans-serif" font-size="12" fill="rgba(255,255,255,0.8)">(Houdini App)</text> | |
| <line x1="60" y1="190" x2="200" y2="190" stroke="rgba(255,255,255,0.3)" stroke-width="1"/> | |
| <text x="130" y="210" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">WebSocket Client</text> | |
| <text x="130" y="228" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">WebRTC Video/Audio</text> | |
| <text x="130" y="246" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">Gamepad/Keyboard</text> | |
| </g> | |
| <!-- Tailscale Cloud --> | |
| <g filter="url(#shadow)"> | |
| <ellipse cx="360" cy="190" rx="100" ry="50" fill="#E5E7EB" stroke="#9CA3AF" stroke-width="2"/> | |
| <text x="360" y="185" text-anchor="middle" font-family="system-ui, sans-serif" font-size="14" font-weight="bold" fill="#4B5563">Tailscale VPN</text> | |
| <text x="360" y="205" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="#6B7280">Secure Mesh Network</text> | |
| </g> | |
| <!-- M20 Relay Box --> | |
| <g filter="url(#shadow)"> | |
| <rect x="520" y="100" width="200" height="180" rx="12" fill="url(#relayGrad)"/> | |
| <text x="620" y="130" text-anchor="middle" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" fill="white">M20 Relay</text> | |
| <text x="620" y="148" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.8)">(On Robot Computer)</text> | |
| <line x1="540" y1="160" x2="700" y2="160" stroke="rgba(255,255,255,0.3)" stroke-width="1"/> | |
| <text x="620" y="180" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">FastAPI + WebSocket</text> | |
| <text x="620" y="198" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">ROS2 Bridge (rclpy)</text> | |
| <text x="620" y="216" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">go2rtc (RTSP→WebRTC)</text> | |
| <text x="620" y="234" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">GStreamer Audio</text> | |
| <text x="620" y="260" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="rgba(255,255,255,0.7)">Port 8000 (WS) | 1984 (WebRTC)</text> | |
| </g> | |
| <!-- ROS2 Box --> | |
| <g filter="url(#shadow)"> | |
| <rect x="760" y="120" width="120" height="140" rx="12" fill="url(#ros2Grad)"/> | |
| <text x="820" y="155" text-anchor="middle" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" fill="white">ROS2</text> | |
| <text x="820" y="173" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.8)">Foxy</text> | |
| <line x1="775" y1="185" x2="865" y2="185" stroke="rgba(255,255,255,0.3)" stroke-width="1"/> | |
| <text x="820" y="205" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="rgba(255,255,255,0.9)">/IMU_DATA</text> | |
| <text x="820" y="220" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="rgba(255,255,255,0.9)">/JOINTS_DATA</text> | |
| <text x="820" y="235" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="rgba(255,255,255,0.9)">/BATTERY_DATA</text> | |
| <text x="820" y="250" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="rgba(255,255,255,0.9)">/JOINTS_CMD</text> | |
| </g> | |
| <!-- Robot Hardware Box --> | |
| <g filter="url(#shadow)"> | |
| <rect x="620" y="340" width="200" height="130" rx="12" fill="url(#hwGrad)"/> | |
| <text x="720" y="375" text-anchor="middle" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" fill="white">Robot Hardware</text> | |
| <line x1="640" y1="390" x2="800" y2="390" stroke="rgba(255,255,255,0.3)" stroke-width="1"/> | |
| <text x="720" y="410" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">16 Joint Motors</text> | |
| <text x="720" y="428" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">IMU Sensor</text> | |
| <text x="720" y="446" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">RTSP Cameras (Front/Rear)</text> | |
| <text x="720" y="464" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="rgba(255,255,255,0.9)">Jabra Speak 510 USB</text> | |
| </g> | |
| <!-- Arrows --> | |
| <!-- Browser to Tailscale --> | |
| <path d="M220 175 L255 175" stroke="#3B82F6" stroke-width="3" marker-end="url(#arrowBlue)"/> | |
| <path d="M255 205 L220 205" stroke="#3B82F6" stroke-width="3" marker-end="url(#arrowBlue)"/> | |
| <!-- Tailscale to Relay --> | |
| <path d="M460 175 L515 175" stroke="#10B981" stroke-width="3" marker-end="url(#arrowGreen)"/> | |
| <path d="M515 205 L460 205" stroke="#10B981" stroke-width="3" marker-end="url(#arrowGreen)"/> | |
| <!-- Relay to ROS2 --> | |
| <path d="M720 190 L755 190" stroke="#F59E0B" stroke-width="3" marker-end="url(#arrowOrange)"/> | |
| <!-- ROS2 to Hardware --> | |
| <path d="M820 260 L820 300 L720 300 L720 335" stroke="#EF4444" stroke-width="3" marker-end="url(#arrowRed)"/> | |
| <!-- Arrow markers --> | |
| <defs> | |
| <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> | |
| <polygon points="0 0, 10 3.5, 0 7" fill="#3B82F6"/> | |
| </marker> | |
| <marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> | |
| <polygon points="0 0, 10 3.5, 0 7" fill="#10B981"/> | |
| </marker> | |
| <marker id="arrowOrange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> | |
| <polygon points="0 0, 10 3.5, 0 7" fill="#F59E0B"/> | |
| </marker> | |
| <marker id="arrowRed" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> | |
| <polygon points="0 0, 10 3.5, 0 7" fill="#EF4444"/> | |
| </marker> | |
| </defs> | |
| <!-- Data flow labels --> | |
| <rect x="225" y="145" width="95" height="20" rx="4" fill="#F3F4F6"/> | |
| <text x="272" y="159" text-anchor="middle" font-family="system-ui, sans-serif" font-size="9" fill="#4B5563">Commands</text> | |
| <rect x="225" y="210" width="95" height="20" rx="4" fill="#F3F4F6"/> | |
| <text x="272" y="224" text-anchor="middle" font-family="system-ui, sans-serif" font-size="9" fill="#4B5563">Telemetry/Video</text> | |
| <rect x="460" y="145" width="55" height="20" rx="4" fill="#F3F4F6"/> | |
| <text x="487" y="159" text-anchor="middle" font-family="system-ui, sans-serif" font-size="9" fill="#4B5563">WS/RTC</text> | |
| <!-- Legend --> | |
| <rect x="40" y="420" width="400" height="60" rx="8" fill="#F9FAFB" stroke="#E5E7EB"/> | |
| <text x="60" y="445" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" fill="#374151">Data Flow:</text> | |
| <circle cx="150" cy="441" r="6" fill="#3B82F6"/> | |
| <text x="162" y="445" font-family="system-ui, sans-serif" font-size="10" fill="#4B5563">WebSocket + WebRTC</text> | |
| <circle cx="280" cy="441" r="6" fill="#F59E0B"/> | |
| <text x="292" y="445" font-family="system-ui, sans-serif" font-size="10" fill="#4B5563">ROS2 Topics</text> | |
| <circle cx="380" cy="441" r="6" fill="#EF4444"/> | |
| <text x="392" y="445" font-family="system-ui, sans-serif" font-size="10" fill="#4B5563">Hardware I/O</text> | |
| <text x="60" y="468" font-family="system-ui, sans-serif" font-size="10" fill="#6B7280">Latency: Commands ~20ms | Video ~300ms | Audio ~50ms</text> | |
| </svg> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment