Compare commits
6 Commits
460b874651
...
real
| Author | SHA1 | Date | |
|---|---|---|---|
| e6ce15aee9 | |||
| ac73cfcf5e | |||
| 2d067013b4 | |||
| cc3371b73b | |||
|
|
dc349ff68d | ||
| caa6ae4432 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1 @@
|
|||||||
__pycache__/
|
__pycache__
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3.12
|
3.13
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -1,5 +0,0 @@
|
|||||||
sim:
|
|
||||||
python simulation.py
|
|
||||||
|
|
||||||
sync:
|
|
||||||
rsync -r --exclude=venv ~/solarmotor guest@hahn1.one:
|
|
||||||
@@ -8,12 +8,6 @@ Use adafruit servokit to manage the servos through the external board.
|
|||||||
Enable the I2C module for the rasberry pi.
|
Enable the I2C module for the rasberry pi.
|
||||||
Install the package and initialize with
|
Install the package and initialize with
|
||||||
|
|
||||||
```python
|
|
||||||
from adafruit_servokit import ServoKit
|
|
||||||
kit = ServoKit(channels=16)
|
|
||||||
kit.servo[0].angle = 180
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
https://pinout.xyz/ Full pinout for the rpi3
|
https://pinout.xyz/ Full pinout for the rpi3
|
||||||
https://components101.com/sites/default/files/component_datasheet/SG90%20Servo%20Motor%20Datasheet.pdf Datasheet for the servomotor used
|
https://components101.com/sites/default/files/component_datasheet/SG90%20Servo%20Motor%20Datasheet.pdf Datasheet for the servomotor used
|
||||||
@@ -23,7 +17,7 @@ https://ben.akrin.com/raspberry-pi-servo-jitter/ Blog post how to fix jittering
|
|||||||
Local address
|
Local address
|
||||||
inet6 fe80::7e2c:ada5:5de7:9a2c/64
|
inet6 fe80::7e2c:ada5:5de7:9a2c/64
|
||||||
|
|
||||||
## Cables
|
## Cables on the rpi
|
||||||
|
|
||||||
From right to left
|
From right to left
|
||||||
|
|
||||||
|
|||||||
@@ -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,20 +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 abs_custom(vec):
|
|
||||||
l = 0
|
|
||||||
for i in range(3):
|
|
||||||
l += vec[i] ** 2
|
|
||||||
return np.sqrt(l)
|
|
||||||
|
|
||||||
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 (
|
||||||
@@ -40,13 +37,15 @@ 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)/(abs_custom(a) * abs_custom(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 normalize(vec):
|
|
||||||
l = abs_custom(vec)
|
|
||||||
return vec/l
|
|
||||||
|
|
||||||
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.
|
||||||
@@ -69,39 +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)
|
||||||
|
|
||||||
GRID_SIZE = 10
|
|
||||||
|
|
||||||
# Aufbau der Koordinaten
|
|
||||||
# Das Zentrum des Spiegels hinten rechts bildet den Ursprung
|
|
||||||
# Dann geht die x-Achse nach links und die y-Achse nach vorne
|
|
||||||
|
|
||||||
# X, Y, Z
|
|
||||||
source_orig = np.array([0, 20, 0])
|
|
||||||
target_orig = np.array([0, 20, 0])
|
|
||||||
|
|
||||||
# Strategie des Programms
|
|
||||||
# 1. Iteration ueber jeden Spiegel
|
|
||||||
# 2. Berechnung des Quellvektors und des Targetvektors fuer die Position des Spiegels
|
|
||||||
# 3. Berechne
|
|
||||||
|
|
||||||
for x in range(4):
|
|
||||||
for y in range(2):
|
|
||||||
x_size = x * GRID_SIZE
|
|
||||||
y_size = y * GRID_SIZE
|
|
||||||
|
|
||||||
phi, theta = get_angles(source_orig - unit_x * x_size - unit_y * y_size, target_orig - unit_x * x_size - unit_y * y_size)
|
|
||||||
|
|
||||||
print(f"For grid ({x}, {y}), phi = {phi} and theta = {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}°"
|
||||||
|
)
|
||||||
9
justfile
Normal file
9
justfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
default: sim
|
||||||
|
|
||||||
|
sim:
|
||||||
|
@echo "Starting the simulation!"
|
||||||
|
uv run python simulation.py
|
||||||
|
|
||||||
|
test:
|
||||||
|
@echo "Try to run all the tests."
|
||||||
|
uv run python -m unittest discover -v
|
||||||
6
main.py
6
main.py
@@ -1,6 +0,0 @@
|
|||||||
def main():
|
|
||||||
print("Hello from solarmotor!")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -3,9 +3,13 @@ from adafruit_servokit import ServoKit
|
|||||||
class Board:
|
class Board:
|
||||||
MIN = 500
|
MIN = 500
|
||||||
MAX = 2500
|
MAX = 2500
|
||||||
|
COVER = 180
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
|
||||||
def __init__(self, channels=16, frequency=50):
|
def __init__(self, channels=16, frequency=50):
|
||||||
self.channels = channels
|
self.channels = channels
|
||||||
|
self.address = "" # For the future
|
||||||
self.frequency = frequency
|
self.frequency = frequency
|
||||||
self.kit = ServoKit(channels=channels, frequency=frequency)
|
self.kit = ServoKit(channels=channels, frequency=frequency)
|
||||||
|
|
||||||
|
|||||||
25
objects/generic.py
Normal file
25
objects/generic.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
class MovingEntity:
|
||||||
|
"""Embedded entity in the world with a position."""
|
||||||
|
|
||||||
|
def __init__(self, world):
|
||||||
|
self.world = world
|
||||||
|
self.pos = np.array((0.0, 0.0, 0.0)) # (x, y, z) in local untilted coordinates
|
||||||
|
|
||||||
|
def get_pos_rotated(self):
|
||||||
|
"""Return position rotated by world's tilt around y-axis."""
|
||||||
|
return self.world.rotate_point_y(self.pos)
|
||||||
|
|
||||||
|
def move(self, dx=0, dy=0, dz=0):
|
||||||
|
self.pos = (self.pos[0] + dx, self.pos[1] + dy, self.pos[2] + dz)
|
||||||
|
|
||||||
|
class Target(MovingEntity):
|
||||||
|
def __init__(self, world, pos=(0.0, 0.0, 0.0)):
|
||||||
|
super().__init__(world)
|
||||||
|
self.pos = np.array(pos) # Store everything in numpy
|
||||||
|
|
||||||
|
class Source(MovingEntity):
|
||||||
|
def __init__(self, world, pos=(10.0, 10.0, 10.0)):
|
||||||
|
super().__init__(world)
|
||||||
|
self.pos = np.array(pos)
|
||||||
48
objects/mirror.py
Normal file
48
objects/mirror.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
"""
|
||||||
|
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
|
||||||
|
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 # TODO: Fix this cyclic reference
|
||||||
|
self.cluster_x = cluster_x
|
||||||
|
self.cluster_y = cluster_y
|
||||||
|
|
||||||
|
# Store the motors
|
||||||
|
# Need to get first the theta because
|
||||||
|
# of the ordeing of the cables on the board
|
||||||
|
self.motor_theta: Motor = Motor(self.world.board)
|
||||||
|
self.motor_phi: Motor = Motor(self.world.board)
|
||||||
|
|
||||||
|
# Position in un-tilted coordinate system
|
||||||
|
self.pos = np.array(
|
||||||
|
[cluster_x * self.world.grid_size, cluster_y * self.world.grid_size, 0.0]
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_pos_rotated(self):
|
||||||
|
return self.world.rotate_point_y(self.pos)
|
||||||
|
|
||||||
|
def set_angle_from_source_target(self, source: Source, target: Target):
|
||||||
|
"Set the angles of a mirror from global source and target vectors."
|
||||||
|
|
||||||
|
rot_pos = self.get_pos_rotated()
|
||||||
|
rel_source = source.pos - rot_pos
|
||||||
|
rel_target = target.pos - rot_pos
|
||||||
|
|
||||||
|
phi, theta = get_angles(rel_source, rel_target)
|
||||||
|
|
||||||
|
# Update the angles based on the normals in rotated positions
|
||||||
|
self.motor_phi.set_angle(phi)
|
||||||
|
self.motor_theta.set_angle(theta)
|
||||||
|
|
||||||
|
def get_angles(self):
|
||||||
|
return self.motor_phi.angle, self.motor_theta.angle
|
||||||
@@ -1,29 +1,21 @@
|
|||||||
"""Helpers for building moving mirrors."""
|
"""Helpers for building moving mirrors."""
|
||||||
|
|
||||||
from objects.board import Board
|
from objects.board import Board
|
||||||
import time
|
|
||||||
|
|
||||||
class Motor:
|
class Motor:
|
||||||
"""Model a type of servo motor."""
|
"""Model a type of servo motor."""
|
||||||
|
|
||||||
# Default vaules for every motor
|
|
||||||
MAX_PULSE = 2500
|
|
||||||
MIN_PULSE = 500
|
|
||||||
COVERAGE = 180 # Total degree of freedom in degrees
|
|
||||||
OFFSET = 0 # In degrees a constant to be added
|
OFFSET = 0 # In degrees a constant to be added
|
||||||
SCALE = 1 # Scaling
|
SCALE = 1 # Scaling
|
||||||
|
|
||||||
# Used for ids
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
def __init__(self, board: Board, angle=0):
|
def __init__(self, board: Board, angle=0):
|
||||||
self.board: Board = board
|
self.board: Board = board
|
||||||
self.id: int = Motor.count
|
self.id: int = Board.count
|
||||||
Motor.count += 1
|
Board.count += 1
|
||||||
|
|
||||||
self.angle = angle
|
self.angle = angle
|
||||||
self.offset = Motor.OFFSET # Fine grained controls over every motor
|
self.offset = Motor.OFFSET # Fine grained controls over every motor
|
||||||
self.coverage = Motor.COVERAGE
|
self.coverage = Board.COVER
|
||||||
self.scale = Motor.SCALE
|
self.scale = Motor.SCALE
|
||||||
|
|
||||||
# Initialization
|
# Initialization
|
||||||
@@ -33,11 +25,6 @@ class Motor:
|
|||||||
def set(self):
|
def set(self):
|
||||||
self.board.kit.servo[self.id].angle = self.angle * self.scale + self.offset
|
self.board.kit.servo[self.id].angle = self.angle * self.scale + self.offset
|
||||||
|
|
||||||
def safe_set_angle(angle=0, sleep=0.01, offset=1):
|
|
||||||
self.board.kit.servo[NUM].angle = angle + offset
|
|
||||||
time.sleep(sleep)
|
|
||||||
kit.servo[NUM].angle = angle
|
|
||||||
|
|
||||||
def set_angle(self, angle):
|
def set_angle(self, angle):
|
||||||
self.angle = min(self.coverage, max(0, angle)) # Double check bad
|
self.angle = min(self.coverage, max(0, angle)) # Double check bad
|
||||||
self.set()
|
self.set()
|
||||||
@@ -47,5 +34,5 @@ class Motor:
|
|||||||
|
|
||||||
def inc(self, inc):
|
def inc(self, inc):
|
||||||
self.angle += inc
|
self.angle += inc
|
||||||
self.angle = min(max(self.angle, 0), Motor.COVERAGE) # Clip
|
self.angle = min(max(self.angle, 0), Board.COVER) # Clip
|
||||||
self.set()
|
self.set()
|
||||||
|
|||||||
111
objects/solar.py
111
objects/solar.py
@@ -1,111 +0,0 @@
|
|||||||
"""Alle gemessenen Koordinaten der Quelle und der Sonne haben den Ursprung in der linken unteren Ecke des Clusters in einem rechtshaendigen flachen System.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import math
|
|
||||||
import objects.motor as motor
|
|
||||||
|
|
||||||
class MovingEntity:
|
|
||||||
"""Embedded entity in the world with a position."""
|
|
||||||
|
|
||||||
def __init__(self, world):
|
|
||||||
self.world = world
|
|
||||||
self.pos = (0.0, 0.0, 0.0) # (x, y, z) in local untilted coordinates
|
|
||||||
|
|
||||||
def get_pos_rotated(self):
|
|
||||||
"""Return position rotated by world's tilt around y-axis."""
|
|
||||||
return self.world.rotate_point_y(self.pos)
|
|
||||||
|
|
||||||
def move(self, dx=0, dy=0, dz=0):
|
|
||||||
self.pos = (self.pos[0] + dx, self.pos[1] + dy, self.pos[2] + dz)
|
|
||||||
|
|
||||||
class Target(MovingEntity):
|
|
||||||
def __init__(self, world, pos=(0.0, 0.0, 0.0)):
|
|
||||||
super().__init__(world)
|
|
||||||
self.pos = pos
|
|
||||||
|
|
||||||
class Source(MovingEntity):
|
|
||||||
def __init__(self, world, pos=(10.0, 10.0, 10.0)):
|
|
||||||
super().__init__(world)
|
|
||||||
self.pos = pos
|
|
||||||
|
|
||||||
class Mirror:
|
|
||||||
def __init__(self, world, cluster_x=0, cluster_y=0):
|
|
||||||
self.world = world
|
|
||||||
self.cluster_x = cluster_x
|
|
||||||
self.cluster_y = cluster_y
|
|
||||||
|
|
||||||
# Store the motors
|
|
||||||
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)
|
|
||||||
|
|
||||||
def get_pos_rotated(self):
|
|
||||||
return self.world.rotate_point_y(self.pos)
|
|
||||||
|
|
||||||
def set_angle_from_source_target(self, source: Source, target: Target):
|
|
||||||
# Get rotated positions
|
|
||||||
pos_mirror = self.get_pos_rotated()
|
|
||||||
pos_source = source.get_pos_rotated()
|
|
||||||
pos_target = target.get_pos_rotated()
|
|
||||||
|
|
||||||
v_source = (
|
|
||||||
pos_source[0] - pos_mirror[0],
|
|
||||||
pos_source[1] - pos_mirror[1],
|
|
||||||
pos_source[2] - pos_mirror[2],
|
|
||||||
)
|
|
||||||
v_target = (
|
|
||||||
pos_target[0] - pos_mirror[0],
|
|
||||||
pos_target[1] - pos_mirror[1],
|
|
||||||
pos_target[2] - pos_mirror[2],
|
|
||||||
)
|
|
||||||
|
|
||||||
def normalize(v):
|
|
||||||
length = math.sqrt(v[0] ** 2 + v[1] ** 2 + v[2] ** 2)
|
|
||||||
if length == 0:
|
|
||||||
return (0, 0, 0)
|
|
||||||
return (v[0] / length, v[1] / length, v[2] / length)
|
|
||||||
|
|
||||||
v_source_n = normalize(v_source)
|
|
||||||
v_target_n = normalize(v_target)
|
|
||||||
|
|
||||||
mirror_normal = (
|
|
||||||
v_source_n[0] + v_target_n[0],
|
|
||||||
v_source_n[1] + v_target_n[1],
|
|
||||||
v_source_n[2] + v_target_n[2],
|
|
||||||
)
|
|
||||||
mirror_normal = normalize(mirror_normal)
|
|
||||||
|
|
||||||
# Update the angles based on the normals in rotated positions
|
|
||||||
self.yaw.set_angle(math.degrees(math.atan2(mirror_normal[0], mirror_normal[2])))
|
|
||||||
self.pitch.set_angle(math.degrees(math.atan2(mirror_normal[1], mirror_normal[2])))
|
|
||||||
|
|
||||||
def get_angles(self):
|
|
||||||
return self.yaw.angle, self.pitch.angle
|
|
||||||
|
|
||||||
class World:
|
|
||||||
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
|
|
||||||
self.mirrors = []
|
|
||||||
|
|
||||||
def add_mirror(self, mirror):
|
|
||||||
self.mirrors.append(mirror)
|
|
||||||
|
|
||||||
def update_mirrors_from_source_target(self, source: Source, target: Target):
|
|
||||||
for mirror in self.mirrors:
|
|
||||||
mirror.set_angle_from_source_target(source, target)
|
|
||||||
|
|
||||||
def rotate_point_y(self, point):
|
|
||||||
"""Rotate a point around the y-axis by the world's tilt angle."""
|
|
||||||
x, y, z = point
|
|
||||||
theta = math.radians(self.tilt_deg)
|
|
||||||
cos_t = math.cos(theta)
|
|
||||||
sin_t = math.sin(theta)
|
|
||||||
x_rot = x * cos_t + z * sin_t
|
|
||||||
y_rot = y
|
|
||||||
z_rot = -x * sin_t + z * cos_t
|
|
||||||
return (x_rot, y_rot, z_rot)
|
|
||||||
56
objects/world.py
Normal file
56
objects/world.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
"""
|
||||||
|
Alle gemessenen Koordinaten der Quelle und der Sonne haben den Ursprung in der rechten
|
||||||
|
oberen Ecke des Clusters in einem rechtshaendigen flachen System.
|
||||||
|
|
||||||
|
Achsen in der Welt mit der z-Achse nach oben.
|
||||||
|
Alles in cm gemessen.
|
||||||
|
Der phi Winkel wird zur x-Achse gemessen.
|
||||||
|
Der thetha Winkel wird zur z-Achse gemessen.
|
||||||
|
|
||||||
|
So sind y und z Koordinaten immer positiv.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
x (2,0) (1,0) (0,0)
|
||||||
|
<-----S----S----S O:z
|
||||||
|
|
|
||||||
|
S S S (0,1)
|
||||||
|
|
|
||||||
|
v y
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from objects.generic import Source, Target
|
||||||
|
from objects.mirror import Mirror
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
class World:
|
||||||
|
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
|
||||||
|
self.mirrors: list[Mirror] = []
|
||||||
|
|
||||||
|
def add_mirror(self, mirror):
|
||||||
|
self.mirrors.append(mirror)
|
||||||
|
|
||||||
|
def update_mirrors_from_source_target(self, source: Source, target: Target):
|
||||||
|
for mirror in self.mirrors:
|
||||||
|
mirror.set_angle_from_source_target(source, target)
|
||||||
|
|
||||||
|
def rotate_point_y(self, point):
|
||||||
|
"""Rotate a point around the y-axis by the world's tilt angle."""
|
||||||
|
x, y, z = point
|
||||||
|
theta = math.radians(self.tilt_deg)
|
||||||
|
cos_t = np.cos(theta)
|
||||||
|
sin_t = np.sin(theta)
|
||||||
|
x_rot = x * cos_t + z * sin_t
|
||||||
|
y_rot = y
|
||||||
|
z_rot = -x * sin_t + z * cos_t
|
||||||
|
return np.array([x_rot, y_rot, z_rot])
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "solarmotor"
|
name = "solarmotor"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
description = "Add your description here"
|
description = "Binary to simulate mirrors"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -27,6 +27,7 @@ dependencies = [
|
|||||||
"jedi-language-server==0.46.0",
|
"jedi-language-server==0.46.0",
|
||||||
"lsprotocol==2025.0.0",
|
"lsprotocol==2025.0.0",
|
||||||
"mypy-extensions==1.1.0",
|
"mypy-extensions==1.1.0",
|
||||||
|
"numpy>=2.4.1",
|
||||||
"packaging==25.0",
|
"packaging==25.0",
|
||||||
"parso==0.8.5",
|
"parso==0.8.5",
|
||||||
"pathspec==0.12.1",
|
"pathspec==0.12.1",
|
||||||
|
|||||||
13
shell.nix
13
shell.nix
@@ -1,13 +0,0 @@
|
|||||||
{ pkgs ? import <nixpkgs> {} }:
|
|
||||||
|
|
||||||
# Simple python shell for all packages
|
|
||||||
|
|
||||||
pkgs.mkShell {
|
|
||||||
buildInputs = with pkgs; [
|
|
||||||
(pkgs.python313.withPackages (ps: with ps; [
|
|
||||||
matplotlib
|
|
||||||
numpy
|
|
||||||
ty
|
|
||||||
]))
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,56 +1,39 @@
|
|||||||
|
from helpers import print_status
|
||||||
import time
|
import time
|
||||||
import math
|
|
||||||
|
|
||||||
# Solar module for simulation of world
|
from objects.generic import Source, Target
|
||||||
import objects.solar as solar # Modeling of the world
|
from objects.world import World
|
||||||
|
from objects.mirror import Mirror
|
||||||
from objects.motor import Motor # Small helper functions and constants
|
|
||||||
from objects.board import Board
|
from objects.board import Board
|
||||||
|
|
||||||
STEP = 10
|
# Solar module for simulation of world
|
||||||
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 = solar.World(board, tilt_deg=15) # The world is tilted 15 degrees around y-axis
|
world = World(board, tilt_deg=0)
|
||||||
|
|
||||||
HEIGHT = 30
|
source = Source(world, pos=(0, 50, 0))
|
||||||
|
target = Target(world, pos=(0, 50, 0))
|
||||||
|
|
||||||
source = solar.Source(world, pos=(30, 50, 100))
|
# Create mirrors in a grid
|
||||||
target = solar.Target(world, pos=(0, 0, 40))
|
for x in range(2):
|
||||||
|
for y in range(1):
|
||||||
# Create mirrors in a 3x2 grid
|
mirror = Mirror(world, cluster_x=x, cluster_y=y)
|
||||||
for x in range(3):
|
|
||||||
for y in range(2):
|
|
||||||
mirror = solar.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):
|
|
||||||
pitch, yaw = mirror.get_angles()
|
|
||||||
print(f"Mirror {i} ({mirror.cluster_x}, {mirror.cluster_y}) angles -> pitch: {pitch:.2f}°, yaw: {yaw:.2f}°")
|
|
||||||
|
|
||||||
print_status()
|
|
||||||
|
|
||||||
a = 1
|
|
||||||
t = time.time()
|
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
source.move(0, 0, 0.1)
|
#source.move(0, 0, 0.5)
|
||||||
#source.move(10 * math.sin(a * t), 10 * math.cos(a * t))
|
#source.move(10 * math.sin(a * t), 10 * math.cos(a * t))
|
||||||
print(source.pos)
|
#print(source.pos)
|
||||||
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
|
||||||
|
|||||||
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
37
tests/test_calculator.py
Normal file
37
tests/test_calculator.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import unittest
|
||||||
|
import numpy as np
|
||||||
|
import calculator
|
||||||
|
|
||||||
|
|
||||||
|
class TestCalculator(unittest.TestCase):
|
||||||
|
def test_proj(self):
|
||||||
|
vec = np.array([123, 325, 1])
|
||||||
|
self.assertEqual(np.array([123, 0, 0]).all(), calculator.proj(vec, 1).all())
|
||||||
|
|
||||||
|
vec = np.array([234, -2134, 12])
|
||||||
|
self.assertEqual(np.array([-2134, 0, 0]).all(), calculator.proj(vec, 2).all())
|
||||||
|
|
||||||
|
vec = np.array([-21, 34, 82])
|
||||||
|
self.assertEqual(np.array([0, 0, 82]).all(), calculator.proj(vec, 3).all())
|
||||||
|
|
||||||
|
def test_rotate(self):
|
||||||
|
vec = np.array([1, 0, 0])
|
||||||
|
self.assertEqual(np.array([0, 1, 0]).all(), calculator.rotate(vec).all())
|
||||||
|
|
||||||
|
def test_agl(self):
|
||||||
|
vec1 = np.array([1, 0, 0])
|
||||||
|
vec2 = np.array([1, 0, 0])
|
||||||
|
self.assertEqual(0, calculator.agl(vec1, vec2))
|
||||||
|
|
||||||
|
vec1 = np.array([1, 0, 0])
|
||||||
|
vec2 = np.array([0, 1, 0])
|
||||||
|
self.assertEqual(90, calculator.agl(vec1, vec2))
|
||||||
|
|
||||||
|
def test_get_angles(self):
|
||||||
|
source = np.array([0, 50, 0])
|
||||||
|
target = np.array([0, 50, 0])
|
||||||
|
self.assertEqual((90, 90), calculator.get_angles(source, target))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
54
uv.lock
generated
54
uv.lock
generated
@@ -305,6 +305,56 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numpy"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/24/62/ae72ff66c0f1fd959925b4c11f8c2dea61f47f6acaea75a08512cdfe3fed/numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690", size = 20721320, upload-time = "2026-01-10T06:44:59.619Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/68/732d4b7811c00775f3bd522a21e8dd5a23f77eb11acdeb663e4a4ebf0ef4/numpy-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d797454e37570cfd61143b73b8debd623c3c0952959adb817dd310a483d58a1b", size = 16652495, upload-time = "2026-01-10T06:43:06.283Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/ca/857722353421a27f1465652b2c66813eeeccea9d76d5f7b74b99f298e60e/numpy-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c55962006156aeef1629b953fd359064aa47e4d82cfc8e67f0918f7da3344f", size = 12368657, upload-time = "2026-01-10T06:43:09.094Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/0d/2377c917513449cc6240031a79d30eb9a163d32a91e79e0da47c43f2c0c8/numpy-2.4.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:71abbea030f2cfc3092a0ff9f8c8fdefdc5e0bf7d9d9c99663538bb0ecdac0b9", size = 5197256, upload-time = "2026-01-10T06:43:13.634Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/39/569452228de3f5de9064ac75137082c6214be1f5c532016549a7923ab4b5/numpy-2.4.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5b55aa56165b17aaf15520beb9cbd33c9039810e0d9643dd4379e44294c7303e", size = 6545212, upload-time = "2026-01-10T06:43:15.661Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/a4/77333f4d1e4dac4395385482557aeecf4826e6ff517e32ca48e1dafbe42a/numpy-2.4.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0faba4a331195bfa96f93dd9dfaa10b2c7aa8cda3a02b7fd635e588fe821bf5", size = 14402871, upload-time = "2026-01-10T06:43:17.324Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/87/d341e519956273b39d8d47969dd1eaa1af740615394fe67d06f1efa68773/numpy-2.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e3087f53e2b4428766b54932644d148613c5a595150533ae7f00dab2f319a8", size = 16359305, upload-time = "2026-01-10T06:43:19.376Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/91/789132c6666288eaa20ae8066bb99eba1939362e8f1a534949a215246e97/numpy-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:49e792ec351315e16da54b543db06ca8a86985ab682602d90c60ef4ff4db2a9c", size = 16181909, upload-time = "2026-01-10T06:43:21.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/b8/090b8bd27b82a844bb22ff8fdf7935cb1980b48d6e439ae116f53cdc2143/numpy-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79e9e06c4c2379db47f3f6fc7a8652e7498251789bf8ff5bd43bf478ef314ca2", size = 18284380, upload-time = "2026-01-10T06:43:23.957Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/78/722b62bd31842ff029412271556a1a27a98f45359dea78b1548a3a9996aa/numpy-2.4.1-cp313-cp313-win32.whl", hash = "sha256:3d1a100e48cb266090a031397863ff8a30050ceefd798f686ff92c67a486753d", size = 5957089, upload-time = "2026-01-10T06:43:27.535Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/a6/cf32198b0b6e18d4fbfa9a21a992a7fca535b9bb2b0cdd217d4a3445b5ca/numpy-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:92a0e65272fd60bfa0d9278e0484c2f52fe03b97aedc02b357f33fe752c52ffb", size = 12307230, upload-time = "2026-01-10T06:43:29.298Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/6c/534d692bfb7d0afe30611320c5fb713659dcb5104d7cc182aff2aea092f5/numpy-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:20d4649c773f66cc2fc36f663e091f57c3b7655f936a4c681b4250855d1da8f5", size = 10313125, upload-time = "2026-01-10T06:43:31.782Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/a1/354583ac5c4caa566de6ddfbc42744409b515039e085fab6e0ff942e0df5/numpy-2.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f93bc6892fe7b0663e5ffa83b61aab510aacffd58c16e012bb9352d489d90cb7", size = 12496156, upload-time = "2026-01-10T06:43:34.237Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/b0/42807c6e8cce58c00127b1dc24d365305189991f2a7917aa694a109c8d7d/numpy-2.4.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:178de8f87948163d98a4c9ab5bee4ce6519ca918926ec8df195af582de28544d", size = 5324663, upload-time = "2026-01-10T06:43:36.211Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/55/7a621694010d92375ed82f312b2f28017694ed784775269115323e37f5e2/numpy-2.4.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:98b35775e03ab7f868908b524fc0a84d38932d8daf7b7e1c3c3a1b6c7a2c9f15", size = 6645224, upload-time = "2026-01-10T06:43:37.884Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/96/9fa8635ed9d7c847d87e30c834f7109fac5e88549d79ef3324ab5c20919f/numpy-2.4.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941c2a93313d030f219f3a71fd3d91a728b82979a5e8034eb2e60d394a2b83f9", size = 14462352, upload-time = "2026-01-10T06:43:39.479Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/d1/8cf62d8bb2062da4fb82dd5d49e47c923f9c0738032f054e0a75342faba7/numpy-2.4.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:529050522e983e00a6c1c6b67411083630de8b57f65e853d7b03d9281b8694d2", size = 16407279, upload-time = "2026-01-10T06:43:41.93Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/1c/95c86e17c6b0b31ce6ef219da00f71113b220bcb14938c8d9a05cee0ff53/numpy-2.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2302dc0224c1cbc49bb94f7064f3f923a971bfae45c33870dcbff63a2a550505", size = 16248316, upload-time = "2026-01-10T06:43:44.121Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/b4/e7f5ff8697274c9d0fa82398b6a372a27e5cef069b37df6355ccb1f1db1a/numpy-2.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9171a42fcad32dcf3fa86f0a4faa5e9f8facefdb276f54b8b390d90447cff4e2", size = 18329884, upload-time = "2026-01-10T06:43:46.613Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/a4/b073f3e9d77f9aec8debe8ca7f9f6a09e888ad1ba7488f0c3b36a94c03ac/numpy-2.4.1-cp313-cp313t-win32.whl", hash = "sha256:382ad67d99ef49024f11d1ce5dcb5ad8432446e4246a4b014418ba3a1175a1f4", size = 6081138, upload-time = "2026-01-10T06:43:48.854Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/16/af42337b53844e67752a092481ab869c0523bc95c4e5c98e4dac4e9581ac/numpy-2.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:62fea415f83ad8fdb6c20840578e5fbaf5ddd65e0ec6c3c47eda0f69da172510", size = 12447478, upload-time = "2026-01-10T06:43:50.476Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/f8/fa85b2eac68ec631d0b631abc448552cb17d39afd17ec53dcbcc3537681a/numpy-2.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a7870e8c5fc11aef57d6fea4b4085e537a3a60ad2cdd14322ed531fdca68d261", size = 10382981, upload-time = "2026-01-10T06:43:52.575Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/a7/ef08d25698e0e4b4efbad8d55251d20fe2a15f6d9aa7c9b30cd03c165e6f/numpy-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3869ea1ee1a1edc16c29bbe3a2f2a4e515cc3a44d43903ad41e0cacdbaf733dc", size = 16652046, upload-time = "2026-01-10T06:43:54.797Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8f/39/e378b3e3ca13477e5ac70293ec027c438d1927f18637e396fe90b1addd72/numpy-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e867df947d427cdd7a60e3e271729090b0f0df80f5f10ab7dd436f40811699c3", size = 12378858, upload-time = "2026-01-10T06:43:57.099Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/74/7ec6154f0006910ed1fdbb7591cf4432307033102b8a22041599935f8969/numpy-2.4.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e3bd2cb07841166420d2fa7146c96ce00cb3410664cbc1a6be028e456c4ee220", size = 5207417, upload-time = "2026-01-10T06:43:59.037Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/b7/053ac11820d84e42f8feea5cb81cc4fcd1091499b45b1ed8c7415b1bf831/numpy-2.4.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:f0a90aba7d521e6954670550e561a4cb925713bd944445dbe9e729b71f6cabee", size = 6542643, upload-time = "2026-01-10T06:44:01.852Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/c4/2e7908915c0e32ca636b92e4e4a3bdec4cb1e7eb0f8aedf1ed3c68a0d8cd/numpy-2.4.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d558123217a83b2d1ba316b986e9248a1ed1971ad495963d555ccd75dcb1556", size = 14418963, upload-time = "2026-01-10T06:44:04.047Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/c0/3ed5083d94e7ffd7c404e54619c088e11f2e1939a9544f5397f4adb1b8ba/numpy-2.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f44de05659b67d20499cbc96d49f2650769afcb398b79b324bb6e297bfe3844", size = 16363811, upload-time = "2026-01-10T06:44:06.207Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/68/42b66f1852bf525050a67315a4fb94586ab7e9eaa541b1bef530fab0c5dd/numpy-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:69e7419c9012c4aaf695109564e3387f1259f001b4326dfa55907b098af082d3", size = 16197643, upload-time = "2026-01-10T06:44:08.33Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/40/e8714fc933d85f82c6bfc7b998a0649ad9769a32f3494ba86598aaf18a48/numpy-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd257026eb1b34352e749d7cc1678b5eeec3e329ad8c9965a797e08ccba205", size = 18289601, upload-time = "2026-01-10T06:44:10.841Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/9a/0d44b468cad50315127e884802351723daca7cf1c98d102929468c81d439/numpy-2.4.1-cp314-cp314-win32.whl", hash = "sha256:727c6c3275ddefa0dc078524a85e064c057b4f4e71ca5ca29a19163c607be745", size = 6005722, upload-time = "2026-01-10T06:44:13.332Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/bb/c6513edcce5a831810e2dddc0d3452ce84d208af92405a0c2e58fd8e7881/numpy-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:7d5d7999df434a038d75a748275cd6c0094b0ecdb0837342b332a82defc4dc4d", size = 12438590, upload-time = "2026-01-10T06:44:15.006Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/da/a598d5cb260780cf4d255102deba35c1d072dc028c4547832f45dd3323a8/numpy-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:ce9ce141a505053b3c7bce3216071f3bf5c182b8b28930f14cd24d43932cd2df", size = 10596180, upload-time = "2026-01-10T06:44:17.386Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/bc/ea3f2c96fcb382311827231f911723aeff596364eb6e1b6d1d91128aa29b/numpy-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e53170557d37ae404bf8d542ca5b7c629d6efa1117dac6a83e394142ea0a43f", size = 12498774, upload-time = "2026-01-10T06:44:19.467Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/ab/ef9d939fe4a812648c7a712610b2ca6140b0853c5efea361301006c02ae5/numpy-2.4.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:a73044b752f5d34d4232f25f18160a1cc418ea4507f5f11e299d8ac36875f8a0", size = 5327274, upload-time = "2026-01-10T06:44:23.189Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/31/d381368e2a95c3b08b8cf7faac6004849e960f4a042d920337f71cef0cae/numpy-2.4.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:fb1461c99de4d040666ca0444057b06541e5642f800b71c56e6ea92d6a853a0c", size = 6648306, upload-time = "2026-01-10T06:44:25.012Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/e5/0989b44ade47430be6323d05c23207636d67d7362a1796ccbccac6773dd2/numpy-2.4.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423797bdab2eeefbe608d7c1ec7b2b4fd3c58d51460f1ee26c7500a1d9c9ee93", size = 14464653, upload-time = "2026-01-10T06:44:26.706Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/a7/cfbe475c35371cae1358e61f20c5f075badc18c4797ab4354140e1d283cf/numpy-2.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52b5f61bdb323b566b528899cc7db2ba5d1015bda7ea811a8bcf3c89c331fa42", size = 16405144, upload-time = "2026-01-10T06:44:29.378Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/a3/0c63fe66b534888fa5177cc7cef061541064dbe2b4b60dcc60ffaf0d2157/numpy-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42d7dd5fa36d16d52a84f821eb96031836fd405ee6955dd732f2023724d0aa01", size = 16247425, upload-time = "2026-01-10T06:44:31.721Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6b/2b/55d980cfa2c93bd40ff4c290bf824d792bd41d2fe3487b07707559071760/numpy-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7b6b5e28bbd47b7532698e5db2fe1db693d84b58c254e4389d99a27bb9b8f6b", size = 18330053, upload-time = "2026-01-10T06:44:34.617Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/12/8b5fc6b9c487a09a7957188e0943c9ff08432c65e34567cabc1623b03a51/numpy-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:5de60946f14ebe15e713a6f22850c2372fa72f4ff9a432ab44aa90edcadaa65a", size = 6152482, upload-time = "2026-01-10T06:44:36.798Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/a5/9f8ca5856b8940492fc24fbe13c1bc34d65ddf4079097cf9e53164d094e1/numpy-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8f085da926c0d491ffff3096f91078cc97ea67e7e6b65e490bc8dcda65663be2", size = 12627117, upload-time = "2026-01-10T06:44:38.828Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/0d/eca3d962f9eef265f01a8e0d20085c6dd1f443cbffc11b6dede81fd82356/numpy-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6436cffb4f2bf26c974344439439c95e152c9a527013f26b3577be6c2ca64295", size = 10667121, upload-time = "2026-01-10T06:44:41.644Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "25.0"
|
version = "25.0"
|
||||||
@@ -466,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" },
|
||||||
@@ -491,6 +541,7 @@ dependencies = [
|
|||||||
{ name = "jedi-language-server" },
|
{ name = "jedi-language-server" },
|
||||||
{ name = "lsprotocol" },
|
{ name = "lsprotocol" },
|
||||||
{ name = "mypy-extensions" },
|
{ name = "mypy-extensions" },
|
||||||
|
{ name = "numpy" },
|
||||||
{ name = "packaging" },
|
{ name = "packaging" },
|
||||||
{ name = "parso" },
|
{ name = "parso" },
|
||||||
{ name = "pathspec" },
|
{ name = "pathspec" },
|
||||||
@@ -535,6 +586,7 @@ requires-dist = [
|
|||||||
{ name = "jedi-language-server", specifier = "==0.46.0" },
|
{ name = "jedi-language-server", specifier = "==0.46.0" },
|
||||||
{ name = "lsprotocol", specifier = "==2025.0.0" },
|
{ name = "lsprotocol", specifier = "==2025.0.0" },
|
||||||
{ name = "mypy-extensions", specifier = "==1.1.0" },
|
{ name = "mypy-extensions", specifier = "==1.1.0" },
|
||||||
|
{ name = "numpy", specifier = ">=2.4.1" },
|
||||||
{ name = "packaging", specifier = "==25.0" },
|
{ name = "packaging", specifier = "==25.0" },
|
||||||
{ name = "parso", specifier = "==0.8.5" },
|
{ name = "parso", specifier = "==0.8.5" },
|
||||||
{ name = "pathspec", specifier = "==0.12.1" },
|
{ name = "pathspec", specifier = "==0.12.1" },
|
||||||
|
|||||||
Reference in New Issue
Block a user