Compare commits
1 Commits
ac73cfcf5e
...
real
| Author | SHA1 | Date | |
|---|---|---|---|
| e6ce15aee9 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1 @@
|
|||||||
__pycache__/
|
__pycache__
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ unit_x = np.array([1, 0, 0])
|
|||||||
unit_y = np.array([0, 1, 0])
|
unit_y = np.array([0, 1, 0])
|
||||||
unit_z = np.array([0, 0, 1])
|
unit_z = np.array([0, 0, 1])
|
||||||
|
|
||||||
|
|
||||||
def get_axis(axis):
|
def get_axis(axis):
|
||||||
"Axis are numbered from 1 to 3 from x to z."
|
"Axis are numbered from 1 to 3 from x to z."
|
||||||
match axis:
|
match axis:
|
||||||
@@ -18,14 +19,16 @@ def get_axis(axis):
|
|||||||
ax = unit_x
|
ax = unit_x
|
||||||
return ax
|
return ax
|
||||||
|
|
||||||
def proj(vec, axis: int =1):
|
|
||||||
|
def proj(vec, axis: int = 1):
|
||||||
"""Simple vector projection onto an axis."""
|
"""Simple vector projection onto an axis."""
|
||||||
ax = get_axis(axis)
|
ax = get_axis(axis)
|
||||||
return np.dot(vec, ax) * ax
|
return np.dot(vec, ax) * ax
|
||||||
|
|
||||||
|
|
||||||
def rotate(v, angle=90, axis=1):
|
def rotate(v, angle=90, axis=1):
|
||||||
"Rotate a vector with an angle around a axis with the right hand rule."
|
"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)
|
k = get_axis(axis)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -34,14 +37,20 @@ def rotate(v, angle=90, axis=1):
|
|||||||
+ k * np.dot(k, v) * (1 - np.cos(angle))
|
+ k * np.dot(k, v) * (1 - np.cos(angle))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def agl(a, b):
|
def agl(a, b):
|
||||||
"Get the angle between two vectors. This is always between 0 and 180 degree."
|
"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):
|
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.
|
"""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.
|
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."""
|
Theta is from 0 to 90 where 0 means up."""
|
||||||
source_planar = source - proj(source, 3)
|
source_planar = source - proj(source, 3)
|
||||||
target_planar = target - proj(target, 3)
|
target_planar = target - proj(target, 3)
|
||||||
|
|
||||||
@@ -59,15 +68,15 @@ def get_angles(source, target):
|
|||||||
if source_phi < target_phi:
|
if source_phi < target_phi:
|
||||||
rota = rotate(source_planar, phi_diff, 3)
|
rota = rotate(source_planar, phi_diff, 3)
|
||||||
theta_diff = agl(rota, target)
|
theta_diff = agl(rota, target)
|
||||||
phi = source_phi + phi_diff/2
|
phi = source_phi + phi_diff / 2
|
||||||
else:
|
else:
|
||||||
rota = rotate(target_planar, phi_diff, 3)
|
rota = rotate(target_planar, phi_diff, 3)
|
||||||
theta_diff = agl(rota, source)
|
theta_diff = agl(rota, source)
|
||||||
phi = target_phi + phi_diff/2
|
phi = target_phi + phi_diff / 2
|
||||||
|
|
||||||
if source_theta < target_theta:
|
if source_theta < target_theta:
|
||||||
theta = target_theta + theta_diff/2
|
theta = target_theta + theta_diff / 2
|
||||||
else:
|
else:
|
||||||
theta = source_theta + theta_diff/2
|
theta = source_theta + theta_diff / 2
|
||||||
|
|
||||||
return (phi, theta)
|
return (phi, theta)
|
||||||
|
|||||||
9
helpers.py
Normal file
9
helpers.py
Normal 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}°"
|
||||||
|
)
|
||||||
@@ -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
|
import numpy as np
|
||||||
|
|
||||||
from objects.generic import Source, Target
|
from objects.generic import Source, Target
|
||||||
@@ -5,9 +10,10 @@ from objects.motor import Motor
|
|||||||
|
|
||||||
from calculator import get_angles
|
from calculator import get_angles
|
||||||
|
|
||||||
|
|
||||||
class Mirror:
|
class Mirror:
|
||||||
def __init__(self, world, cluster_x=0, cluster_y=0):
|
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_x = cluster_x
|
||||||
self.cluster_y = cluster_y
|
self.cluster_y = cluster_y
|
||||||
|
|
||||||
@@ -32,7 +38,7 @@ class Mirror:
|
|||||||
rel_source = source.pos - rot_pos
|
rel_source = source.pos - rot_pos
|
||||||
rel_target = target.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
|
# Update the angles based on the normals in rotated positions
|
||||||
self.motor_phi.set_angle(phi)
|
self.motor_phi.set_angle(phi)
|
||||||
|
|||||||
@@ -53,3 +53,4 @@ class World:
|
|||||||
y_rot = y
|
y_rot = y
|
||||||
z_rot = -x * sin_t + z * cos_t
|
z_rot = -x * sin_t + z * cos_t
|
||||||
return np.array([x_rot, y_rot, z_rot])
|
return np.array([x_rot, y_rot, z_rot])
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from helpers import print_status
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from objects.generic import Source, Target
|
from objects.generic import Source, Target
|
||||||
@@ -6,42 +7,21 @@ from objects.mirror import Mirror
|
|||||||
from objects.board import Board
|
from objects.board import Board
|
||||||
|
|
||||||
# Solar module for simulation of world
|
# Solar module for simulation of world
|
||||||
STEP = 10
|
|
||||||
LOOP_DELAY = 0.005 # In seconds
|
LOOP_DELAY = 0.005 # In seconds
|
||||||
|
|
||||||
# Testing embedding the mirrors in the world
|
# Testing embedding the mirrors in the world
|
||||||
board = Board()
|
board = Board()
|
||||||
world = World(board, tilt_deg=0)
|
world = World(board, tilt_deg=0)
|
||||||
|
|
||||||
HEIGHT = 30
|
|
||||||
|
|
||||||
source = Source(world, pos=(0, 50, 0))
|
source = Source(world, pos=(0, 50, 0))
|
||||||
target = Target(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 x in range(2):
|
||||||
for y in range(1):
|
for y in range(1):
|
||||||
mirror = Mirror(world, cluster_x=x, cluster_y=y)
|
mirror = Mirror(world, cluster_x=x, cluster_y=y)
|
||||||
world.add_mirror(mirror)
|
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
|
# Main
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
@@ -51,11 +31,9 @@ try:
|
|||||||
#print(target.pos)
|
#print(target.pos)
|
||||||
|
|
||||||
world.update_mirrors_from_source_target(source, target)
|
world.update_mirrors_from_source_target(source, target)
|
||||||
print_status()
|
print_status(world)
|
||||||
|
|
||||||
time.sleep(LOOP_DELAY)
|
time.sleep(LOOP_DELAY)
|
||||||
|
|
||||||
t = time.time()
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
|
|||||||
2
uv.lock
generated
2
uv.lock
generated
@@ -516,7 +516,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solarmotor"
|
name = "solarmotor"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "adafruit-blinka" },
|
{ name = "adafruit-blinka" },
|
||||||
|
|||||||
Reference in New Issue
Block a user