Skip to content

Commit 6f4124a

Browse files
authored
Merge pull request #67 from OpenSourceEcology/copilot/update-github-actions-render
Fix cnclayout.scad path and separate rendering workflows
2 parents 9843d07 + d778c02 commit 6f4124a

File tree

4 files changed

+455
-117
lines changed

4 files changed

+455
-117
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
name: Generate Animation GIF
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
paths:
7+
- 'LifeTrac-v25/mechanical_design/openscad/lifetrac_v25.scad'
8+
- 'LifeTrac-v25/mechanical_design/openscad/**/*.scad'
9+
pull_request:
10+
branches: [ main, master ]
11+
paths:
12+
- 'LifeTrac-v25/mechanical_design/openscad/lifetrac_v25.scad'
13+
- 'LifeTrac-v25/mechanical_design/openscad/**/*.scad'
14+
workflow_dispatch:
15+
16+
jobs:
17+
generate-animation-gif:
18+
runs-on: ubuntu-latest
19+
20+
permissions:
21+
contents: write
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
token: ${{ secrets.GITHUB_TOKEN }}
27+
ref: ${{ github.head_ref || github.ref_name }}
28+
fetch-depth: 0
29+
30+
- name: Install OpenSCAD and ImageMagick
31+
run: |
32+
sudo apt-get update
33+
sudo apt-get install -y openscad xvfb x11-utils imagemagick
34+
openscad --version
35+
36+
- name: Start Xvfb
37+
run: |
38+
Xvfb :99 -screen 0 1024x768x16 &
39+
XVFB_PID=$!
40+
echo "XVFB_PID=$XVFB_PID" >> $GITHUB_ENV
41+
42+
# Wait for Xvfb to be ready (max 10 seconds)
43+
for i in {1..10}; do
44+
if xdpyinfo -display :99 >/dev/null 2>&1; then
45+
echo "Xvfb is ready on display :99"
46+
break
47+
fi
48+
if [ $i -eq 10 ]; then
49+
echo "Timeout waiting for Xvfb to start"
50+
exit 1
51+
fi
52+
sleep 1
53+
done
54+
55+
echo "DISPLAY=:99" >> $GITHUB_ENV
56+
57+
- name: Calculate camera position
58+
run: |
59+
cd LifeTrac-v25/mechanical_design
60+
61+
# Calculate camera position dynamically based on machine dimensions
62+
# Extract parameters from OpenSCAD file
63+
MACHINE_HEIGHT=$(grep -E "^MACHINE_HEIGHT = " openscad/lifetrac_v25.scad | grep -oE "[0-9]+\.?[0-9]*" || echo "1000")
64+
WHEEL_BASE=$(grep -E "^WHEEL_BASE = " openscad/lifetrac_v25.scad | grep -oE "[0-9]+\.?[0-9]*" || echo "1400")
65+
GROUND_CLEARANCE=$(grep -E "^GROUND_CLEARANCE = " openscad/lifetrac_v25.scad | grep -oE "[0-9]+\.?[0-9]*" || echo "150")
66+
ARM_MAX_ANGLE=$(grep -E "^ARM_MAX_ANGLE = " openscad/lifetrac_v25.scad | grep -oE "[0-9]+\.?[0-9]*" || echo "60")
67+
BUCKET_HEIGHT=$(grep -E "^BUCKET_HEIGHT = " openscad/lifetrac_v25.scad | grep -oE "[0-9]+\.?[0-9]*" || echo "450")
68+
69+
# Validate all extracted parameters
70+
if [ -z "$MACHINE_HEIGHT" ] || [ -z "$WHEEL_BASE" ] || [ -z "$GROUND_CLEARANCE" ] || [ -z "$ARM_MAX_ANGLE" ] || [ -z "$BUCKET_HEIGHT" ]; then
71+
echo "ERROR: Failed to extract required parameters from OpenSCAD file"
72+
echo " MACHINE_HEIGHT: $MACHINE_HEIGHT"
73+
echo " WHEEL_BASE: $WHEEL_BASE"
74+
echo " GROUND_CLEARANCE: $GROUND_CLEARANCE"
75+
echo " ARM_MAX_ANGLE: $ARM_MAX_ANGLE"
76+
echo " BUCKET_HEIGHT: $BUCKET_HEIGHT"
77+
exit 1
78+
fi
79+
80+
# Calculate key dimensions
81+
FRAME_Z_OFFSET=$GROUND_CLEARANCE
82+
ARM_PIVOT_Z=$((FRAME_Z_OFFSET + MACHINE_HEIGHT - 50))
83+
WHEEL_MIDPOINT_Y=$((WHEEL_BASE / 2))
84+
85+
# Calculate maximum height when arms are raised to ARM_MAX_ANGLE
86+
ARM_LENGTH_APPROX=1600
87+
88+
# Max height = ARM_PIVOT_Z + ARM_LENGTH * sin(ARM_MAX_ANGLE) + BUCKET_HEIGHT
89+
MAX_ARM_TIP_HEIGHT=$(awk "BEGIN {pi=3.14159; print int($ARM_PIVOT_Z + $ARM_LENGTH_APPROX * sin($ARM_MAX_ANGLE * pi / 180) + $BUCKET_HEIGHT)}")
90+
91+
# Calculate camera position to frame the scene properly
92+
SCENE_HEIGHT=$MAX_ARM_TIP_HEIGHT
93+
MARGIN_FACTOR="1.75"
94+
95+
# Center point: halfway between ground and max height, at wheel midpoint Y
96+
CENTER_Y=$WHEEL_MIDPOINT_Y
97+
CENTER_Z=$(awk "BEGIN {print int($SCENE_HEIGHT / 2)}")
98+
99+
# Camera distance
100+
CAMERA_DISTANCE=$(awk "BEGIN {print int($SCENE_HEIGHT * $MARGIN_FACTOR * 1.414)}")
101+
102+
echo "=== Camera Calculation ==="
103+
echo "Camera position: --camera=$CAMERA_DISTANCE,$CAMERA_DISTANCE,$CAMERA_DISTANCE,0,$CENTER_Y,$CENTER_Z"
104+
echo "=========================="
105+
106+
# Export calculated values as environment variables for subsequent steps
107+
echo "CAMERA_DISTANCE=$CAMERA_DISTANCE" >> $GITHUB_ENV
108+
echo "CENTER_Y=$CENTER_Y" >> $GITHUB_ENV
109+
echo "CENTER_Z=$CENTER_Z" >> $GITHUB_ENV
110+
111+
- name: Create output directories
112+
run: |
113+
cd LifeTrac-v25/mechanical_design
114+
mkdir -p output/animations/frames
115+
116+
- name: Generate animation frames
117+
run: |
118+
cd LifeTrac-v25/mechanical_design
119+
120+
# Use camera parameters calculated in previous step (from environment variables)
121+
echo "Generating animation frames with calculated camera position..."
122+
echo "Camera: $CAMERA_DISTANCE,$CAMERA_DISTANCE,$CAMERA_DISTANCE,0,$CENTER_Y,$CENTER_Z"
123+
124+
# Generate 36 frames for animation (every 10 degrees)
125+
# Using dynamically calculated camera position that adapts to machine dimensions
126+
total_frames=36
127+
for i in $(seq 0 $((total_frames-1))); do
128+
# Use total_frames-1 so last frame lands exactly at t=1.0
129+
t=$(awk "BEGIN {print $i/($total_frames-1)}")
130+
printf "Frame %d (t=%.4f)\n" "$i" "$t"
131+
openscad -o "output/animations/frames/frame_$(printf %03d $i).png" \
132+
--camera=$CAMERA_DISTANCE,$CAMERA_DISTANCE,$CAMERA_DISTANCE,0,$CENTER_Y,$CENTER_Z \
133+
--imgsize=720,720 \
134+
--projection=p \
135+
--colorscheme=Nature \
136+
-D "animation_time=$t" \
137+
-D "\$t=$t" \
138+
openscad/lifetrac_v25.scad
139+
done
140+
141+
echo "Animation frames generated"
142+
143+
- name: Create animation GIF
144+
run: |
145+
cd LifeTrac-v25/mechanical_design/output/animations
146+
147+
echo "Creating animation GIF of arm movement..."
148+
convert -delay 10 -loop 0 frames/frame_*.png lifetrac_v25_animation.gif
149+
150+
# Copy to parent directory for easy access
151+
cp lifetrac_v25_animation.gif ../../lifetrac_v25_animation.gif
152+
153+
echo "✓ Animation GIF created successfully"
154+
ls -lh ../../lifetrac_v25_animation.gif
155+
156+
- name: Upload animation artifacts
157+
uses: actions/upload-artifact@v4
158+
with:
159+
name: openscad-animation
160+
path: |
161+
LifeTrac-v25/mechanical_design/output/animations/
162+
LifeTrac-v25/mechanical_design/lifetrac_v25_animation.gif
163+
retention-days: 90
164+
165+
- name: Commit and push animation GIF
166+
run: |
167+
cd LifeTrac-v25/mechanical_design
168+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
169+
git config --global user.name "github-actions[bot]"
170+
git add lifetrac_v25_animation.gif || true
171+
172+
if git diff --staged --quiet; then
173+
echo "ℹ️ No changes to commit"
174+
else
175+
echo "📝 Committing changes..."
176+
git commit -m "Update animation GIF [skip ci]"
177+
178+
# Fetch and rebase to incorporate any remote changes
179+
BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
180+
echo "🔄 Fetching latest changes from branch: ${BRANCH_NAME}..."
181+
if git fetch origin "${BRANCH_NAME}"; then
182+
echo "🔄 Rebasing on latest changes..."
183+
if ! git rebase "origin/${BRANCH_NAME}"; then
184+
echo "❌ Failed to rebase. There may be conflicts."
185+
echo "Aborting rebase and exiting..."
186+
git rebase --abort
187+
exit 1
188+
fi
189+
else
190+
echo "⚠️ Could not fetch branch ${BRANCH_NAME} from origin. This may be a PR from a fork. Skipping fetch/rebase."
191+
fi
192+
193+
echo "📤 Pushing changes with --force-with-lease..."
194+
if git push --force-with-lease; then
195+
echo "✅ Changes pushed successfully"
196+
else
197+
echo "⚠️ Push failed. This is expected for PRs from forks or if you do not have write permissions."
198+
echo "The files are available as workflow artifacts."
199+
fi
200+
fi
201+
202+
- name: Cleanup Xvfb
203+
if: always()
204+
run: |
205+
if [ -n "$XVFB_PID" ]; then
206+
echo "Stopping Xvfb process (PID: $XVFB_PID)"
207+
# Try graceful shutdown first
208+
kill -TERM $XVFB_PID 2>/dev/null || true
209+
# Wait up to 5 seconds for process to terminate
210+
for i in {1..5}; do
211+
if ! kill -0 $XVFB_PID 2>/dev/null; then
212+
echo "Xvfb stopped gracefully"
213+
break
214+
fi
215+
sleep 1
216+
done
217+
# Force kill if still running
218+
kill -KILL $XVFB_PID 2>/dev/null || true
219+
echo "Xvfb force stopped"
220+
fi

0 commit comments

Comments
 (0)