增加局域网发布消息+全图+锥桶
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,5 @@ build/
|
|||||||
dist/
|
dist/
|
||||||
wheels/
|
wheels/
|
||||||
*.egg-info
|
*.egg-info
|
||||||
|
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
|
|||||||
176
README.md
176
README.md
@@ -0,0 +1,176 @@
|
|||||||
|
# Origincar Simulation
|
||||||
|
|
||||||
|
基于 MotrixSim 的阿克曼小车仿真,支持键盘控制和 HTTP API 局域网共享。
|
||||||
|
|
||||||
|
## 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run mxpython main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## HTTP API(端口 8765)
|
||||||
|
|
||||||
|
仿真启动后,局域网内其他设备可通过 HTTP 获取摄像头图像、IMU 数据和发送控制指令。
|
||||||
|
|
||||||
|
### GET `/image`
|
||||||
|
|
||||||
|
获取前置摄像头最新 JPEG 图像。浏览器可直接打开。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 浏览器
|
||||||
|
http://<仿真机IP>:8765/image
|
||||||
|
|
||||||
|
# curl
|
||||||
|
curl http://192.168.1.100:8765/image -o frame.jpg
|
||||||
|
|
||||||
|
# Python
|
||||||
|
import requests
|
||||||
|
r = requests.get("http://192.168.1.100:8765/image")
|
||||||
|
with open("frame.jpg", "wb") as f:
|
||||||
|
f.write(r.content)
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET `/state`
|
||||||
|
|
||||||
|
获取小车当前状态(JSON)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://192.168.1.100:8765/state
|
||||||
|
```
|
||||||
|
|
||||||
|
返回示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"x": -2.0,
|
||||||
|
"y": -2.3,
|
||||||
|
"z": 0.08,
|
||||||
|
"yaw_deg": 0.0,
|
||||||
|
"speed_target": 1.0,
|
||||||
|
"speed_actual": 0.98,
|
||||||
|
"steer_target": 0.0,
|
||||||
|
"speed_amp": 1.0,
|
||||||
|
"steer_amp": 0.35
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET `/imu`
|
||||||
|
|
||||||
|
获取 IMU 数据(含 MPU6050 噪声),JSON。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://192.168.1.100:8765/imu
|
||||||
|
```
|
||||||
|
|
||||||
|
返回示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"orientation": {"w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0},
|
||||||
|
"angular_velocity": {"x": 0.001, "y": -0.003, "z": 0.008},
|
||||||
|
"linear_acceleration": {"x": 0.02, "y": -0.01, "z": 9.81}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
噪声参数(MPU6050 级别):
|
||||||
|
- 陀螺仪白噪声 σ = 0.01 rad/s,bias 随机游走
|
||||||
|
- 加速度计白噪声 σ = 0.05 m/s²,bias 随机游走
|
||||||
|
|
||||||
|
### POST `/cmd`
|
||||||
|
|
||||||
|
发送控制指令(JSON)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://192.168.1.100:8765/cmd \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"speed": 1.0, "steer": 0.3}'
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `speed` | float | 目标速度 m/s,正=前进,负=后退 |
|
||||||
|
| `steer` | float | 目标转向角 rad,正=左转,负=右转 |
|
||||||
|
|
||||||
|
**Python 客户端示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
IP = "192.168.1.100"
|
||||||
|
|
||||||
|
# 获取图像
|
||||||
|
r = requests.get(f"http://{IP}:8765/image")
|
||||||
|
with open("frame.jpg", "wb") as f:
|
||||||
|
f.write(r.content)
|
||||||
|
|
||||||
|
# 获取状态
|
||||||
|
state = requests.get(f"http://{IP}:8765/state").json()
|
||||||
|
print(f"位置: ({state['x']}, {state['y']}), 速度: {state['speed_actual']} m/s")
|
||||||
|
|
||||||
|
# 发送控制指令
|
||||||
|
requests.post(f"http://{IP}:8765/cmd", json={"speed": 1.0, "steer": 0.2})
|
||||||
|
time.sleep(2)
|
||||||
|
requests.post(f"http://{IP}:8765/cmd", json={"speed": 0.0, "steer": 0.0})
|
||||||
|
```
|
||||||
|
|
||||||
|
**ROS2 桥接示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import rclpy
|
||||||
|
from rclpy.node import Node
|
||||||
|
from sensor_msgs.msg import Image as RosImage
|
||||||
|
from geometry_msgs.msg import Twist
|
||||||
|
from cv_bridge import CvBridge
|
||||||
|
import requests
|
||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
IP = "192.168.1.100"
|
||||||
|
|
||||||
|
class OrigincarBridge(Node):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("origincar_bridge")
|
||||||
|
self.bridge = CvBridge()
|
||||||
|
self.pub = self.create_publisher(RosImage, "/image", 10)
|
||||||
|
self.sub = self.create_subscription(Twist, "/cmd_vel", self.cmd_cb, 10)
|
||||||
|
self.timer = self.create_timer(0.1, self.fetch_and_publish)
|
||||||
|
|
||||||
|
def fetch_and_publish(self):
|
||||||
|
r = requests.get(f"http://{IP}:8765/image", timeout=1)
|
||||||
|
if r.status_code == 200:
|
||||||
|
arr = np.frombuffer(r.content, np.uint8)
|
||||||
|
cv_img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
|
||||||
|
msg = self.bridge.cv2_to_imgmsg(cv_img, "bgr8")
|
||||||
|
self.pub.publish(msg)
|
||||||
|
|
||||||
|
def cmd_cb(self, msg: Twist):
|
||||||
|
requests.post(f"http://{IP}:8765/cmd", json={
|
||||||
|
"speed": msg.linear.x,
|
||||||
|
"steer": msg.angular.z
|
||||||
|
})
|
||||||
|
|
||||||
|
rclpy.init()
|
||||||
|
node = OrigincarBridge()
|
||||||
|
rclpy.spin(node)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 键盘控制
|
||||||
|
|
||||||
|
| 按键 | 方式 | 作用 |
|
||||||
|
|------|------|------|
|
||||||
|
| W/S | 按住 | 前进/后退 |
|
||||||
|
| A/D | 按住 | 左转/右转 |
|
||||||
|
| ↑/↓ | 点按 | 速度幅度 ±0.2 m/s(0~2.0) |
|
||||||
|
| ←/→ | 点按 | 转向幅度 ±0.05 rad(0~0.5) |
|
||||||
|
| Space | 点按 | 截图保存到 `captures/` |
|
||||||
|
|
||||||
|
键盘与 HTTP `/cmd` 可同时使用:按住 W/A/S/D 时键盘优先,松开后自动切回 HTTP 控制。
|
||||||
|
|
||||||
|
## 场景结构
|
||||||
|
|
||||||
|
```
|
||||||
|
scene.xml — 5m×5m 地图 + 40cm 白色围栏 + 阿克曼小车
|
||||||
|
main.py — 仿真控制 + HTTP API 服务
|
||||||
|
origincar.urdf / origincar.xacro — 小车模型(参考)
|
||||||
|
```
|
||||||
|
|||||||
BIN
captures/front_cam_0000.png
Normal file
BIN
captures/front_cam_0000.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 732 KiB |
219
cone.obj
Normal file
219
cone.obj
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
# Traffic cone
|
||||||
|
v 0.100000 0.000000 0.000000
|
||||||
|
v 0.098481 0.017365 0.000000
|
||||||
|
v 0.093969 0.034202 0.000000
|
||||||
|
v 0.086603 0.050000 0.000000
|
||||||
|
v 0.076604 0.064279 0.000000
|
||||||
|
v 0.064279 0.076604 0.000000
|
||||||
|
v 0.050000 0.086603 0.000000
|
||||||
|
v 0.034202 0.093969 0.000000
|
||||||
|
v 0.017365 0.098481 0.000000
|
||||||
|
v 0.000000 0.100000 0.000000
|
||||||
|
v -0.017365 0.098481 0.000000
|
||||||
|
v -0.034202 0.093969 0.000000
|
||||||
|
v -0.050000 0.086603 0.000000
|
||||||
|
v -0.064279 0.076604 0.000000
|
||||||
|
v -0.076604 0.064279 0.000000
|
||||||
|
v -0.086603 0.050000 0.000000
|
||||||
|
v -0.093969 0.034202 0.000000
|
||||||
|
v -0.098481 0.017365 0.000000
|
||||||
|
v -0.100000 0.000000 0.000000
|
||||||
|
v -0.098481 -0.017365 0.000000
|
||||||
|
v -0.093969 -0.034202 0.000000
|
||||||
|
v -0.086603 -0.050000 0.000000
|
||||||
|
v -0.076604 -0.064279 0.000000
|
||||||
|
v -0.064279 -0.076604 0.000000
|
||||||
|
v -0.050000 -0.086603 0.000000
|
||||||
|
v -0.034202 -0.093969 0.000000
|
||||||
|
v -0.017365 -0.098481 0.000000
|
||||||
|
v -0.000000 -0.100000 0.000000
|
||||||
|
v 0.017365 -0.098481 0.000000
|
||||||
|
v 0.034202 -0.093969 0.000000
|
||||||
|
v 0.050000 -0.086603 0.000000
|
||||||
|
v 0.064279 -0.076604 0.000000
|
||||||
|
v 0.076604 -0.064279 0.000000
|
||||||
|
v 0.086603 -0.050000 0.000000
|
||||||
|
v 0.093969 -0.034202 0.000000
|
||||||
|
v 0.098481 -0.017365 0.000000
|
||||||
|
v 0.025000 0.000000 0.270000
|
||||||
|
v 0.024620 0.004341 0.270000
|
||||||
|
v 0.023492 0.008551 0.270000
|
||||||
|
v 0.021651 0.012500 0.270000
|
||||||
|
v 0.019151 0.016070 0.270000
|
||||||
|
v 0.016070 0.019151 0.270000
|
||||||
|
v 0.012500 0.021651 0.270000
|
||||||
|
v 0.008551 0.023492 0.270000
|
||||||
|
v 0.004341 0.024620 0.270000
|
||||||
|
v 0.000000 0.025000 0.270000
|
||||||
|
v -0.004341 0.024620 0.270000
|
||||||
|
v -0.008551 0.023492 0.270000
|
||||||
|
v -0.012500 0.021651 0.270000
|
||||||
|
v -0.016070 0.019151 0.270000
|
||||||
|
v -0.019151 0.016070 0.270000
|
||||||
|
v -0.021651 0.012500 0.270000
|
||||||
|
v -0.023492 0.008551 0.270000
|
||||||
|
v -0.024620 0.004341 0.270000
|
||||||
|
v -0.025000 0.000000 0.270000
|
||||||
|
v -0.024620 -0.004341 0.270000
|
||||||
|
v -0.023492 -0.008551 0.270000
|
||||||
|
v -0.021651 -0.012500 0.270000
|
||||||
|
v -0.019151 -0.016070 0.270000
|
||||||
|
v -0.016070 -0.019151 0.270000
|
||||||
|
v -0.012500 -0.021651 0.270000
|
||||||
|
v -0.008551 -0.023492 0.270000
|
||||||
|
v -0.004341 -0.024620 0.270000
|
||||||
|
v -0.000000 -0.025000 0.270000
|
||||||
|
v 0.004341 -0.024620 0.270000
|
||||||
|
v 0.008551 -0.023492 0.270000
|
||||||
|
v 0.012500 -0.021651 0.270000
|
||||||
|
v 0.016070 -0.019151 0.270000
|
||||||
|
v 0.019151 -0.016070 0.270000
|
||||||
|
v 0.021651 -0.012500 0.270000
|
||||||
|
v 0.023492 -0.008551 0.270000
|
||||||
|
v 0.024620 -0.004341 0.270000
|
||||||
|
v 0.000000 0.000000 0.000000
|
||||||
|
v 0.000000 0.000000 0.270000
|
||||||
|
f 1 2 38
|
||||||
|
f 1 38 37
|
||||||
|
f 2 3 39
|
||||||
|
f 2 39 38
|
||||||
|
f 3 4 40
|
||||||
|
f 3 40 39
|
||||||
|
f 4 5 41
|
||||||
|
f 4 41 40
|
||||||
|
f 5 6 42
|
||||||
|
f 5 42 41
|
||||||
|
f 6 7 43
|
||||||
|
f 6 43 42
|
||||||
|
f 7 8 44
|
||||||
|
f 7 44 43
|
||||||
|
f 8 9 45
|
||||||
|
f 8 45 44
|
||||||
|
f 9 10 46
|
||||||
|
f 9 46 45
|
||||||
|
f 10 11 47
|
||||||
|
f 10 47 46
|
||||||
|
f 11 12 48
|
||||||
|
f 11 48 47
|
||||||
|
f 12 13 49
|
||||||
|
f 12 49 48
|
||||||
|
f 13 14 50
|
||||||
|
f 13 50 49
|
||||||
|
f 14 15 51
|
||||||
|
f 14 51 50
|
||||||
|
f 15 16 52
|
||||||
|
f 15 52 51
|
||||||
|
f 16 17 53
|
||||||
|
f 16 53 52
|
||||||
|
f 17 18 54
|
||||||
|
f 17 54 53
|
||||||
|
f 18 19 55
|
||||||
|
f 18 55 54
|
||||||
|
f 19 20 56
|
||||||
|
f 19 56 55
|
||||||
|
f 20 21 57
|
||||||
|
f 20 57 56
|
||||||
|
f 21 22 58
|
||||||
|
f 21 58 57
|
||||||
|
f 22 23 59
|
||||||
|
f 22 59 58
|
||||||
|
f 23 24 60
|
||||||
|
f 23 60 59
|
||||||
|
f 24 25 61
|
||||||
|
f 24 61 60
|
||||||
|
f 25 26 62
|
||||||
|
f 25 62 61
|
||||||
|
f 26 27 63
|
||||||
|
f 26 63 62
|
||||||
|
f 27 28 64
|
||||||
|
f 27 64 63
|
||||||
|
f 28 29 65
|
||||||
|
f 28 65 64
|
||||||
|
f 29 30 66
|
||||||
|
f 29 66 65
|
||||||
|
f 30 31 67
|
||||||
|
f 30 67 66
|
||||||
|
f 31 32 68
|
||||||
|
f 31 68 67
|
||||||
|
f 32 33 69
|
||||||
|
f 32 69 68
|
||||||
|
f 33 34 70
|
||||||
|
f 33 70 69
|
||||||
|
f 34 35 71
|
||||||
|
f 34 71 70
|
||||||
|
f 35 36 72
|
||||||
|
f 35 72 71
|
||||||
|
f 36 1 37
|
||||||
|
f 36 37 72
|
||||||
|
f 73 2 1
|
||||||
|
f 73 3 2
|
||||||
|
f 73 4 3
|
||||||
|
f 73 5 4
|
||||||
|
f 73 6 5
|
||||||
|
f 73 7 6
|
||||||
|
f 73 8 7
|
||||||
|
f 73 9 8
|
||||||
|
f 73 10 9
|
||||||
|
f 73 11 10
|
||||||
|
f 73 12 11
|
||||||
|
f 73 13 12
|
||||||
|
f 73 14 13
|
||||||
|
f 73 15 14
|
||||||
|
f 73 16 15
|
||||||
|
f 73 17 16
|
||||||
|
f 73 18 17
|
||||||
|
f 73 19 18
|
||||||
|
f 73 20 19
|
||||||
|
f 73 21 20
|
||||||
|
f 73 22 21
|
||||||
|
f 73 23 22
|
||||||
|
f 73 24 23
|
||||||
|
f 73 25 24
|
||||||
|
f 73 26 25
|
||||||
|
f 73 27 26
|
||||||
|
f 73 28 27
|
||||||
|
f 73 29 28
|
||||||
|
f 73 30 29
|
||||||
|
f 73 31 30
|
||||||
|
f 73 32 31
|
||||||
|
f 73 33 32
|
||||||
|
f 73 34 33
|
||||||
|
f 73 35 34
|
||||||
|
f 73 36 35
|
||||||
|
f 73 1 36
|
||||||
|
f 74 37 38
|
||||||
|
f 74 38 39
|
||||||
|
f 74 39 40
|
||||||
|
f 74 40 41
|
||||||
|
f 74 41 42
|
||||||
|
f 74 42 43
|
||||||
|
f 74 43 44
|
||||||
|
f 74 44 45
|
||||||
|
f 74 45 46
|
||||||
|
f 74 46 47
|
||||||
|
f 74 47 48
|
||||||
|
f 74 48 49
|
||||||
|
f 74 49 50
|
||||||
|
f 74 50 51
|
||||||
|
f 74 51 52
|
||||||
|
f 74 52 53
|
||||||
|
f 74 53 54
|
||||||
|
f 74 54 55
|
||||||
|
f 74 55 56
|
||||||
|
f 74 56 57
|
||||||
|
f 74 57 58
|
||||||
|
f 74 58 59
|
||||||
|
f 74 59 60
|
||||||
|
f 74 60 61
|
||||||
|
f 74 61 62
|
||||||
|
f 74 62 63
|
||||||
|
f 74 63 64
|
||||||
|
f 74 64 65
|
||||||
|
f 74 65 66
|
||||||
|
f 74 66 67
|
||||||
|
f 74 67 68
|
||||||
|
f 74 68 69
|
||||||
|
f 74 69 70
|
||||||
|
f 74 70 71
|
||||||
|
f 74 71 72
|
||||||
|
f 74 72 37
|
||||||
145
cone_white.obj
Normal file
145
cone_white.obj
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# White band
|
||||||
|
v 0.066700 0.000000 0.000000
|
||||||
|
v 0.065687 0.011582 0.000000
|
||||||
|
v 0.062677 0.022813 0.000000
|
||||||
|
v 0.057764 0.033350 0.000000
|
||||||
|
v 0.051095 0.042874 0.000000
|
||||||
|
v 0.042874 0.051095 0.000000
|
||||||
|
v 0.033350 0.057764 0.000000
|
||||||
|
v 0.022813 0.062677 0.000000
|
||||||
|
v 0.011582 0.065687 0.000000
|
||||||
|
v 0.000000 0.066700 0.000000
|
||||||
|
v -0.011582 0.065687 0.000000
|
||||||
|
v -0.022813 0.062677 0.000000
|
||||||
|
v -0.033350 0.057764 0.000000
|
||||||
|
v -0.042874 0.051095 0.000000
|
||||||
|
v -0.051095 0.042874 0.000000
|
||||||
|
v -0.057764 0.033350 0.000000
|
||||||
|
v -0.062677 0.022813 0.000000
|
||||||
|
v -0.065687 0.011582 0.000000
|
||||||
|
v -0.066700 0.000000 0.000000
|
||||||
|
v -0.065687 -0.011582 0.000000
|
||||||
|
v -0.062677 -0.022813 0.000000
|
||||||
|
v -0.057764 -0.033350 0.000000
|
||||||
|
v -0.051095 -0.042874 0.000000
|
||||||
|
v -0.042874 -0.051095 0.000000
|
||||||
|
v -0.033350 -0.057764 0.000000
|
||||||
|
v -0.022813 -0.062677 0.000000
|
||||||
|
v -0.011582 -0.065687 0.000000
|
||||||
|
v -0.000000 -0.066700 0.000000
|
||||||
|
v 0.011582 -0.065687 0.000000
|
||||||
|
v 0.022813 -0.062677 0.000000
|
||||||
|
v 0.033350 -0.057764 0.000000
|
||||||
|
v 0.042874 -0.051095 0.000000
|
||||||
|
v 0.051095 -0.042874 0.000000
|
||||||
|
v 0.057764 -0.033350 0.000000
|
||||||
|
v 0.062677 -0.022813 0.000000
|
||||||
|
v 0.065687 -0.011582 0.000000
|
||||||
|
v 0.038900 0.000000 0.100000
|
||||||
|
v 0.038309 0.006755 0.100000
|
||||||
|
v 0.036554 0.013305 0.100000
|
||||||
|
v 0.033688 0.019450 0.100000
|
||||||
|
v 0.029799 0.025004 0.100000
|
||||||
|
v 0.025004 0.029799 0.100000
|
||||||
|
v 0.019450 0.033688 0.100000
|
||||||
|
v 0.013305 0.036554 0.100000
|
||||||
|
v 0.006755 0.038309 0.100000
|
||||||
|
v 0.000000 0.038900 0.100000
|
||||||
|
v -0.006755 0.038309 0.100000
|
||||||
|
v -0.013305 0.036554 0.100000
|
||||||
|
v -0.019450 0.033688 0.100000
|
||||||
|
v -0.025004 0.029799 0.100000
|
||||||
|
v -0.029799 0.025004 0.100000
|
||||||
|
v -0.033688 0.019450 0.100000
|
||||||
|
v -0.036554 0.013305 0.100000
|
||||||
|
v -0.038309 0.006755 0.100000
|
||||||
|
v -0.038900 0.000000 0.100000
|
||||||
|
v -0.038309 -0.006755 0.100000
|
||||||
|
v -0.036554 -0.013305 0.100000
|
||||||
|
v -0.033688 -0.019450 0.100000
|
||||||
|
v -0.029799 -0.025004 0.100000
|
||||||
|
v -0.025004 -0.029799 0.100000
|
||||||
|
v -0.019450 -0.033688 0.100000
|
||||||
|
v -0.013305 -0.036554 0.100000
|
||||||
|
v -0.006755 -0.038309 0.100000
|
||||||
|
v -0.000000 -0.038900 0.100000
|
||||||
|
v 0.006755 -0.038309 0.100000
|
||||||
|
v 0.013305 -0.036554 0.100000
|
||||||
|
v 0.019450 -0.033688 0.100000
|
||||||
|
v 0.025004 -0.029799 0.100000
|
||||||
|
v 0.029799 -0.025004 0.100000
|
||||||
|
v 0.033688 -0.019450 0.100000
|
||||||
|
v 0.036554 -0.013305 0.100000
|
||||||
|
v 0.038309 -0.006755 0.100000
|
||||||
|
f 1 2 38
|
||||||
|
f 1 38 37
|
||||||
|
f 2 3 39
|
||||||
|
f 2 39 38
|
||||||
|
f 3 4 40
|
||||||
|
f 3 40 39
|
||||||
|
f 4 5 41
|
||||||
|
f 4 41 40
|
||||||
|
f 5 6 42
|
||||||
|
f 5 42 41
|
||||||
|
f 6 7 43
|
||||||
|
f 6 43 42
|
||||||
|
f 7 8 44
|
||||||
|
f 7 44 43
|
||||||
|
f 8 9 45
|
||||||
|
f 8 45 44
|
||||||
|
f 9 10 46
|
||||||
|
f 9 46 45
|
||||||
|
f 10 11 47
|
||||||
|
f 10 47 46
|
||||||
|
f 11 12 48
|
||||||
|
f 11 48 47
|
||||||
|
f 12 13 49
|
||||||
|
f 12 49 48
|
||||||
|
f 13 14 50
|
||||||
|
f 13 50 49
|
||||||
|
f 14 15 51
|
||||||
|
f 14 51 50
|
||||||
|
f 15 16 52
|
||||||
|
f 15 52 51
|
||||||
|
f 16 17 53
|
||||||
|
f 16 53 52
|
||||||
|
f 17 18 54
|
||||||
|
f 17 54 53
|
||||||
|
f 18 19 55
|
||||||
|
f 18 55 54
|
||||||
|
f 19 20 56
|
||||||
|
f 19 56 55
|
||||||
|
f 20 21 57
|
||||||
|
f 20 57 56
|
||||||
|
f 21 22 58
|
||||||
|
f 21 58 57
|
||||||
|
f 22 23 59
|
||||||
|
f 22 59 58
|
||||||
|
f 23 24 60
|
||||||
|
f 23 60 59
|
||||||
|
f 24 25 61
|
||||||
|
f 24 61 60
|
||||||
|
f 25 26 62
|
||||||
|
f 25 62 61
|
||||||
|
f 26 27 63
|
||||||
|
f 26 63 62
|
||||||
|
f 27 28 64
|
||||||
|
f 27 64 63
|
||||||
|
f 28 29 65
|
||||||
|
f 28 65 64
|
||||||
|
f 29 30 66
|
||||||
|
f 29 66 65
|
||||||
|
f 30 31 67
|
||||||
|
f 30 67 66
|
||||||
|
f 31 32 68
|
||||||
|
f 31 68 67
|
||||||
|
f 32 33 69
|
||||||
|
f 32 69 68
|
||||||
|
f 33 34 70
|
||||||
|
f 33 70 69
|
||||||
|
f 34 35 71
|
||||||
|
f 34 71 70
|
||||||
|
f 35 36 72
|
||||||
|
f 35 72 71
|
||||||
|
f 36 1 37
|
||||||
|
f 36 37 72
|
||||||
369
main.py
369
main.py
@@ -1,5 +1,372 @@
|
|||||||
|
import io
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import threading
|
||||||
|
from collections import deque
|
||||||
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
|
from motrixsim import SceneData, load_model, run, step
|
||||||
|
from motrixsim.render import CaptureTask, Layout, RenderApp
|
||||||
|
|
||||||
|
# ── Ackermann geometry ──────────────────────────────────────────────
|
||||||
|
L = 0.1682 # wheelbase: front-rear axle distance
|
||||||
|
T = 0.189 # track width: left-right wheel distance
|
||||||
|
|
||||||
|
PORT = 8765
|
||||||
|
|
||||||
|
# ── MPU6050 noise parameters ────────────────────────────────────────
|
||||||
|
GYRO_NOISE_STD = 0.01 # rad/s
|
||||||
|
ACCEL_NOISE_STD = 0.05 # m/s²
|
||||||
|
GYRO_BIAS_WALK = 1e-5 # rad/s per step
|
||||||
|
ACCEL_BIAS_WALK = 1e-4 # m/s² per step
|
||||||
|
|
||||||
|
|
||||||
|
def ackermann_angles(steer_cmd_rad):
|
||||||
|
if abs(steer_cmd_rad) < 1e-6:
|
||||||
|
return 0.0, 0.0
|
||||||
|
R = L / math.tan(abs(steer_cmd_rad))
|
||||||
|
inner = math.atan(L / (R - T / 2))
|
||||||
|
outer = math.atan(L / (R + T / 2))
|
||||||
|
if steer_cmd_rad > 0:
|
||||||
|
return outer, inner
|
||||||
|
else:
|
||||||
|
return -inner, -outer
|
||||||
|
|
||||||
|
|
||||||
|
def quat_to_body_rotation(qw, qx, qy, qz):
|
||||||
|
"""World-frame vector → body-frame vector using quaternion."""
|
||||||
|
v = np.array
|
||||||
|
R = np.array([
|
||||||
|
[1 - 2*(qy*qy + qz*qz), 2*(qx*qy + qw*qz), 2*(qx*qz - qw*qy)],
|
||||||
|
[ 2*(qx*qy - qw*qz), 1 - 2*(qx*qx + qz*qz), 2*(qy*qz + qw*qx)],
|
||||||
|
[ 2*(qx*qz + qw*qy), 2*(qy*qz - qw*qx), 1 - 2*(qx*qx + qy*qy)],
|
||||||
|
])
|
||||||
|
return R
|
||||||
|
|
||||||
|
|
||||||
|
class MPU6050Sim:
|
||||||
|
def __init__(self):
|
||||||
|
self.gyro_bias = np.zeros(3)
|
||||||
|
self.accel_bias = np.zeros(3)
|
||||||
|
|
||||||
|
def apply(self, gyro_true, accel_true):
|
||||||
|
self.gyro_bias += np.random.normal(0, GYRO_BIAS_WALK, 3)
|
||||||
|
self.accel_bias += np.random.normal(0, ACCEL_BIAS_WALK, 3)
|
||||||
|
gyro = gyro_true + self.gyro_bias + np.random.normal(0, GYRO_NOISE_STD, 3)
|
||||||
|
accel = accel_true + self.accel_bias + np.random.normal(0, ACCEL_NOISE_STD, 3)
|
||||||
|
return gyro, accel
|
||||||
|
|
||||||
|
|
||||||
|
# ── Shared state (main ↔ HTTP thread) ──────────────────────────────
|
||||||
|
shared = {
|
||||||
|
"latest_jpg": None, # bytes
|
||||||
|
"cmd_speed": 0.0, # from POST /cmd
|
||||||
|
"cmd_steer": 0.0, # from POST /cmd
|
||||||
|
"imu_json": b"{}",
|
||||||
|
"state_json": b"{}",
|
||||||
|
"key_active": False, # True when W/A/S/D pressed
|
||||||
|
}
|
||||||
|
shared_lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPHandler(BaseHTTPRequestHandler):
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
pass # suppress logs
|
||||||
|
|
||||||
|
def _send_json(self, data):
|
||||||
|
body = json.dumps(data).encode()
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/json")
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
|
||||||
|
def _send_jpg(self, jpg_bytes):
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "image/jpeg")
|
||||||
|
self.send_header("Content-Length", str(len(jpg_bytes)))
|
||||||
|
self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(jpg_bytes)
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == "/image":
|
||||||
|
with shared_lock:
|
||||||
|
jpg = shared["latest_jpg"]
|
||||||
|
if jpg:
|
||||||
|
self._send_jpg(jpg)
|
||||||
|
else:
|
||||||
|
self.send_response(204)
|
||||||
|
self.end_headers()
|
||||||
|
elif self.path == "/state":
|
||||||
|
with shared_lock:
|
||||||
|
body = shared["state_json"]
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/json")
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
elif self.path == "/imu":
|
||||||
|
with shared_lock:
|
||||||
|
body = shared["imu_json"]
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/json")
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
if self.path == "/cmd":
|
||||||
|
length = int(self.headers.get("Content-Length", 0))
|
||||||
|
body = json.loads(self.rfile.read(length))
|
||||||
|
with shared_lock:
|
||||||
|
shared["cmd_speed"] = float(body.get("speed", 0))
|
||||||
|
shared["cmd_steer"] = float(body.get("steer", 0))
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
else:
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
|
||||||
|
def start_http_server():
|
||||||
|
server = HTTPServer(("0.0.0.0", PORT), HTTPHandler)
|
||||||
|
server.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
|
# ── Main ────────────────────────────────────────────────────────────
|
||||||
def main():
|
def main():
|
||||||
print("Hello from motrixsim-examples!")
|
# Start HTTP server in background thread
|
||||||
|
http_thread = threading.Thread(target=start_http_server, daemon=True)
|
||||||
|
http_thread.start()
|
||||||
|
|
||||||
|
with RenderApp() as render:
|
||||||
|
render.opt.set_left_panel_vis(True)
|
||||||
|
|
||||||
|
model = load_model("scene.xml")
|
||||||
|
|
||||||
|
cameras = model.cameras
|
||||||
|
front_cam = cameras[0]
|
||||||
|
front_cam.set_render_target("image", 1280, 960)
|
||||||
|
|
||||||
|
render.launch(model)
|
||||||
|
render.widgets.create_camera_viewport(
|
||||||
|
front_cam, layout=Layout(right=0, top=0, width=480, height=360)
|
||||||
|
)
|
||||||
|
|
||||||
|
data = SceneData(model)
|
||||||
|
init_pos = data.dof_pos.copy()
|
||||||
|
init_pos[0] = -2.0
|
||||||
|
init_pos[1] = -2.3
|
||||||
|
init_pos[5] = 0.0
|
||||||
|
init_pos[6] = 1.0
|
||||||
|
data.set_dof_pos(init_pos, model)
|
||||||
|
|
||||||
|
# Drive actuators
|
||||||
|
drive_dl = model.get_actuator("down_left_drive")
|
||||||
|
drive_dr = model.get_actuator("down_right_drive")
|
||||||
|
drive_ul = model.get_actuator("up_left_drive")
|
||||||
|
drive_ur = model.get_actuator("up_right_drive")
|
||||||
|
|
||||||
|
# Steering actuators
|
||||||
|
steer_ul = model.get_actuator("up_left_steer")
|
||||||
|
steer_ur = model.get_actuator("up_right_steer")
|
||||||
|
|
||||||
|
speed = 0.0
|
||||||
|
steer_cmd = 0.0
|
||||||
|
speed_amp = 1.0
|
||||||
|
steer_amp = 0.35
|
||||||
|
frame = 0
|
||||||
|
|
||||||
|
base_link = model.get_link("base_link")
|
||||||
|
|
||||||
|
# IMU state
|
||||||
|
imu = MPU6050Sim()
|
||||||
|
prev_vel_world = np.zeros(3)
|
||||||
|
timestep = float(model.options.timestep)
|
||||||
|
|
||||||
|
# Continuous image capture
|
||||||
|
capture_task = None
|
||||||
|
capture_tasks: deque[tuple[int, CaptureTask]] = deque()
|
||||||
|
capture_index = 0
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
print("Origincar — HTTP API on port", PORT)
|
||||||
|
print(" http://<ip>:{}/image — camera JPEG".format(PORT))
|
||||||
|
print(" http://<ip>:{}/state — position & speed".format(PORT))
|
||||||
|
print(" http://<ip>:{}/imu — IMU (MPU6050 noise)".format(PORT))
|
||||||
|
print(" POST /cmd {\"speed\":1.0,\"steer\":0.3}")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
def phys_step():
|
||||||
|
nonlocal prev_vel_world
|
||||||
|
|
||||||
|
# ── P-controller ──
|
||||||
|
vel = base_link.get_linear_velocity(data)
|
||||||
|
pose = base_link.get_pose(data)
|
||||||
|
qw, qx, qy, qz = pose[3], pose[4], pose[5], pose[6]
|
||||||
|
fwd_x = 1 - 2 * (qy * qy + qz * qz)
|
||||||
|
fwd_y = 2 * (qx * qy + qw * qz)
|
||||||
|
actual_speed = vel[0] * fwd_x + vel[1] * fwd_y
|
||||||
|
error = speed - actual_speed
|
||||||
|
kp = 5.0
|
||||||
|
base_torque = max(-15.0, min(15.0, kp * error))
|
||||||
|
|
||||||
|
# ── Differential ──
|
||||||
|
if abs(steer_cmd) < 1e-6:
|
||||||
|
factor_l, factor_r = 1.0, 1.0
|
||||||
|
else:
|
||||||
|
R_turn = L / math.tan(abs(steer_cmd))
|
||||||
|
outer_f = (R_turn + T / 2) / R_turn
|
||||||
|
inner_f = (R_turn - T / 2) / R_turn
|
||||||
|
if steer_cmd > 0:
|
||||||
|
factor_l, factor_r = inner_f, outer_f
|
||||||
|
else:
|
||||||
|
factor_l, factor_r = outer_f, inner_f
|
||||||
|
|
||||||
|
tq_l = max(-15.0, min(15.0, base_torque * factor_l))
|
||||||
|
tq_r = max(-15.0, min(15.0, base_torque * factor_r))
|
||||||
|
|
||||||
|
drive_dl.set_ctrl(data, tq_l)
|
||||||
|
drive_dr.set_ctrl(data, -tq_r)
|
||||||
|
drive_ul.set_ctrl(data, tq_l)
|
||||||
|
drive_ur.set_ctrl(data, -tq_r)
|
||||||
|
|
||||||
|
steer_l, steer_r = ackermann_angles(steer_cmd)
|
||||||
|
steer_ul.set_ctrl(data, steer_l)
|
||||||
|
steer_ur.set_ctrl(data, steer_r)
|
||||||
|
|
||||||
|
step(model, data)
|
||||||
|
|
||||||
|
# ── IMU with MPU6050 noise ──
|
||||||
|
ang_vel = np.array(base_link.get_angular_velocity(data)) # world frame
|
||||||
|
vel_world = np.array(vel)
|
||||||
|
accel_world = (vel_world - prev_vel_world) / timestep
|
||||||
|
prev_vel_world = vel_world
|
||||||
|
|
||||||
|
# Rotate to body frame
|
||||||
|
R_w2b = quat_to_body_rotation(qw, qx, qy, qz)
|
||||||
|
ang_vel_body = R_w2b @ ang_vel
|
||||||
|
accel_body = R_w2b @ accel_world
|
||||||
|
|
||||||
|
gyro_n, accel_n = imu.apply(ang_vel_body, accel_body)
|
||||||
|
|
||||||
|
with shared_lock:
|
||||||
|
shared["imu_json"] = json.dumps({
|
||||||
|
"orientation": {"w": float(qw), "x": float(qx), "y": float(qy), "z": float(qz)},
|
||||||
|
"angular_velocity": {"x": float(gyro_n[0]), "y": float(gyro_n[1]), "z": float(gyro_n[2])},
|
||||||
|
"linear_acceleration": {"x": float(accel_n[0]), "y": float(accel_n[1]), "z": float(accel_n[2])},
|
||||||
|
}).encode()
|
||||||
|
|
||||||
|
def render_step():
|
||||||
|
nonlocal speed, steer_cmd, capture_index, frame, speed_amp, steer_amp
|
||||||
|
|
||||||
|
render.sync(data)
|
||||||
|
inp = render.input
|
||||||
|
|
||||||
|
frame += 1
|
||||||
|
|
||||||
|
# ── Keyboard controls (speed & steer independent) ──
|
||||||
|
if inp.is_key_just_pressed("up"):
|
||||||
|
speed_amp = min(speed_amp + 0.2, 2.0)
|
||||||
|
if inp.is_key_just_pressed("down"):
|
||||||
|
speed_amp = max(speed_amp - 0.2, 0.0)
|
||||||
|
if inp.is_key_just_pressed("left"):
|
||||||
|
steer_amp = min(steer_amp + 0.05, 0.5)
|
||||||
|
if inp.is_key_just_pressed("right"):
|
||||||
|
steer_amp = max(steer_amp - 0.05, 0.0)
|
||||||
|
|
||||||
|
speed = 0.0
|
||||||
|
if inp.is_key_pressed("w"):
|
||||||
|
speed = speed_amp
|
||||||
|
if inp.is_key_pressed("s"):
|
||||||
|
speed = -speed_amp
|
||||||
|
|
||||||
|
steer_cmd = 0.0 # always reset — returns to center when A/D released
|
||||||
|
if inp.is_key_pressed("a"):
|
||||||
|
steer_cmd = steer_amp
|
||||||
|
if inp.is_key_pressed("d"):
|
||||||
|
steer_cmd = -steer_amp
|
||||||
|
|
||||||
|
key_active = speed != 0.0 or steer_cmd != 0.0
|
||||||
|
|
||||||
|
# ── HTTP /cmd override (if keyboard not active) ──
|
||||||
|
if not key_active:
|
||||||
|
with shared_lock:
|
||||||
|
speed = shared["cmd_speed"]
|
||||||
|
steer_cmd = shared["cmd_steer"]
|
||||||
|
|
||||||
|
with shared_lock:
|
||||||
|
shared["key_active"] = key_active
|
||||||
|
|
||||||
|
# ── Continuous image capture (~30 Hz) ──
|
||||||
|
if frame % 2 == 0:
|
||||||
|
rcam = render.get_camera(0)
|
||||||
|
capture_tasks.append((capture_index, rcam.capture()))
|
||||||
|
capture_index += 1
|
||||||
|
|
||||||
|
while capture_tasks:
|
||||||
|
idx, task = capture_tasks[0]
|
||||||
|
if task.state != "pending":
|
||||||
|
capture_tasks.popleft()
|
||||||
|
try:
|
||||||
|
img = task.take_image()
|
||||||
|
if img is not None:
|
||||||
|
arr = img.pixels
|
||||||
|
if arr.shape[2] == 4:
|
||||||
|
pil = PILImage.fromarray(arr, "RGBA").convert("RGB")
|
||||||
|
else:
|
||||||
|
pil = PILImage.fromarray(arr, "RGB")
|
||||||
|
buf = io.BytesIO()
|
||||||
|
pil.save(buf, format="JPEG", quality=80)
|
||||||
|
with shared_lock:
|
||||||
|
shared["latest_jpg"] = buf.getvalue()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# ── Console status ──
|
||||||
|
if frame % 60 == 0:
|
||||||
|
pose = base_link.get_pose(data)
|
||||||
|
x, y, z = pose[0], pose[1], pose[2]
|
||||||
|
qw, qx, qy, qz = pose[3], pose[4], pose[5], pose[6]
|
||||||
|
yaw = math.atan2(2 * (qw * qz + qx * qy), 1 - 2 * (qy * qy + qz * qz))
|
||||||
|
v = base_link.get_linear_velocity(data)
|
||||||
|
actual_spd = math.hypot(v[0], v[1])
|
||||||
|
with shared_lock:
|
||||||
|
shared["state_json"] = json.dumps({
|
||||||
|
"x": round(float(x), 3), "y": round(float(y), 3), "z": round(float(z), 3),
|
||||||
|
"yaw_deg": round(math.degrees(yaw), 1),
|
||||||
|
"speed_target": round(speed, 2),
|
||||||
|
"speed_actual": round(float(actual_spd), 2),
|
||||||
|
"steer_target": round(steer_cmd, 3),
|
||||||
|
"speed_amp": round(speed_amp, 1),
|
||||||
|
"steer_amp": round(steer_amp, 3),
|
||||||
|
}).encode()
|
||||||
|
print(f"[pos] x={x:+.3f} y={y:+.3f} z={z:+.3f} | yaw={math.degrees(yaw):+.1f}° "
|
||||||
|
f"spd={speed:.1f}/{actual_spd:.2f} steer={steer_cmd:+.2f}", flush=True)
|
||||||
|
|
||||||
|
# ── Snapshot to disk ──
|
||||||
|
if inp.is_key_just_pressed("space"):
|
||||||
|
with shared_lock:
|
||||||
|
jpg = shared["latest_jpg"]
|
||||||
|
if jpg:
|
||||||
|
os.makedirs("captures", exist_ok=True)
|
||||||
|
path = f"captures/front_cam_{capture_index:04d}.jpg"
|
||||||
|
with open(path, "wb") as f:
|
||||||
|
f.write(jpg)
|
||||||
|
print(f"Captured: {path}")
|
||||||
|
|
||||||
|
run.render_loop(model.options.timestep, 60, phys_step, render_step)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
BIN
map_full.png
Normal file
BIN
map_full.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 299 KiB |
@@ -4,4 +4,7 @@ version = "0.1.0"
|
|||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = []
|
dependencies = [
|
||||||
|
"motrixsim-core",
|
||||||
|
"pillow",
|
||||||
|
]
|
||||||
|
|||||||
148
scene.xml
Normal file
148
scene.xml
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
<mujoco model="origincar_scene">
|
||||||
|
<compiler angle="radian" autolimits="true"/>
|
||||||
|
|
||||||
|
<option timestep="0.005" iterations="10" solver="PGS"/>
|
||||||
|
|
||||||
|
<statistic center="0 0 0.1" extent="3"/>
|
||||||
|
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0"/>
|
||||||
|
<rgba haze="0.15 0.25 0.35 1"/>
|
||||||
|
<global azimuth="120" elevation="-20"/>
|
||||||
|
<quality shadowsize="4096"/>
|
||||||
|
</visual>
|
||||||
|
|
||||||
|
<asset>
|
||||||
|
<texture name="checker_tex" type="2d" builtin="checker" width="512" height="512" mark="edge"
|
||||||
|
rgb1="0.35 0.45 0.55" rgb2="0.55 0.65 0.75" markrgb="0.15 0.15 0.15"/>
|
||||||
|
<material name="checker_mat" texture="checker_tex" texrepeat="5 5" texuniform="true" reflectance="0.05"/>
|
||||||
|
|
||||||
|
<mesh name="cone_mesh" file="cone.obj"/>
|
||||||
|
<mesh name="cone_white_mesh" file="cone_white.obj"/>
|
||||||
|
<texture name="map_tex" type="2d" file="map_full.png"/>
|
||||||
|
<material name="map_mat" texture="map_tex" texrepeat="0.2 0.2" texuniform="true" reflectance="0.0"/>
|
||||||
|
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.4 0.5 0.6" rgb2="0 0 0" width="512" height="512"/>
|
||||||
|
</asset>
|
||||||
|
|
||||||
|
<default>
|
||||||
|
<geom density="500"/>
|
||||||
|
<joint damping="0.5"/>
|
||||||
|
<default class="wheel">
|
||||||
|
<geom type="cylinder" size="0.03 0.0125" density="1000" condim="3"/>
|
||||||
|
<joint damping="0.2"/>
|
||||||
|
</default>
|
||||||
|
<default class="steering">
|
||||||
|
<joint axis="0 0 1" damping="2" limited="true" range="-0.6 0.6"/>
|
||||||
|
<geom type="sphere" size="0.015" density="500" contype="0" conaffinity="0" rgba="0 0 0 0"/>
|
||||||
|
</default>
|
||||||
|
<default class="cone_blue">
|
||||||
|
<geom density="300" rgba="0.0 0.0 0.5 1"/>
|
||||||
|
</default>
|
||||||
|
</default>
|
||||||
|
|
||||||
|
<worldbody>
|
||||||
|
<light name="sun" pos="0 0 5" dir="0 0 -1" directional="true" castshadow="true"
|
||||||
|
diffuse="0.8 0.8 0.8" specular="0.2 0.2 0.2"/>
|
||||||
|
|
||||||
|
<!-- Checkerboard ground (infinite) -->
|
||||||
|
<geom name="floor" type="plane" size="0 0 0.01" material="checker_mat"
|
||||||
|
friction="0.6 0.1 0.1" condim="3"/>
|
||||||
|
|
||||||
|
<!-- 5m x 5m map tile, just above the ground -->
|
||||||
|
<geom name="map_tile" type="box" size="2.5 2.5 0.002" pos="0 0 0.002"
|
||||||
|
material="map_mat" friction="0.6 0.1 0.1" condim="3"/>
|
||||||
|
|
||||||
|
<!-- 40cm white fence around the map -->
|
||||||
|
<!-- ===== Blue cone obstacles ===== -->
|
||||||
|
<!-- Square base 20x20x3cm + cone taper 20cm→2cm over 27cm, total H=30cm -->
|
||||||
|
<!-- White reflective strip at 2/3 height (z=20cm) -->
|
||||||
|
<body name="cone_1" pos=" 1.0 1.0 0.0">
|
||||||
|
<geom type="box" size="0.10 0.10 0.015" pos="0 0 0.015" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_mesh" pos="0 0 0.03" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_white_mesh" pos="0 0 0.15" rgba="1 1 1 1"/>
|
||||||
|
</body>
|
||||||
|
<body name="cone_2" pos="-1.0 0.5 0.0">
|
||||||
|
<geom type="box" size="0.10 0.10 0.015" pos="0 0 0.015" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_mesh" pos="0 0 0.03" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_white_mesh" pos="0 0 0.15" rgba="1 1 1 1"/>
|
||||||
|
</body>
|
||||||
|
<body name="cone_3" pos=" 0.0 -1.5 0.0">
|
||||||
|
<geom type="box" size="0.10 0.10 0.015" pos="0 0 0.015" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_mesh" pos="0 0 0.03" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_white_mesh" pos="0 0 0.15" rgba="1 1 1 1"/>
|
||||||
|
</body>
|
||||||
|
<body name="cone_4" pos=" 1.5 -1.0 0.0">
|
||||||
|
<geom type="box" size="0.10 0.10 0.015" pos="0 0 0.015" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_mesh" pos="0 0 0.03" class="cone_blue"/>
|
||||||
|
<geom type="mesh" mesh="cone_white_mesh" pos="0 0 0.15" rgba="1 1 1 1"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<geom name="fence_n" type="box" size="2.5 0.02 0.2" pos="0 2.5 0.2" rgba="1 1 1 1"/>
|
||||||
|
<geom name="fence_s" type="box" size="2.5 0.02 0.2" pos="0 -2.5 0.2" rgba="1 1 1 1"/>
|
||||||
|
<geom name="fence_e" type="box" size="0.02 2.5 0.2" pos=" 2.5 0 0.2" rgba="1 1 1 1"/>
|
||||||
|
<geom name="fence_w" type="box" size="0.02 2.5 0.2" pos="-2.5 0 0.2" rgba="1 1 1 1"/>
|
||||||
|
|
||||||
|
<body name="base_link" pos="0 0 0.08">
|
||||||
|
<freejoint/>
|
||||||
|
|
||||||
|
<geom name="base_geom" type="box" size="0.138 0.082 0.04" pos="0 0 0.07"
|
||||||
|
rgba="0.4 0.039 0.039 1" contype="0" conaffinity="0"/>
|
||||||
|
|
||||||
|
<!-- Camera: look along +X, right=-Y, up=+Z -->
|
||||||
|
<camera name="front_cam" pos="0.1205 0 0.11" xyaxes="0 -1 0 0 0 1" fovy="60"/>
|
||||||
|
|
||||||
|
<body name="camera" pos="0.1205 0 0.11">
|
||||||
|
<geom name="camera_geom" type="box" size="0.0075 0.0225 0.015" pos="0 0 0.015"
|
||||||
|
rgba="0.365 0.306 0.306 1"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body name="board_link" pos="-0.038 0 0.11">
|
||||||
|
<geom name="board_geom" type="box" size="0.100 0.082 0.035" pos="0 0 0.035"
|
||||||
|
rgba="0.965 0.596 0.596 1"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<!-- ===== Rear wheels (drive only, no steering) ===== -->
|
||||||
|
<body name="down_left_Link" pos="-0.0841 0.0945 0.03">
|
||||||
|
<joint name="down_left_joint" axis="0 1 0"/>
|
||||||
|
<geom class="wheel" zaxis="0 1 0" rgba="0.745 0.129 0.129 1"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body name="down_right_Link" pos="-0.0841 -0.0945 0.03">
|
||||||
|
<joint name="down_right_joint" axis="0 -1 0"/>
|
||||||
|
<geom class="wheel" zaxis="0 -1 0" rgba="0.745 0.129 0.129 1"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<!-- ===== Front wheels (steer + drive) ===== -->
|
||||||
|
<body name="up_left_steer" pos="0.0841 0.0945 0.03">
|
||||||
|
<joint name="up_left_steer_joint" axis="0 0 1" limited="true" range="-0.6 0.6"/>
|
||||||
|
<geom class="steering"/>
|
||||||
|
<body name="up_left_Link">
|
||||||
|
<joint name="up_left_drive_joint" axis="0 1 0"/>
|
||||||
|
<geom class="wheel" zaxis="0 1 0" rgba="0.745 0.129 0.129 1"/>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body name="up_right_steer" pos="0.0841 -0.0945 0.03">
|
||||||
|
<joint name="up_right_steer_joint" axis="0 0 1" limited="true" range="-0.6 0.6"/>
|
||||||
|
<geom class="steering"/>
|
||||||
|
<body name="up_right_Link">
|
||||||
|
<joint name="up_right_drive_joint" axis="0 -1 0"/>
|
||||||
|
<geom class="wheel" zaxis="0 -1 0" rgba="0.745 0.129 0.129 1"/>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<actuator>
|
||||||
|
<!-- Drive motors (torque) for all 4 wheels -->
|
||||||
|
<motor name="down_left_drive" joint="down_left_joint" ctrlrange="-20 20"/>
|
||||||
|
<motor name="down_right_drive" joint="down_right_joint" ctrlrange="-20 20"/>
|
||||||
|
<motor name="up_left_drive" joint="up_left_drive_joint" ctrlrange="-20 20"/>
|
||||||
|
<motor name="up_right_drive" joint="up_right_drive_joint" ctrlrange="-20 20"/>
|
||||||
|
|
||||||
|
<!-- Steering position servos (kp/kv matched to car.py pattern) -->
|
||||||
|
<position name="up_left_steer" joint="up_left_steer_joint" ctrlrange="-0.6 0.6" kp="3000" kv="300"/>
|
||||||
|
<position name="up_right_steer" joint="up_right_steer_joint" ctrlrange="-0.6 0.6" kp="3000" kv="300"/>
|
||||||
|
</actuator>
|
||||||
|
</mujoco>
|
||||||
150
uv.lock
generated
Normal file
150
uv.lock
generated
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "absl-py"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7a/8f/fc001b92ecc467cc32ab38398bd0bfb45df46e7523bf33c2ad22a505f06e/absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff", size = 118055, upload-time = "2024-01-16T22:14:26.154Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/ad/e0d3c824784ff121c03cc031f944bc7e139a8f1870ffd2845cc2dd76f6c4/absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308", size = 133706, upload-time = "2024-01-16T22:14:24.055Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "motrixsim-core"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "absl-py" },
|
||||||
|
{ name = "numpy" },
|
||||||
|
]
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/fc/811c71d6053006ed6afb2a46fed61a6ca294cb9dc5d93bc99c55f05ceab9/motrixsim_core-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:57f37d36b6399b82cd06e88285529c056e487f063edbb4f697aaeb052456dabd", size = 47082098, upload-time = "2026-06-08T14:30:54.736Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/b6/3f0f9b85ea90d70f1ac0c82640c6ed59d83d11409723d909ba1c5a95934f/motrixsim_core-0.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0504de2c260380d40ed9393d699034a2cdaf7aff9cf6fe97d55f05b080f4bd0e", size = 54718509, upload-time = "2026-06-08T14:31:33.642Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/12/d8476ee4da47b5c54ac1625b7645830b9116dbc436a2650a8e727a5aa0d7/motrixsim_core-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf76189cbf1db814a66694a32653d8f7423ee072122f8f8f57da23243f2f695b", size = 52207612, upload-time = "2026-06-08T14:31:43.047Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/3e/f62c0c46cf89da0f174e39fb058ff9e71fa3dcd9ffb42b6d4c3923660700/motrixsim_core-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:e91340f961c71d989b34d6717b06a17c3f6a0b8930bc5d47e12a7e485cbd6903", size = 40402629, upload-time = "2026-06-08T14:30:26.842Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "motrixsim-examples"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { virtual = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "motrixsim-core" },
|
||||||
|
{ name = "pillow" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "motrixsim-core" },
|
||||||
|
{ name = "pillow" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numpy"
|
||||||
|
version = "2.4.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pillow"
|
||||||
|
version = "12.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" },
|
||||||
|
]
|
||||||
BIN
智能车地图源文件.avif
Normal file
BIN
智能车地图源文件.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Reference in New Issue
Block a user