Last active
January 11, 2025 02:23
-
-
Save yuanoook/deeddea3b17088c3adbed879470a98c7 to your computer and use it in GitHub Desktop.
Joystick controls 2 SG90 9g Micro Servos with ESP32-S3
This file contains 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
import machine | |
import time | |
from engine import Engine | |
from joystick import Joystick | |
# Define pins | |
led_pin = 1 | |
eyelid_angle_limit = 70 | |
# Create objects | |
leftEyeLidUp = Engine(9, eyelid_angle_limit) | |
leftEyeLidDown = Engine(13, eyelid_angle_limit) | |
rightEyeLidUp = Engine(8, eyelid_angle_limit) | |
rightEyeLidDown = Engine(5, eyelid_angle_limit) | |
eyeBallUpdown = Engine(7, 70) | |
eyeBallLeftRight = Engine(6, 70) | |
led = machine.Pin(led_pin, machine.Pin.OUT) | |
# Initialize joystick with custom pins (X=12, Y=11, Switch=10) | |
joystick = Joystick(x_pin=12, y_pin=11, switch_pin=10) | |
last_x_value = 2047 | |
left_eye_lid_up_offset = - 400 | |
left_eye_lid_down_offset = 400 | |
def reset_eyelids(): | |
leftEyeLidUp.move_servo(last_x_value + left_eye_lid_up_offset) | |
rightEyeLidUp.move_servo(4095 - last_x_value) | |
down_speed = 1 | |
if last_x_value < 2047: | |
down_speed = 0.5 | |
leftEyeLidDown.move_servo((last_x_value - 2047) * down_speed + 2047 + left_eye_lid_down_offset) | |
rightEyeLidDown.move_servo((4095 - last_x_value) * down_speed) | |
def close_eyelids(): | |
print("Closing eyelids.") | |
leftEyeLidUp.move_servo(4095 + left_eye_lid_up_offset) | |
leftEyeLidDown.move_servo(0 + left_eye_lid_down_offset) | |
rightEyeLidUp.move_servo(0) | |
rightEyeLidDown.move_servo(4095) | |
def joystick_callback(x_value, y_value, switch_value): | |
global last_x_value | |
# Update the previous switch value | |
last_x_value = x_value | |
print(f"Joystick: {x_value} {y_value} {switch_value}") | |
if switch_value == 0: | |
close_eyelids() | |
else: | |
reset_eyelids() | |
# Move eye balls based on joystick | |
eyeBallUpdown.move_servo(4095 - x_value) | |
eyeBallLeftRight.move_servo(4095 - y_value) | |
def loop(func, *args, **kwargs): | |
try: | |
while True: | |
func(*args, **kwargs) | |
time.sleep(0.05) | |
except KeyboardInterrupt: | |
servo.deinit() if 'servo' in globals() else None | |
loop(joystick.read, joystick_callback) | |
This file contains 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
import machine | |
import time | |
class Engine: | |
def __init__(self, pin, angle_range=90): | |
""" | |
Initialize the Engine with the specified pin and angle range. | |
Default angle range is 90 degrees (45 degrees on each side). | |
""" | |
self.servo = machine.PWM(machine.Pin(pin)) | |
self.servo.freq(50) | |
self.angle_range = angle_range | |
self.center_angle = 90 # Assuming the center position is 90 degrees (neutral position) | |
def interval_mapping(self, x, in_min, in_max, out_min, out_max): | |
""" | |
Maps a value from one range to another. | |
""" | |
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min | |
def servo_write(self, angle): | |
""" | |
Moves the servo to a specific angle. | |
""" | |
pulse_width = self.interval_mapping(angle, 0, 180, 0.5, 2.5) # Map angle to pulse width in ms | |
duty = int(self.interval_mapping(pulse_width, 0, 20, 0, 65535)) # Map pulse width to duty cycle | |
self.servo.duty_u16(duty) # Set PWM duty cycle | |
def move_servo(self, x_value): | |
""" | |
Move the servo based on joystick X value. | |
x_value is assumed to be between 0 and 4095. | |
""" | |
# Calculate the total possible range of motion based on the configured angle range | |
half_range = self.angle_range / 2 | |
angle = self.center_angle + int(((x_value / 4095) * self.angle_range) - half_range) | |
self.servo_write(angle) | |
This file contains 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
from machine import Pin, ADC | |
class Joystick: | |
def __init__(self, x_pin=12, y_pin=11, switch_pin=10): | |
self.x_pin = ADC(Pin(x_pin)) # X-axis (analog input) | |
self.y_pin = ADC(Pin(y_pin)) # Y-axis (analog input) | |
self.switch_pin = Pin(switch_pin, Pin.IN, Pin.PULL_UP) # Switch (digital input) | |
self.x_pin.atten(ADC.ATTN_11DB) | |
self.y_pin.atten(ADC.ATTN_11DB) | |
def read(self, callback): | |
x_value = self.x_pin.read() | |
y_value = self.y_pin.read() | |
# Read the switch value (high or low) | |
switch_value = self.switch_pin.value() | |
# Pass the values to the callback function | |
callback(x_value, y_value, switch_value) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment