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):
|
|
||||||
"""Simple vector projection onto an axis."""
|
def proj(vec, axis: int = 1):
|
||||||
|
"""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 (
|
||||||
@@ -39,19 +36,21 @@ def rotate(v, angle=90, axis=1):
|
|||||||
+ np.cross(k, v) * np.sin(angle)
|
+ np.cross(k, v) * np.sin(angle)
|
||||||
+ 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.
|
||||||
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)
|
||||||
|
|
||||||
@@ -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