- 🛠️ October 1, 2024: Started to build a drivetrain based on this design.
- 🎯 October 7, 2024: Started building the catapult based on this design.
- 🔧 October 8, 2024: Finished the drivetrain and now moving on to the tensioning system.
- ⚙️ October 11, 2024: Finished tensioning system, now moving onto the catapult.
- 📦 October 13, 2024: Finished catapult, now making intake rollers.
- 🚀 October 14, 2024: Finished robot, now working on quality of life improvements.
- 🧭 October 15, 2024: Added distance sensor to detect when the catapult is lowered and to stop movement.
- 💻 October 16, 2024: Added code to use this distance sensor (Patch V1.0.1).
- 🔧 October 16, 2024: Robot Patch - Added the following improvements:
- 💡 October 17, 2024: Added LED's and partial autonomous support.
- 🎊 Feb 18, 2025: We got the invite to worlds and we are now starting to prepare for worlds.
- Tuned tensioning system to add presets to top and bottom goal
- Nothing More
- 🎮 Added partial autonomous support
- ⏳ Changed the amount of time the tensioner rotates to improve accuracy
- 💡 Added LED support on ports 12 and 9
- ⏳ Added timer
- ⚙️ Added automatic lowering and detection when the catapult is lowered
- 🎮 Added 1 button to both wind-up catapult and to release
- 🔄 Preset wind back strength changed up by around 0.3 rotations to make it go in
- 🕒 L3 now starts a 1-minute timer with a sound at 35, 25, and 0 seconds remaining
- 🔒 Also stops all movement after the timer is finished
- 🔄 R3 does not reset movement from being stopped after the timer finishes
- 🛠️ Added clearer motor names (launcher, tensioning, launcher_detector, intake)
- 📝 Added comments to make the code clear
Full Changelog: Code V1.0.1 Changelog
- ⏱️ Timer with audio cues
- 🧮 Score calculation
- 🔄 Reset functionality
- 📊 Real-time point tracking
- 🎯 Goal scoring system
- 🔄 Pass counter
- 📈 Score progression tracking
- 📊 Moving averages analysis
- 📉 Score distribution visualization
- ⚖️ Performance consistency metrics
- 📈 Score growth rate analysis
- 🎯 Performance heatmap
- 📊 Momentum index tracking
- 📈 Advanced statistics including:
- Performance consistency index
- Peak performance frequency
- Recovery rate
- Performance efficiency
- Trend strength
- Performance volatility
- 📊 Skill acquisition rate analysis
- 🎯 Relative performance indexing
- 📋 Game rules overview
- 🎯 Scoring system explanation
- 🤖 Robot Requirements
- 🏁 Match Rules
- ⚖️ Penalty Rules
- 📱 Mobile-friendly layout
- 🔍 Easy navigation
- 📖 Links to official documentation
- ✅ Works on desktop and mobile devices
- ✅ Chrome, Firefox, Safari, and Edge support
- ✅ Responsive design adapts to screen size
- ✅ Touch-friendly interface
- App for mobile devices
Full Changelog: Code V1.0.1 Changelog
- 🔧 Added toggle for timer visibility: Functionality to toggle timer on/off with a simple button press.
- 🎵 Enhanced audio functionality: Implemented the playback of audio at key countdown points using JavaScript's `Audio` API.
- 📊 Improved score calculation: JavaScript function dynamically calculates points based on the user’s inputs for goals, switches, and passes, providing instant feedback in the UI.
- 🛠️ Reset functionality added: Integrated a reset button to clear inputs and reset values on the point calculator.
- 🧩 Refined timer function: The `startPauseTimer()` function handles both countdown and regular timer modes, making the logic cleaner and more intuitive.
- ⏳ We implemented a timer that starts with a 3-second countdown and then runs for 1 minute.
- 🎵 During the countdown, an audio file (`Timer.mp3`) plays a beep at each second: 3, 2, 1.
- ⌛ The timer can be controlled using a start button.
- 🔄 You can toggle the visibility of the timer using the "Timer On/Off" toggle.
- 🖱️ Try the Timer Here!
Please Check if your system can run this code by looking at my recomended specs for this code
The system tracks yellow balls going into goals by:
- Detecting the yellow color
- Monitoring specific areas (goals)
- Tracking when balls enter and exit goals
- Calculating scores based on these movements
The system first needs to know what "yellow" looks like. It lets users click on a yellow ball to sample the color:
def sample_yellow_color(self, frame):
"""Sample yellow ball color from user click"""
print("\nYellow Ball Color Sampling:")
print("1. Click on a yellow ball")
print("2. Press 'r' to resample")
print("3. Press 'c' when satisfied with the color")
# When user clicks, we get the color at that point
if sample_point:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
color = hsv[sample_point[1], sample_point[0]]
# Create a range around that color
self.lower_yellow = np.array([max(0, color[0] - 10), 100, 100])
self.upper_yellow = np.array([min(180, color[0] + 10), 255, 255])
This creates a color range that will be used to detect yellow balls throughout the video.
The system needs to know where to look for balls. It can automatically detect goals or let users manually select them: Python
def auto_select_goals(self, frame):
"""Automatically detect goals with manual fallback"""
try:
# Convert to HSV for yellow detection
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Find yellow goal borders
yellow_mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
contours, _ = cv2.findContours(yellow_mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# Look for square/rectangular shapes
goal_contours = []
for contour in contours:
if len(approx) == 4: # If it has 4 corners
# Check if it's roughly square shaped
x, y, w, h = cv2.boundingRect(contour)
if 0.7 < float(w)/h < 1.3:
goal_contours.append(approx)
The system monitors each goal area for ball movement. Here's how it works: Python
def process_frame(self, frame):
"""Process single frame to detect scoring"""
current_time = time.time()
for i in range(4): # For each goal
# Check if there's yellow in the goal area
yellow_pixels = cv2.countNonZero(cv2.bitwise_and(yellow_mask, center_mask))
# Determine if goal is empty
is_empty = yellow_pixels <= 50
was_empty = self.goal_states[i]['is_empty']
# Track when balls enter/exit
if is_empty and not was_empty:
self.goal_states[i]['last_empty'] = current_time
elif not is_empty and was_empty:
self.goal_states[i]['entered_time'] = current_time
# Score detection logic
if not is_empty:
# Check if this is a valid score:
# 1. Enough time since last score
# 2. Ball was outside goal before
# 3. Ball entered recently
if (current_time - last_time >= 0.75 and
last_empty > 0 and
entered_time - last_empty >= 0.3 and
current_time - entered_time <= 0.2):
self.score['goals'] += 1
For Windows systems, there are specific optimizations: Python
class RapidRelayScorer:
def __init__(self):
# Performance optimizations
self.frame_queue = Queue(maxsize=2)
self.result_queue = Queue()
# Windows-specific optimizations
cv2.setNumThreads(4) # Optimize for quad-core processors
def process_video(self, source):
# Windows optimization: Set DirectShow backend
cap.set(cv2.CAP_PROP_BACKEND, cv2.CAP_DSHOW)
# Optimize buffer size
cap.set(cv2.CAP_PROP_BUFFERSIZE, 2)
-
Setup:
- User clicks on a yellow ball color
- System detects or user selects goals
- System initializes tracking
-
Processing Phase:
- Each frame is analyzed for yellow balls
- System tracks ball movement in goal areas
- Scores are calculated based on valid movements
- Data is stored and can be exported
-
Scoring Logic:
- Ball must be outside goal first
- Ball must enter goal area
- Movement must meet timing requirements
- Switch bonuses are calculated automatically
The system uses multiple checks to give accurate scoring:
- Time between scores
- Ball movement patterns
- Color detection thresholds
- Goal area monitoring
<div class="container mx-auto p-4">
<!-- Three-column grid -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
<!-- Left: Calculator -->
<!-- Middle: Live Scores -->
<!-- Right: Analytics -->
</div>
</div>
Purpose:
- Creates responsive 3-column layout
- Adapts to screen size (single column on mobile)
- Maintains consistent spacing and padding
- Uses Daisy UI and Tailwind CSS for frount end
// Button handlers for score adjustments
const buttons = {
'increase-goals': () => adjustValue('goals', 1),
'decrease-goals': () => adjustValue('goals', -1),
'increase-switches': () => adjustValue('switches', 1),
'decrease-switches': () => adjustValue('switches', -1)
};
function adjustValue(field, change) {
const input = document.getElementById(`${field}-display`);
let value = parseInt(input.value) + change;
// Validation for switches (max 4)
if (field === 'switches') {
value = Math.min(4, Math.max(0, value));
}
calculateScores(); // Recalculate after change
}
Features:
- Increment/decrement controls for each score type
- Input validation
- Automatic score recalculation
- Maximum limits enforcement so you cant have more than 4 switches etc
function calculateScores() {
let score = 0;
// Get input values
let goals = parseInt(document.getElementById('goals-display').value) || 0;
let switches = parseInt(document.getElementById('switches-display').value) || 0;
let passes = parseInt(document.getElementById('passes-display').value) || 0;
// Mode-specific calculations
if (mode === 'teamwork') {
// Teamwork scoring rules
if (switches === 0) {
passes = Math.min(passes, 4); // Max 4 passes without switches
} else {
passes = Math.min(passes, goals); // Can't pass more than goals
}
score = goals + switches + (passes * switchMultiplier);
} else {
// Skills scoring rules
const switchKey = [1, 4, 8, 10, 12, 12, 12, 12, 12];
score = (goals * switchKey[switches]) + switches;
}
updateDisplay(score);
return score;
}
Functionality:
- Handles both Teamwork and Skills modes
- Applies appropriate multipliers
- Validates input combinations
- Updates score display
let isRunning = false;
let timeLeft = 60;
let countdown = 3;
function startPauseTimer() {
if (!isRunning) {
// Start timer
isRunning = true;
if (document.getElementById("countdown-toggle").checked) {
startCountdown();
} else {
startMainTimer();
}
} else {
// Pause timer
clearInterval(timerInterval);
isRunning = false;
}
updateButtonDisplay();
}
function updateTimerDisplay(minutes, seconds) {
document.getElementById('timer-minutes').style.setProperty('--value', minutes);
document.getElementById('timer-seconds').style.setProperty('--value', seconds);
}
Features:
- 60-second match timer
- Optional 3-second countdown
- Start/pause functionality
- Audio alerts
- Visual countdown display
function saveScores() {
chrome.storage.sync.set({
scores: scores,
timestamp: new Date().toISOString()
});
}
function exportScores() {
const data = {
scores: scores,
mode: mode,
timestamp: new Date().toISOString(),
statistics: {
average: calculateAverage(),
highest: Math.max(...scores),
total: scores.length
}
};
// Create downloadable file
const blob = new Blob([JSON.stringify(data)],
{type: 'application/json'});
const url = URL.createObjectURL(blob);
downloadFile(url, 'vex-scores.json');
}
Capabilities:
- Persistent score storage
- JSON export format
- Statistical data inclusion
- Chrome storage sync
- File download generation
const chartConfig = {
responsive: true,
maintainAspectRatio: true,
interaction: {
mode: 'index',
intersect: false
},
plugins: {
legend: {
position: 'top',
labels: { usePointStyle: true }
}
}
};
function updateGraphs() {
// Score History
new Chart(ctx, {
type: 'line',
data: {
labels: timeLabels,
datasets: [{
label: 'Match Scores',
data: scores
}]
},
options: chartConfig
});
// Additional charts...
}
Features:
- Responsive chart sizing
- Multiple chart types
- Interactive charts
- Theme styling
- Auto updating data
function toggleTheme() {
const isDark = body.getAttribute('data-theme') === 'dark';
const newTheme = isDark ? 'light' : 'dark';
// Update DOM
body.setAttribute('data-theme', newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
// Save preference
chrome.storage.sync.set({ theme: newTheme });
// Update charts
if (document.getElementById('showAllGraphs').checked) {
updateGraphs();
}
}
Functionality:
- Light/dark mode toggle
- Theme preference
- Real-time UI updates
- Chart theme sync
Try out our new in house developed tools to help show your performance along with our new code VEX VISION. Able to score your games autonomosly using AI and Machine Learning
Ultralytics Yolo V8 nano Open CV Daisy UI Tailwind CSS