
M1Drop
Use this site while presenting: point to the pictures, show the iterations, and let the visuals carry the story.
One-glance takeaway: Push is dominant, Pull is limited, so we optimize push-first and keep one reliable pull attachment.
Sorted by Action Type: Push → Push/Pull → Pull → Lift → Drop















M5
M6
M7
M8
M9
M10
M1
M2
M3
M4
M11
M13
M15Passive mechanism progression for cleaner trigger flow.




Tip control evolution for repeatable pan contact.




Pickup geometry tuned for more reliable retrieval.




Lift geometry evolved toward stable drop positioning.


Underside approach refined for faster transitions.




#!/usr/bin/env pybricks-micropython
"""
FLL Season PID Drive Straight Module
Maintains accurate heading using gyro feedback and proportional correction.
"""
from pybricks.hubs import EV3Brick
from pybricks.ev3devices import Motor, GyroSensor
from pybricks.parameters import Port, Direction
from pybricks.tools import wait
# Initialize hardware
ev3_brick = EV3Brick()
gyro_sensor = GyroSensor(Port.S3)
left_motor = Motor(Port.B, positive_direction=Direction.FORWARD)
right_motor = Motor(Port.C, positive_direction=Direction.FORWARD)
# PID Configuration Constants
TARGET_HEADING_DEGREES = 0 # Maintain straight line (0° yaw)
KP_GAIN = 1.2 # Proportional gain: higher = stronger correction
MOTOR_BASE_SPEED_DPS = 360 # Base drive speed in degrees per second
# Drive Parameters
DRIVE_DISTANCE_MM = 1000 # Distance to drive straight
WHEEL_DIAMETER_MM = 55.0 # FLL standard wheel size
GEAR_RATIO = 1.0 # Direct drive (adjust if geared)
def calculate_wheel_rotation_degrees(distance_mm):
"""Convert linear distance to motor rotation in degrees."""
wheel_circumference = WHEEL_DIAMETER_MM * 3.14159
full_rotations = distance_mm / wheel_circumference
return full_rotations * 360
def pid_drive_straight(distance_mm, base_speed_dps):
"""
Drive straight using PID feedback from gyro sensor.
Args:
distance_mm: Distance to drive in millimeters
base_speed_dps: Base motor speed in degrees per second
"""
# Reset gyro heading to establish reference
gyro_sensor.reset_angle(0)
# Calculate target motor rotation
target_rotation_degrees = calculate_wheel_rotation_degrees(distance_mm)
# Motor position tracking
left_start_angle = left_motor.angle()
right_start_angle = right_motor.angle()
# PID error tracking for diagnostics
yaw_errors = []
# Main drive loop
while True:
# Calculate distance traveled (average of both motors)
left_current_angle = left_motor.angle()
right_current_angle = right_motor.angle()
average_rotation = (left_current_angle + right_current_angle) / 2
distance_traveled = average_rotation - (left_start_angle + right_start_angle) / 2
# Check if target distance reached
if distance_traveled >= target_rotation_degrees:
left_motor.stop()
right_motor.stop()
ev3_brick.speaker.beep(frequency=1000, duration=50)
break
# Read current heading from gyro
current_heading = gyro_sensor.angle()
# Calculate heading error (deviation from target)
heading_error = current_heading - TARGET_HEADING_DEGREES
# Store error for analysis
yaw_errors.append(heading_error)
# PID Correction: proportional only (P-controller)
# Negative error = heading right, positive = heading left
correction_speed = -1 * KP_GAIN * heading_error
# Apply correction by differential motor speed
left_motor_speed = base_speed_dps + correction_speed
right_motor_speed = base_speed_dps - correction_speed
# Send commands to motors
left_motor.run(left_motor_speed)
right_motor.run(right_motor_speed)
# Small delay for sensor reading cycle
wait(10)
# Calculate and log performance metrics
average_error = sum(yaw_errors) / len(yaw_errors) if yaw_errors else 0
max_error = max(yaw_errors) if yaw_errors else 0
ev3_brick.speaker.say(f"Drive complete. Avg error: {average_error:.2f} degrees")
return {
"average_yaw_error": average_error,
"max_yaw_error": max_error,
"trials": len(yaw_errors)
}
# Main execution
if __name__ == "__main__":
ev3_brick.speaker.beep()
# Run drive straight test
results = pid_drive_straight(
distance_mm=DRIVE_DISTANCE_MM,
base_speed_dps=MOTOR_BASE_SPEED_DPS
)
ev3_brick.speaker.say(f"Complete")
Pybricks + PID correction achieved 94.2% consistency by continuously adjusting motor power based on gyro heading feedback.