With the camera mounted to move with the aim mechanism, targeting is now much simpler and more accurate:
Edit these values in octv2_server_v2.py
to match your hardware:
# In MouthDetector.__init__():
self.target_deadzone_pixels = 30 # Larger = more tolerant centering
self.max_adjustment_degrees = 10 # Smaller = more precise movements
# In calculate_centering_adjustment():
pixels_per_degree_rotation = 15 # Adjust for your setup
pixels_per_degree_pitch = 12 # Adjust for your setup
# Camera parameters (measure your actual camera)
self.camera_focal_length_mm = 3.04 # Pi Camera focal length
self.sensor_width_mm = 3.68 # Pi Camera sensor width
self.average_face_width_cm = 16.0 # Average human face width
# Mechanical compensation
self.rotation_offset_degrees = 0.0 # If camera/launcher not aligned
self.pitch_offset_degrees = 0.0 # For gravity/drop compensation
self.distance_pitch_factor = 0.5 # Higher pitch for closer targets
# Run the server
python3 octv2_server_v2.py
# Test manual aiming first:
# 1. Use iOS app manual controls
# 2. Check that ESP32 responds to commands
# 3. Verify camera moves with motors
Open mouth wide and observe behavior:
Expected sequence:
1. Detects WIDE_OPEN mouth
2. Calculates centering adjustment
3. Moves motors to center the mouth
4. Fires when mouth is in target zone
If the system over/under-corrects, adjust these values:
# Too much movement (overshoots):
pixels_per_degree_rotation = 20 # Increase value
pixels_per_degree_pitch = 16 # Increase value
# Too little movement (doesn't reach target):
pixels_per_degree_rotation = 10 # Decrease value
pixels_per_degree_pitch = 8 # Decrease value
Test distance estimation accuracy:
Adjust parameters if needed:
# If distance reads too high:
self.average_face_width_cm = 15.0 # Decrease face width
# If distance reads too low:
self.average_face_width_cm = 17.0 # Increase face width
For accurate trajectory at different distances:
# If shooting too low at close range:
self.distance_pitch_factor = 0.7 # Increase compensation
# If shooting too high at close range:
self.distance_pitch_factor = 0.3 # Decrease compensation
distance = (face_width_real * focal_length * image_width) / (face_width_pixels * sensor_width)
# 1. Calculate offset from center
dx = mouth_x - center_x
dy = mouth_y - center_y
# 2. Convert to angle adjustments
rotation_adj = dx / pixels_per_degree_rotation
pitch_adj = -dy / pixels_per_degree_pitch
# 3. Apply distance scaling (closer = smaller adjustments)
distance_factor = 100.0 / estimated_distance
adjusted_pixels_per_degree *= distance_factor
# 4. Add compensation offsets
rotation_adj += rotation_offset_degrees
pitch_adj += pitch_offset_degrees + distance_compensation
🎯 AUTO TARGET: Mouth detected (confidence 0.85, distance ~120cm)
🎯 CENTERING: Adjusting R:+2.3° E:-1.5° -> R:15.3° E:28.5°
🔥 AUTO FIRE: Launching Oreo at centered target! (offset: 12px)
pixels_per_degree_rotation/pitch
valuesmax_adjustment_degrees
for smaller stepspixels_per_degree_rotation/pitch
valuesaverage_face_width_cm
accordinglyUse offset parameters to compensate:
self.rotation_offset_degrees = -2.0 # Aim 2° left
self.pitch_offset_degrees = 1.5 # Aim 1.5° higher
The system automatically adjusts pitch based on distance:
If target not centered on first try:
Your OCTv2 now has precision camera-follows-aim targeting with distance compensation! 🎯📷