Skip to the content
PCBKitNew board
4 layers63.2 × 54.2 mmRaven, the printed circuit board in 3D

Autonomous can-collecting robot for the MIT MASLAB 2026 competition. Features dual-camera vision, YOLOv11 segmentation, path planning with Theta, and a distributed architecture with Pi-side execution and computer-side…

Size
63.2 × 54.2 mm
Copper layers
4
Thickness
1.61 mm
Parts
198
Nets
170
Pads
679
Tracks, vias
1,543, 409
Pours
30
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
24 Feb 2026
Updated
24 Feb 2026

Overview

Raven is an open-source printed circuit board by jguo22, from the jguo22/MDS repository on GitHub. It is a 4-layer board of 63.2 × 54.2 mm with 198 parts on 170 nets, routed with 1,543 tracks and 409 vias.

It is built around the QMC5883L, TPS548B28RWWR and 74HC595, with the ICM-42688-P, AO3400A and DMP2002UPS among its other parts. Its parts include 67 capacitors, 64 resistors, 25 connectors, 17 diodes and 10 ICs. It belongs with the STM32 boards of this library.

Main components

6

README

README.md

MASLAB 2026 Autonomous Robot

https://maslab.mit.edu/2026/wiki/team02

Autonomous can-collecting robot for the MIT MASLAB 2026 competition. Features dual-camera vision, YOLOv11 segmentation, path planning with Theta*, and a distributed architecture with Pi-side execution and computer-side control.

Architecture

text
┌─────────────────────────────────────────────────────────────────────┐
│                          Computer                                    │
│  ┌─────────────────┐    ┌──────────────────┐    ┌────────────────┐  │
│  │ ComputerReceiver│◄───│  RobotHandler    │◄───│ Vision (YOLO)  │  │
│  │ (video in,      │    │  State Machine   │    │ Segmentation   │  │
│  │  commands out)  │    │  + Theta* Path   │    │ + Pixel-to-3D  │  │
│  └────────┬────────┘    └──────────────────┘    └────────────────┘  │
│           │                                                          │
│           │ TCP (video: 5000, commands: 5001)                        │
│           ▼                                                          │
│  ┌─────────────────┐                                                 │
│  │RemoteRobotCmd   │ ◄── IRobotCommander interface                   │
│  └─────────────────┘                                                 │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              │ Network
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│                        Raspberry Pi                                  │
│  ┌─────────────────┐    ┌──────────────────┐    ┌────────────────┐  │
│  │  PiStreamer     │───►│ DirectRobotCmd   │───►│ Nav + Raven    │  │
│  │  (video out,    │    │ (local execution)│    │ Motor Control  │  │
│  │   commands in)  │    └──────────────────┘    └────────────────┘  │
│  └─────────────────┘                                                 │

Quick Start

Computer Side

bash
# Install dependencies
pip install -e .

# Run computer receiver (waits for Pi connection)
python main_comp.py

Pi Side

bash
# Install dependencies
pip install -e .

# Run Pi streamer (auto-reconnects to computer)
python main_pi.py --camera-top /dev/videoblacktop --camera-bottom /dev/videoblackbot

Project Structure

text
MDS/
├── main_comp.py              # Computer entry point (receiver + vision + state machine)
├── main_pi.py                # Pi entry point (streamer + command execution)
│
├── IRobotCommander.py        # Abstract interface for robot commands
├── RemoteRobotCommander.py   # Network implementation (computer side)
├── DirectRobotCommander.py   # Direct execution (Pi side)
│
├── RobotHandler.py           # Full state machine with zone/can tracking
├── RobotHandler_Simple.py    # Simplified state machine for basic collection
│
├── thetaStar.py              # Theta* path planning with obstacle avoidance
├── nav.py                    # Navigation controller (IMU + odometry)
├── navHelpers.py             # Movement command generators
│
├── raven.py                  # Raven motor controller driver
├── RavenWrapper.py           # High-level Raven interface (gripper, elevator)
├── IMUWrapper.py             # BNO08x IMU wrapper
├── distanceSensorWrapper.py  # Distance sensor for can approach
│
├── config.py                 # Robot configuration constants
├── colors.py                 # YOLO class names and color constants
├── getPickedCanColor.py      # Detect color of can in gripper
│

Vision System

YOLO Segmentation

Custom YOLOv11n model trained on 8 classes:

  • Boundary (0), Golden Can (1), Golden Zone (2)
  • Green Can (3), Green Zone (4), Red Can (5), Red Zone (6), Robot (7)
python
from vision.segment import segmentImage
from vision.can_utils import getCans
from vision.zone_utils import getZones

result = segmentImage(image)  # Run YOLO segmentation
cans, can_classes = getCans(result, image, is_top=True)  # Get can positions (mm)
zones, zone_classes = getZones(result, image, is_top=True)  # Get zone quads (mm)

Pixel-to-World Transformation

Transforms pixel coordinates to ground plane (mm) using camera calibration:

python
from vision.pixelTo3D import transform_uv_to_xy

# pixel (u, v) -> world (x, y) in mm
x, y = transform_uv_to_xy(pixel_x, pixel_y, is_top=True)

Coordinate Transformations

SE2-based world/relative coordinate conversion:

python
from spatialmath import SE2
from vision.relativeCoordinates import world_to_relative, relative_to_world

robot_pose = SE2(robot_x, robot_y, robot_heading)
local_x, local_y = world_to_relative(world_point, robot_pose)
world_x, world_y = relative_to_world(local_point, robot_pose)

Gripper Can Detection

Detect which color can is currently in the gripper:

python
from getPickedCanColor import getPickedUpCanColor

color = getPickedUpCanColor(result, image)  # Returns 'Green Can', 'Red Can', etc.

Robot Commander Interface

All robot commands go through IRobotCommander, with two implementations:

MethodDescription
override_movement(args)Raw motor commands [left, right, ticks, ...]
override_waypoints(args)Navigate through waypoints [x1, y1, x2, y2, ...]
override_relative_xy(x, y)Move relative to robot (mm)
override_world_xy(x, y)Navigate to world coordinates (mm)
pickup_can()Close gripper + raise elevator
set_down_can()Lower elevator + open gripper
open_gripper()Open gripper only
lower_elevator()Lower elevator only
approach_can_with_ds()Approach can using distance sensor
backup()Back up short distance
stack(temp, stack, count)Stack can at position
waitFinishedMoving()Block until movement complete

State Machines

RobotHandler (Full)

Complex state machine with:

  • Zone confidence tracking
  • Can detection grid with thresholds
  • Opponent zone avoidance
  • Full early game strategy

RobotHandler_Simple (Simplified)

Basic can collection:

text
SearchForCan -> MoveToCan -> ApproachingCan -> GrabCan -> MoveToZone -> Done

Configuration:

  • MAX_STACK: Number of cans to collect before going to zone
  • target_zone: Which zone to deliver to (GREEN_ZONE, RED_ZONE, GOLDEN_ZONE)
  • target_can_color: Which color cans to collect

Hardware

Raven Motor Controller

Custom serial motor controller (460800 baud):

  • 5 motor channels, 4 servo channels
  • Position/velocity PID control
  • Built-in odometry

IMU (BNO08x)

  • Must initialize before Raven board
  • Heading relative to startup position

Distance Sensor

  • Used for precise can approach
  • Target distance: 25mm, Max detection: 500mm

Network Protocol

TCP-based with custom framing:

  • Video port: 5000 (JPEG frames)
  • Command port: 5001 (typed messages with float arrays)

Message types defined in connection/message_types.py:

python
OVERRIDE_MOVEMENTS = 2      # [left, right, ticks, ...]
OVERRIDE_WAYPOINTS = 3      # [x1, y1, x2, y2, ...]
PICKUP_CAN = 4              # No args
RELEASE_CAN = 5             # No args
APPROACH_CAN_DS = 9         # No args
OPEN_GRIPPER = 15           # No args
LOWER_ELEVATOR = 16         # No args
# ... and more

Configuration

Key constants in config.py:

python
FRAME_WIDTH = 640
FRAME_HEIGHT = 480
FPS = 30

CAN_DIAMETER = 76.2         # mm
ROBOT_DIAMETER = 300        # mm
CLAW_OFFSET = 150           # mm from robot center
APPROACH_OFFSET = 200       # mm approach distance

Development

Testing Vision

bash
# Test segmentation on image
python vision/segment.py

# Test can detection
python getPickedCanColor.py

Training YOLO

bash
cd vision/train
python train.py

Debugging

  • Frames auto-saved to images/ with cooldown
  • Telemetry streamed via Streamer class
  • Profile data saved to profiles/

Dependencies

See pyproject.toml:

  • ultralytics (YOLO)
  • opencv-python
  • numpy
  • spatialmath-python
  • shapely
  • adafruit-circuitpython-bno08x (Pi only)
  • pyserial (Pi only)

Parts

198
QtyValueFootprintReferences
317k5Resistor_SMD:R_0402_1005MetricR25, R26, R28, R29, R30, R31, R32, R33, R34, R35, R36, R37, R38, R39, R40, R41 +15
281kResistor_SMD:R_0402_1005MetricR1, R2, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23 +12
20100nCapacitor_SMD:C_0402_1005MetricC2, C4, C10, C14, C16, C18, C19, C21, C24, C26, C30, C31, C34, C35, C36, C39 +4
1522uCapacitor_SMD:C_0805_2012MetricC13, C50, C51, C52, C53, C54, C57, C58, C59, C60, C61, C62, C63, C64, C65
72u2Capacitor_SMD:C_0402_1005MetricC3, C6, C9, C15, C20, C25, C67
7GLEDLED_SMD:LED_0603_1608MetricD1, D3, D6, D9, D12, D14, D27
61uCapacitor_SMD:C_0402_1005MetricC37, C38, C46, C47, C48, C49
522nCapacitor_SMD:C_0402_1005MetricC5, C17, C22, C27, C69
5Conn_01x02_PinConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ4, J6, J7, J8, J9
5Conn_01x04_PinConnector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_VerticalJ14, J15, J16, J17, J18
5DRV8874PWPRPackage_SO:HTSSOP-16-1EP_4.4x5mm_P0.65mm_EP3.4x5mm_Mask2.46x2.31mmU1, U4, U5, U6, U30
5RLEDLED_SMD:LED_0603_1608MetricD4, D7, D10, D13, D28
5Screw_Terminal_01x02TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2_1x02_P5.00mm_HorizontalJ20, J26, J27, J28, J29
5WLEDLED_SMD:LED_0603_1608MetricD2, D5, D8, D11, D26
447uCapacitor_SMD:C_1206_3216MetricC40, C41, C42, C43
4Conn_01x03_PinConnector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_VerticalJ21, J22, J23, J24
4MountingHole_PadMountingHole:MountingHole_2.5mm_PadH1, H2, H3, H4
212pCapacitor_SMD:C_0402_1005MetricC32, C33
2220nCapacitor_SMD:C_0402_1005MetricC11, C44
256kResistor_SMD:R_0402_1005MetricR53, R57
2Conn_01x04_MountingPinConnector_JST:JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_HorizontalJ2, J5
2LOGOLOGOG1, G2
2SW_PushFootprints:TS-1088SW1, SW2
1100kResistor_SMD:R_0402_1005MetricR58
1100nCapacitor_SMD:C_0603_1608MetricC23
1100uCapacitor_SMD:C_Elec_8x6.2C1
110uCapacitor_SMD:C_0603_1608MetricC28
110uCapacitor_SMD:C_0402_1005MetricC55
116MHzCrystal:Crystal_SMD_3225-4Pin_3.2x2.5mmY1
11uFootprints:L_0660AL1
12u2Capacitor_SMD:C_0805_2012MetricC45
133kResistor_SMD:R_0402_1005MetricR24
147kResistor_SMD:R_0402_1005MetricR56
14u7Capacitor_SMD:C_0603_1608MetricC12
174HC595Package_SO:SOIC-16_3.9x9.9mm_P1.27mmU8
1AO3400APackage_TO_SOT_SMD:SOT-23Q1
1Conn_01x02_PinConnector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_VerticalJ11
1Conn_01x02_PinConnector_AMASS:AMASS_XT30UPB-M_1x02_P5.0mm_VerticalJ3
1Conn_02x20_Odd_EvenConnector_PinSocket_2.54mm:PinSocket_2x20_P2.54mm_VerticalJ1
1Conn_ARM_SWD_TagConnect_TC2030-NLConnector:Tag-Connect_TC2030-IDC-NL_2x03_P1.27mm_VerticalJ10
1DMP2002UPSFootprints:DMP2002UPSQ3
1FerriteBeadInductor_SMD:L_0805_2012MetricFB1
1FuseFuse:Fuse_1206_3216MetricF1
1ICM-42688-PPackage_LGA:LGA-14_3x2.5mm_P0.5mm_LayoutBorder3x4yU2
1NetTie_2NetTie:NetTie-2_SMD_Pad0.5mmNT1
1QMC5883LPackage_LGA:LGA-16_3x3mm_P0.5mmU3
1STM32G431CBUxPackage_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.6x5.6mmU7
1TPS548B28RWWRFootprints:TPS548B28RWWRU9

Questions

How big is the Raven PCB?

It measures 63.2 × 54.2 mm and has 4 copper layers, 1.61 mm thick.

What parts does the Raven use?

198 parts, built around the QMC5883L, TPS548B28RWWR, 74HC595 and ICM-42688-P. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Raven KiCad files?

From the jguo22/MDS repository on GitHub, at the commit this page was made from: the board is raven/pcb/raven.kicad_pcb and its schematic raven/pcb/encoder.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Raven design in my own project?

Its repository states no licence, so its author keeps all rights: ask jguo22 before reusing the design.

Similar boards

  • 4 layers108 × 74 mmSTM32 Drone, the printed circuit board in 3D

    STM32 Drone

    bassammorsy/stm32-flight-controller

    Custom 4-layer STM32F405RGTx quadcopter flight controller PCB designed in KiCad. Betaflight compatible, 4S–6S LiPo input, SMT assembled by JLCPCB.

    104 parts3MIT
  • 4 layers94.7 × 69.1 mmVariometerV2.2.1, the printed circuit board in 3D

    VariometerV2.2.1

    oiver12/VariometerV2

    Paragliding variometer: custom KiCad PCBs, ESP32 firmware, sensor fusion, e-ink UI, and desktop flight replay.

    158 partsMIT
  • 4 layers169 × 71.3 mmB.B V1.1, the printed circuit board in 3D

    B.B V1.1

    RoboticsBrno/RB3203-BlackBox

    258 parts
  • 4 layers55 × 55 mmThetaAnomalain, the printed circuit board in 3D

    ThetaAnomalain

    Barsy-Barsevich/Barsotion-TA

    Board computer for model rockets

    110 parts1GPL-3.0
  • 2 layers40.9 × 84.4 mmBicycle board, the printed circuit board in 3D

    Bicycle board

    XuHg-zjcn/bicycle_board

    a PCB board for bicycle

    158 partsCERN-OHL-S-2.0
  • 6 layers39.5 × 39.5 mmLEVIA H7, the printed circuit board in 3D

    LEVIA H7

    piecol/LEVIA-H7

    Open hardware STM32H743 drone flight controller

    173 parts71CERN-OHL-S-2.0
  • 4 layers80.4 × 49.3 mmLeany, the printed circuit board in 3D

    Leany

    gilleshenrard/leany

    STM32 ARM Core-M3 based inclinometer

    83 parts3
  • 2 layers238 × 114 mmPanel, the printed circuit board in 3D

    Panel

    sbarisic/MagMouse

    Open source hall-effect based mouse - no mechanical contacts - no failure points

    384 parts2