Formatting

This commit is contained in:
2026-01-15 18:36:56 +01:00
parent ac73cfcf5e
commit e6ce15aee9
7 changed files with 43 additions and 40 deletions

2
.gitignore vendored
View File

@@ -1 +1 @@
__pycache__/
__pycache__

View File

@@ -5,6 +5,7 @@ unit_x = np.array([1, 0, 0])
unit_y = np.array([0, 1, 0])
unit_z = np.array([0, 0, 1])
def get_axis(axis):
"Axis are numbered from 1 to 3 from x to z."
match axis:
@@ -18,14 +19,16 @@ def get_axis(axis):
ax = unit_x
return ax
def proj(vec, axis: int =1):
def proj(vec, axis: int = 1):
"""Simple vector projection onto an axis."""
ax = get_axis(axis)
return np.dot(vec, ax) * ax
def rotate(v, angle=90, axis=1):
"Rotate a vector with an angle around a axis with the right hand rule."
angle = angle/180 * np.pi
angle = angle / 180 * np.pi
k = get_axis(axis)
return (
@@ -34,14 +37,20 @@ def rotate(v, angle=90, axis=1):
+ k * np.dot(k, v) * (1 - np.cos(angle))
)
def agl(a, b):
"Get the angle between two vectors. This is always between 0 and 180 degree."
return np.round(np.acos(np.dot(a, b)/(np.linalg.norm(a) * np.linalg.norm(b)))/(2 * np.pi) * 360)
return np.round(
np.acos(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
/ (2 * np.pi)
* 360
)
def get_angles(source, target):
"""Main function to get the phi and theta angles for a source and a target vector. Both vectors must lie on the front half sphere.
Phi is from 0 to 180 where 0 means left when you look at the mirrors. The hardware is bounded between 45 and 135 degree. Thus the here provided angle needs to be subtracted by 45 and then doubled.
Theta is from 0 to 90 where 0 means up."""
Phi is from 0 to 180 where 0 means left when you look at the mirrors. The hardware is bounded between 45 and 135 degree. Thus the here provided angle needs to be subtracted by 45 and then doubled.
Theta is from 0 to 90 where 0 means up."""
source_planar = source - proj(source, 3)
target_planar = target - proj(target, 3)
@@ -59,15 +68,15 @@ def get_angles(source, target):
if source_phi < target_phi:
rota = rotate(source_planar, phi_diff, 3)
theta_diff = agl(rota, target)
phi = source_phi + phi_diff/2
phi = source_phi + phi_diff / 2
else:
rota = rotate(target_planar, phi_diff, 3)
theta_diff = agl(rota, source)
phi = target_phi + phi_diff/2
phi = target_phi + phi_diff / 2
if source_theta < target_theta:
theta = target_theta + theta_diff/2
theta = target_theta + theta_diff / 2
else:
theta = source_theta + theta_diff/2
theta = source_theta + theta_diff / 2
return (phi, theta)

9
helpers.py Normal file
View File

@@ -0,0 +1,9 @@
from objects.world import World
def print_status(world: World):
for i, mirror in enumerate(world.mirrors):
phi, theta = mirror.get_angles()
print(
f"Mirror {i} ({mirror.cluster_x}, {mirror.cluster_y}) angles -> phi: {phi:.2f}°, theta: {theta:.2f}°"
)

View File

@@ -1,3 +1,8 @@
"""
When theta motor is at 0 then mirror is up and when at 180 then mirror is front.
Phi 0 equals right and phi 180 equals left by 45 degrees.
"""
import numpy as np
from objects.generic import Source, Target
@@ -5,9 +10,10 @@ from objects.motor import Motor
from calculator import get_angles
class Mirror:
def __init__(self, world, cluster_x=0, cluster_y=0):
self.world = world
self.world = world # TODO: Fix this cyclic reference
self.cluster_x = cluster_x
self.cluster_y = cluster_y
@@ -32,7 +38,7 @@ class Mirror:
rel_source = source.pos - rot_pos
rel_target = target.pos - rot_pos
phi, theta = get_angles(rel_source, rel_target) # ty:ignore[unresolved-reference]
phi, theta = get_angles(rel_source, rel_target)
# Update the angles based on the normals in rotated positions
self.motor_phi.set_angle(phi)

View File

@@ -53,3 +53,4 @@ class World:
y_rot = y
z_rot = -x * sin_t + z * cos_t
return np.array([x_rot, y_rot, z_rot])

View File

@@ -1,3 +1,4 @@
from helpers import print_status
import time
from objects.generic import Source, Target
@@ -6,42 +7,21 @@ from objects.mirror import Mirror
from objects.board import Board
# Solar module for simulation of world
STEP = 10
LOOP_DELAY = 0.005 # In seconds
# Testing embedding the mirrors in the world
board = Board()
world = World(board, tilt_deg=0)
HEIGHT = 30
source = Source(world, pos=(0, 50, 0))
target = Target(world, pos=(0, 50, 0))
# Create mirrors in a 3x2 grid
# Create mirrors in a grid
for x in range(2):
for y in range(1):
mirror = Mirror(world, cluster_x=x, cluster_y=y)
world.add_mirror(mirror)
world.update_mirrors_from_source_target(source, target)
def print_status():
for i, mirror in enumerate(world.mirrors):
phi, theta = mirror.get_angles()
print(f"Mirror {i} ({mirror.cluster_x}, {mirror.cluster_y}) angles -> phi: {phi:.2f}°, theta: {theta:.2f}°")
a = 1
t = time.time()
world.mirrors[0].motor_theta.set_angle(180)
world.mirrors[0].motor_phi.set_angle(180)
world.mirrors[1].motor_phi.set_angle(0)
world.mirrors[1].motor_theta.set_angle(0)
print_status()
# Main
try:
while True:
@@ -51,11 +31,9 @@ try:
#print(target.pos)
world.update_mirrors_from_source_target(source, target)
print_status()
print_status(world)
time.sleep(LOOP_DELAY)
t = time.time()
except KeyboardInterrupt:
pass

2
uv.lock generated
View File

@@ -516,7 +516,7 @@ wheels = [
[[package]]
name = "solarmotor"
version = "0.1.0"
version = "0.1.1"
source = { virtual = "." }
dependencies = [
{ name = "adafruit-blinka" },