Skip to content

Commit d52b7ac

Browse files
authored
Merge pull request #14 from Zeroth-Robotics/revert-12-runtime2
Revert "Runtime2"
2 parents 86f57ea + 3b8c357 commit d52b7ac

37 files changed

+8288
-109
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ logs/
5151

5252
# artifacts
5353
artifacts/
54-
# Model artifacts directories in models/
55-
models/*_artifacts/
5654

5755
# gitlab-ci-local
5856
.gitlab-ci-local/

.gitlab-ci-local/.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

.gitmodules

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
[submodule "runtime/firmware/duo-sdk"]
88
path = runtime/firmware/duo-sdk
99
url = https://github.com/milkv-duo/duo-sdk.git
10-
[submodule "models/tpu-mlir"]
11-
path = models/tpu-mlir
12-
url = https://github.com/milkv-duo/tpu-mlir.git
10+
[submodule "runtime/models/tpu-mlir"]
11+
path = runtime/models/tpu-mlir
12+
url = https://github.com/milkv-duo/tpu-mlir

models/ppo_standing.pt

-1.85 MB
Binary file not shown.

models/ppo_walking.pt

-1.85 MB
Binary file not shown.

runtime/.cargo/config.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ rustflags = [
66
"-L", "./firmware/sts3215",
77
"-L", "./firmware/tpu-sdk-sg200x/lib",
88
"-L", "./firmware/duo-sdk/rootfs/usr/lib",
9-
"-L", "./models/tpu-mlir/lib",
10-
"-Clink-arg=-Wl,-rpath,../models/tpu-mlir/lib",
11-
"-Clink-arg=-Wl,-rpath,./firmware/tpu-sdk-sg200x/lib",
12-
"-Clink-arg=-Wl,-rpath,./firmware/duo-sdk/rootfs/lib",
139
"-Clink-arg=-Wl,-rpath,./tpu-libs",
1410
"-Clink-arg=-Wl,-rpath,./sysroot/lib",
1511
"-Clink-arg=-Wl,-rpath,./sysroot/usr/lib",

runtime/README.md

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,22 @@ If you're connecting via USB, use the following details:
3636
SSH:
3737
3838

39-
4. Build Runtime
40-
```bash
41-
cargo check && gitlab-ci-local # check and build
42-
```
39+
4. Download Required Artifacts
40+
Go to OpenLCH Artifacts and download the following:
41+
`runtime`
42+
`servo`
43+
`cviwrapper`
4344

44-
5. Transfer Files to the Target Device
45-
Find binaries in target/riscv64gc-unknown-linux-musl/release/
46-
47-
`scp -O target/riscv64gc-unknown-linux-musl/release/runtime $MILKV_IP:/usr/local/bin/`
45+
6. Transfer Files to the Target Device
46+
Run the following commands to copy the necessary files to your device:
4847

49-
Debug:
50-
Note that you cannot ping the device in Cursor editor terminal for some reason. Try:
5148
```bash
52-
ping 192.168.42.1
53-
```
49+
scp -O runtime [email protected]:/usr/local/bin/
50+
scp -O servo [email protected]:/usr/local/bin/
51+
scp -O cviwrapper [email protected]:/usr/local/bin/
52+
5453

54+
```
5555
6. Run the Application
5656
To run the servo setup, execute the following on the target device:
5757

@@ -61,12 +61,27 @@ To run the servo setup, execute the following on the target device:
6161
ls /usr/local/bin/
6262

6363
# Run your desired binary (example: runtime)
64-
/usr/local/bin/runtime
64+
sudo /usr/local/bin/runtime
65+
```
66+
67+
68+
69+
70+
```
71+
# Install docker / docker desktop
72+
brew install gitlab-ci-local
6573
```
6674

75+
### Build
6776

77+
```bash
78+
gitlab-ci-local --stage build-runtime
79+
```
6880

81+
Find binaries in target/riscv64gc-unknown-linux-musl/release/
6982

83+
### Copy to the milk-v board
84+
`scp -O target/riscv64gc-unknown-linux-musl/release/runtime $MILKV_IP:/usr/local/bin/`
7085

7186
If the board is connected over usb, ip is `192.168.42.1`
7287

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import json
2+
import numpy as np
3+
4+
# Define the number of servos
5+
NUM_SERVOS = 12
6+
7+
# Static movement states with positions and transition times
8+
raw_movements = {
9+
"move_forward": [
10+
{"pos": [867, 91, 225, 903, 330, 769, 250, 387, 587, 197, 210, 562, 569], "trans_time": 600},
11+
{"pos": [868, 91, 225, 1004, 330, 769, 250, 387, 587, 199, 151, 562, 570], "trans_time": 600},
12+
{"pos": [867, 91, 225, 1001, 329, 769, 250, 387, 587, 225, 299, 560, 569], "trans_time": 600},
13+
{"pos": [867, 91, 225, 1019, 330, 766, 250, 386, 587, 211, 143, 562, 569], "trans_time": 600},
14+
{"pos": [867, 92, 225, 837, 328, 766, 250, 387, 586, 210, 144, 562, 569], "trans_time": 600},
15+
{"pos": [867, 91, 225, 955, 328, 769, 250, 387, 587, 210, 82, 561, 569], "trans_time": 600},
16+
{"pos": [867, 91, 225, 956, 328, 769, 250, 387, 587, 213, 250, 562, 569], "trans_time": 600},
17+
{"pos": [867, 91, 225, 1037, 331, 767, 250, 387, 587, 210, 158, 562, 569], "trans_time": 600},
18+
{"pos": [867, 91, 225, 865, 329, 768, 250, 387, 587, 210, 159, 562, 569], "trans_time": 600},
19+
{"pos": [867, 91, 225, 946, 329, 768, 250, 387, 587, 211, 78, 561, 569], "trans_time": 600},
20+
{"pos": [867, 91, 225, 948, 328, 769, 250, 387, 587, 213, 234, 562, 569], "trans_time": 600},
21+
{"pos": [867, 91, 225, 1016, 329, 768, 250, 387, 587, 210, 150, 562, 569], "trans_time": 600},
22+
{"pos": [867, 91, 225, 857, 330, 767, 250, 387, 587, 210, 151, 562, 569], "trans_time": 600},
23+
],
24+
"zero": [
25+
{"pos": [865, 92, 228, 895, 514, 628, 249, 385, 586, 338, 195, 387, 570], "trans_time": 600},
26+
{"pos": [865, 92, 228, 895, 514, 628, 249, 385, 586, 338, 195, 387, 570], "trans_time": 600}
27+
28+
],
29+
"bounce": [
30+
{"pos": [867, 90, 225, 895, 510, 625, 247, 386, 587, 341, 195, 391, 570], "trans_time": 600},
31+
{"pos": [867, 91, 225, 887, 374, 751, 247, 387, 587, 210, 187, 544, 570], "trans_time": 600},
32+
],
33+
# "dabbing": [
34+
35+
# # {"pos": [668, 64, -160, 907, -11, 20, 446, 432, 99, -31, 962, -1, 3], "trans_time": 300},
36+
# # {"pos": [668, 64, -160, 907, -11, 20, 446, 431, 99, -31, 961, -1, 112], "trans_time": 300},
37+
# # {"pos": [668, 64, -160, 907, -11, 20, 446, 431, 99, -31, 960, -1, 300], "trans_time": 300},
38+
39+
# {"pos": [668, 64, -160, 907, -11, 20, 446, 432, 99, -31, 962, -1, 3], "trans_time": 300},
40+
# {"pos": [619, 254, 1193, 907, 2, 20, 446, 483, 100, -10, 960, -1, 0], "trans_time": 300},
41+
# {"pos": [668, 64, -160, 907, -11, 20, 446, 432, 99, -31, 962, -1, 3], "trans_time": 300},
42+
43+
44+
45+
# {"pos": [1081, 147, -83, 907, 126, -19, 82, 393, 166, 44, 959, 0, 0], "trans_time": 300},
46+
# {"pos": [1081, 147, -83, 907, 216, -188, 82, 394, 166, 199, 960, -194, 0], "trans_time": 300},
47+
# {"pos": [896, 59, -194, 857, 342, 1194, 240, 394, 165, 288, 921, 1193, 0], "trans_time": 300},
48+
49+
# ],
50+
}
51+
52+
def interpolate_positions(start, end, steps):
53+
"""Interpolate between start and end positions over the given number of steps."""
54+
return np.linspace(start, end, steps).tolist()
55+
56+
# Generate the fully interpolated movements
57+
movements = {}
58+
59+
for movement_name, movement_data in raw_movements.items():
60+
interpolated_movement = []
61+
for i in range(len(movement_data)):
62+
start_pos = np.array(movement_data[i]["pos"])
63+
transition_time = movement_data[i]["trans_time"]
64+
steps = max(1, int(transition_time / 50)) # Calculate the number of 50ms steps
65+
end_pos = np.array(movement_data[(i + 1) % len(movement_data)]["pos"]) # Next position
66+
67+
# Interpolate between the current position and the next
68+
interpolated_positions = interpolate_positions(start_pos, end_pos, steps)
69+
70+
# Append the interpolated positions to the movement list
71+
interpolated_movement.extend(interpolated_positions)
72+
73+
movements[movement_name] = interpolated_movement
74+
75+
# Save the movements to a JSON file
76+
with open('movements.json', 'w') as f:
77+
json.dump(movements, f, indent=4)
78+
79+
print("Interpolated movements array saved to movements.json")
80+

runtime/firmware/lx16_control/main.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import pygame
2+
import asyncio
3+
import websockets
4+
import json
5+
import time
6+
7+
import sys, time
8+
9+
from ..servo_driver.hiwonder_lsbc_v16 import ServoController
10+
11+
# import serial
12+
# import lewansoul_lx16a
13+
14+
# SERIAL_PORT = '/dev/cu.usbserial-110'
15+
16+
ctrl = ServoController(vid=0x0483, pid=0x5750)
17+
global prev_movement
18+
prev_movement = None
19+
# Initialize Pygame
20+
pygame.init()
21+
22+
# WebSocket server URI
23+
# Load the pre-generated movement arrays from the JSON file
24+
with open('movements.json', 'r') as f:
25+
movements = json.load(f)
26+
27+
# Active movement state key
28+
current_movement = None
29+
30+
# Circular buffer to manage movement states
31+
movement_buffer = []
32+
current_step = 0
33+
34+
# Time tracking for transitions
35+
last_transition_time = 0
36+
transition_interval = 0.05 # 50ms
37+
38+
# Function to handle state transitions
39+
async def handle_transitions(websocket):
40+
global current_step, last_transition_time
41+
42+
# Check the current time
43+
current_time = time.time()
44+
elapsed_time = current_time - last_transition_time
45+
46+
if elapsed_time >= transition_interval:
47+
if current_movement:
48+
# Get the current position from the buffer
49+
servo_states = movement_buffer[current_step]
50+
message = json.dumps({"servo_states": servo_states})
51+
52+
for n, val in enumerate(servo_states):
53+
ctrl.move_servos([(n + 1, int(val))], 20)
54+
# ctrl.move(n + 1, val, 20)
55+
56+
# await websocket.send(message)
57+
58+
# Move to the next step
59+
current_step = (current_step + 1) % len(movement_buffer)
60+
61+
# Update the last transition time
62+
last_transition_time = current_time
63+
64+
# Function to set the current movement and prepare the buffer
65+
def set_movement(movement_name):
66+
global current_movement, movement_buffer, current_step, last_transition_time, prev_movement
67+
if movement_name in movements and current_movement != movement_name:
68+
current_movement = movement_name
69+
movement_buffer = movements[movement_name]
70+
if prev_movement != current_movement:
71+
current_step = 0
72+
prev_movement = current_movement
73+
last_transition_time = time.time() # Reset the timer
74+
print(f"Transitioning to movement: {movement_name}")
75+
76+
# Function to stop the current movement
77+
def stop_movement():
78+
global current_movement
79+
current_movement = None
80+
print("Stopped movement")
81+
82+
# Main function to run the websocket client
83+
async def main():
84+
# Set up a simple Pygame window (required to capture events)
85+
screen = pygame.display.set_mode((640, 480))
86+
pygame.display.set_caption('Servo Movement Controller')
87+
88+
# Connect to the WebSocket server
89+
# async with websockets.connect(WEBSOCKET_URI) as websocket:
90+
91+
running = True
92+
while running:
93+
for event in pygame.event.get():
94+
if event.type == pygame.QUIT:
95+
running = False
96+
elif event.type == pygame.KEYDOWN:
97+
if event.key == pygame.K_w: # Move forward on 'W' key press
98+
set_movement("move_forward")
99+
elif event.key == pygame.K_a: # Move left on 'A' key press
100+
set_movement("move_left")
101+
elif event.key == pygame.K_d: # Move left on 'A' key press
102+
set_movement("dabbing")
103+
elif event.key == pygame.K_z: # Move left on 'A' key press
104+
set_movement("zero")
105+
elif event.key == pygame.K_q: # Quit on 'Q' key press
106+
running = False
107+
elif event.type == pygame.KEYUP:
108+
if event.key in [pygame.K_w, pygame.K_a, pygame.K_d, pygame.K_z]:
109+
stop_movement()
110+
111+
# Call handle_transitions every 50ms if a movement is active
112+
await handle_transitions(None)
113+
114+
# Allow other events to be processed
115+
await asyncio.sleep(0) # Yield control to the event loop
116+
117+
pygame.quit()
118+
119+
# Run the main function
120+
asyncio.run(main())
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.16)
4+
5+
# (Not part of the boilerplate)
6+
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
7+
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
8+
9+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
10+
project(ws_echo_server)

0 commit comments

Comments
 (0)