From aeeb78bf982df85295a7c8ef845668605efdaee5 Mon Sep 17 00:00:00 2001 From: Dlr Rpi Date: Thu, 6 Nov 2025 16:20:44 +0100 Subject: [PATCH] Changed structure --- board.py | 12 +++++++++ motor.py | 30 ++++++++------------- simulation.py | 72 +++------------------------------------------------ solar.py | 8 +++--- test.py | 54 -------------------------------------- 5 files changed, 31 insertions(+), 145 deletions(-) create mode 100644 board.py delete mode 100644 test.py diff --git a/board.py b/board.py new file mode 100644 index 0000000..d6a4e84 --- /dev/null +++ b/board.py @@ -0,0 +1,12 @@ +from adafruit_servokit import ServoKit + +class Board: + def __init__(self, channels=16, frequency=50): + self.channels = channels + self.frequency = frequency + self.kit = ServoKit(channels=channels, frequency=frequency) + + for i in range(CHANNELS): + kit.servo[i].set_pulse_width_range(MIN, MAX) + kit.servo[i].actuation_range = RANGE + kit.servo[i].angle = INIT diff --git a/motor.py b/motor.py index b9dd71b..c559376 100644 --- a/motor.py +++ b/motor.py @@ -1,11 +1,5 @@ """Helpers for building moving mirrors.""" -from adafruit_servokit import ServoKit - -class Board: - def __init__(self, channels=16, frequency=50): - self.kit = ServoKit(channels=channels, frequency=frequency) - class Motor: """Model a type of servo motor.""" @@ -13,42 +7,40 @@ class Motor: MAX_PULSE = 2500 MIN_PULSE = 500 COVERAGE = 180 # Total degree of freedom in degrees - AREA = MAX_PULSE - MIN_PULSE - OFFSET = 2 # In degrees a constant to be added + OFFSET = 0 # In degrees a constant to be added SCALE = 1 # Scaling # Used for ids count = 0 - def __init__(self, pi, pin, angle=0): + def __init__(self, board, angle=0): + self.board = board self.id = Motor.count; Motor.count += 1 - self.pi = pi # Local pi instance - self.pin = pin self.angle = angle self.offset = Motor.OFFSET # Fine grained controls over every motor + self.coverage = Motor.COVERAGE self.scale = Motor.SCALE # Initialization self.set() - def angle_to_pulse(self, angle): - return min(max(Motor.MIN_PULSE, (Motor.MIN_PULSE + Motor.AREA * angle/Motor.COVERAGE + self.offset) * self.scale), Motor.MAX_PULSE) - # Update the motor position on hardware def set(self): - self.pi.set_servo_pulsewidth(self.pin, self.angle_to_pulse(self.angle)) + self.board.kit.servo[self.id].angle = self.angle * self.scale + self.offset + + def safe_set_angle(angle=0, sleep=0.01, offset=1): + kit.servo[NUM].angle = angle + offset + time.sleep(sleep) + kit.servo[NUM].angle = angle def set_angle(self, angle): - self.angle = angle + self.angle = min(self.coverage, max(0, angle)) # Double check bad self.set() def __str__(self): return f"Motor {self.id} is set at {self.angle} degrees." - def __del__(self): - self.pi.set_servo_pulsewidth(self.pin, 0) - def inc(self, inc): self.angle += inc self.angle = min(max(self.angle, 0), Motor.COVERAGE) # Clip diff --git a/simulation.py b/simulation.py index d0e213f..5eafe1c 100644 --- a/simulation.py +++ b/simulation.py @@ -1,29 +1,17 @@ -import pigpio -import RPi.GPIO as GPIO import time # Solar module for simulation of world import solar # Modeling of the world + from motor import Motor # Small helper functions and constants +from motor import Board -# Constants -SERVO1_PIN = 18 -SERVO2_PIN = 19 - -INIT_PULSE = 0 STEP = 10 LOOP_DELAY = 0.01 # In seconds -pi = pigpio.pi() -if not pi.connected: - print("Cannot connect to pigpio daemon!") - exit() - -angle1 = init_motor(SERVO1_PIN) -angle2 = init_motor(SERVO2_PIN) - # Testing embedding the mirrors in the world -world = solar.World(tilt_deg=15) # The world is tilted 15 degrees around y-axis +board = Board() +world = solar.World(board, tilt_deg=15) # The world is tilted 15 degrees around y-axis HEIGHT = 30 @@ -42,30 +30,6 @@ for i, mirror in enumerate(world.mirrors): pitch, yaw = mirror.get_angles() print(f"Mirror {i} ({mirror.cluster_x}, {mirror.cluster_y}) angles -> pitch: {pitch:.2f}°, yaw: {yaw:.2f}°") -def sm1(a): # Set motor 1 - pi.set_servo_pulsewidth(SERVO1_PIN, angle_to_pulse(a)) - time.sleep(2) - - -angle = 150 -time.sleep(10) - -sm1(150) -sm1(90) -sm1(0) -sm1(180) -sm1(30) -sm1(120) -sm1(60) -sm1(30) -sm1(180) -sm1(120) -sm1(30) -sm1(150) -sm1(3) - - - # Main try: while True: @@ -73,35 +37,7 @@ try: if GPIO.input(SHUTDOWN_BTN) == GPIO.HIGH: os.system("sudo shutdown now") - pulse1 = angle_to_pulse(angle) - time.sleep(3) - angle += 10 - - # Motor 1 - target1 = pulse1 - if GPIO.input(BUTTON1_FWD): - target1 = min(MAX_PULSE, pulse1 + STEP) - elif GPIO.input(BUTTON1_BWD): - target1 = max(MIN_PULSE, pulse1 - STEP) - pulse1 = move_servo(pulse1, target1) - pi.set_servo_pulsewidth(SERVO1_PIN, pulse1) - - # Motor 2 - target2 = pulse2 - if GPIO.input(BUTTON2_FWD): - target2 = min(MAX_PULSE, pulse2 + STEP) - elif GPIO.input(BUTTON2_BWD): - target2 = max(MIN_PULSE, pulse2 - STEP) - pulse2 = move_servo(pulse2, target2) - pi.set_servo_pulsewidth(SERVO2_PIN, pulse2) - time.sleep(LOOP_DELAY) except KeyboardInterrupt: pass - -finally: - pi.set_servo_pulsewidth(SERVO1_PIN, 0) - pi.set_servo_pulsewidth(SERVO2_PIN, 0) - pi.stop() - GPIO.cleanup() diff --git a/solar.py b/solar.py index 62f4864..5b97cb0 100644 --- a/solar.py +++ b/solar.py @@ -31,8 +31,8 @@ class Mirror: self.cluster_y = cluster_y # Store the motors - self.yaw = motor.Motor(self.world.pi, yaw_pin) - self.pitch = motor.Motor(self.world.pi, pitch_pin) + self.yaw = motor.Motor(self.world.board) + self.pitch = motor.Motor(self.world.board) # Position in un-tilted coordinate system self.pos = (cluster_x * self.world.grid_size, cluster_y * self.world.grid_size, 0.0) @@ -81,8 +81,8 @@ class Mirror: return self.yaw.angle, self.pitch.angle class World: - def __init__(self, pi, tilt_deg=0.0): - self.pi = pi + def __init__(self, board, tilt_deg=0.0): + self.board = board self.grid_size = 10 # In cm self.tilt_deg = tilt_deg # Tilt of the grid system around y-axis diff --git a/test.py b/test.py deleted file mode 100644 index ba5c9f7..0000000 --- a/test.py +++ /dev/null @@ -1,54 +0,0 @@ -import time -from adafruit_servokit import ServoKit - -# This is set to zero for the max range -OFFSET = -10 - -MIN = 500 + OFFSET -MAX = 2500 - OFFSET -CHANNELS = 16 -RANGE = 180 -INIT = 0 -FREQUENCY = 50 - -# Setup the kit -kit = ServoKit(channels=CHANNELS, frequency=FREQUENCY) - -for i in range(CHANNELS): - kit.servo[i].set_pulse_width_range(MIN, MAX) - kit.servo[i].actuation_range = RANGE - kit.servo[i].angle = INIT - -time.sleep(2) - -# Testing the accuracy of the lib -NUM = 8 -OFFSET = 5 - -# Set the angle -def sa(angle=0, sleep=1.5): - print(f"Set angle of pin {NUM+1} to {angle}.") - kit.servo[NUM].angle = angle + OFFSET - time.sleep(0.01) - kit.servo[NUM].angle = angle - kit.servo[NUM].angle = angle - OFFSET - time.sleep(0.01) - kit.servo[NUM].angle = angle - time.sleep(sleep) - -sa(80) -exit() - -#for i in range(180): - #sa(i, 0) - #time.sleep(0.1) - - -# Run the actual testing -sa(10) -sa(90) -sa(30) -sa(170) -sa(60) -sa(150) -sa(90, 0)