Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:05:02 +08:00
commit 265175ed82
23 changed files with 3329 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
# Camera Frustums in Robotics Visualization
## Overview
Camera frustums are essential for visualizing camera viewpoints in robotics applications. Vuer allows you to programmatically insert camera frustums into the scene to represent camera positions and orientations.
## Basic Frustum
```python
from vuer import Vuer
from vuer.schemas import Scene, Frustum, DefaultScene
import asyncio
app = Vuer()
@app.spawn(start=True)
async def main(session):
session.set @ Scene(
DefaultScene(),
Frustum(
position=[0, 1, 2],
rotation=[0, 0, 0],
scale=[1, 1, 1],
showImagePlane=True,
showFrustum=True,
showFocalPlane=True,
key="camera-frustum",
),
)
while True:
await asyncio.sleep(1.0)
app.run()
```
## Frustum Configuration Options
### showImagePlane
Display the image plane (where the image is captured).
### showFrustum
Show the frustum wireframe (pyramid shape representing the camera's field of view).
### showFocalPlane
Display the focal plane (plane at the focal length).
### Position and Orientation
- **position**: `[x, y, z]` coordinates
- **rotation**: Euler angles `[x, y, z]` in radians
- **scale**: `[x, y, z]` scale factors
## Stress Test Example: 1,728 Frustums
The tutorial demonstrates a stress-test implementation with a large grid of frustums:
```python
from vuer import Vuer, VuerSession
from vuer.schemas import Scene, Frustum, DefaultScene
import asyncio
app = Vuer()
@app.spawn(start=True)
async def main(session: VuerSession):
frustums = []
# Create 12×12×12 grid of frustums
for x in range(12):
for y in range(12):
for z in range(12):
frustums.append(
Frustum(
position=[x * 2, y * 2, z * 2],
scale=[0.5, 0.5, 0.5],
showImagePlane=True,
showFrustum=True,
showFocalPlane=False,
key=f"frustum-{x}-{y}-{z}",
)
)
session.set @ Scene(
DefaultScene(),
*frustums, # Unpack all frustums into the scene
)
while True:
await asyncio.sleep(1.0)
app.run()
```
This creates **1,728 frustum objects** (12³), demonstrating the framework's capability to handle large numbers of camera visualization objects simultaneously.
## Practical Use Case: Multi-Camera Robot
```python
from vuer import Vuer
from vuer.schemas import Scene, Frustum, Urdf, DefaultScene
import asyncio
app = Vuer()
@app.spawn(start=True)
async def main(session):
session.set @ Scene(
DefaultScene(),
# Robot model
Urdf(
src="/static/robot.urdf",
position=[0, 0, 0],
key="robot",
),
# Front camera
Frustum(
position=[0.5, 0.5, 0],
rotation=[0, 0, 0],
scale=[0.3, 0.3, 0.3],
showImagePlane=True,
showFrustum=True,
key="front-camera",
),
# Left camera
Frustum(
position=[0, 0.5, 0.5],
rotation=[0, -1.57, 0],
scale=[0.3, 0.3, 0.3],
showImagePlane=True,
showFrustum=True,
key="left-camera",
),
# Right camera
Frustum(
position=[0, 0.5, -0.5],
rotation=[0, 1.57, 0],
scale=[0.3, 0.3, 0.3],
showImagePlane=True,
showFrustum=True,
key="right-camera",
),
)
while True:
await asyncio.sleep(1.0)
app.run()
```
## Dynamic Frustum Updates
You can update frustum positions in real-time:
```python
import math
@app.spawn(start=True)
async def main(session):
session.set @ Scene(DefaultScene())
for i in range(1000):
# Orbit the frustum around the origin
x = 3 * math.cos(i * 0.05)
z = 3 * math.sin(i * 0.05)
rotation_y = i * 0.05
session.upsert @ Frustum(
position=[x, 1, z],
rotation=[0, rotation_y, 0],
showImagePlane=True,
showFrustum=True,
key="orbiting-camera",
)
await asyncio.sleep(0.033) # ~30 FPS
app.run()
```
## Performance Considerations
The stress test with 1,728 frustums demonstrates that Vuer can handle:
- Large numbers of visualization objects
- Complex geometric primitives
- Real-time rendering of camera representations
This makes it practical for robotics applications requiring:
- Multi-camera system visualization
- SLAM trajectory visualization
- Sensor fusion displays
- Camera calibration tools
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/robotics/frustums.html

View File

@@ -0,0 +1,181 @@
# Unitree Go1 Robot with Stairs
## Overview
This tutorial demonstrates setting up a 3D scene containing a Unitree Go1 quadruped robot positioned in front of a staircase, along with lighting and atmospheric effects.
## Scene Components
The visualization includes four main elements:
1. **Unitree Go1 Robot** - A quadrupedal robot model loaded via URDF format
2. **Stairway Mesh** - A textured 3D model of stairs
3. **Fog Effect** - Atmospheric fog that darkens distant portions of the scene
4. **Lighting** - An ambient light source plus two movable point lights
## Complete Code Example
```python
import math
import asyncio
from vuer import Vuer
from vuer.schemas import Scene, Urdf, Obj, AmbientLight, PointLight, Movable, Plane, Fog
app = Vuer()
@app.spawn(start=True)
async def main(session):
# Setup scene with fog and lighting
session.set @ Scene(
# Add fog effect
Fog(
color="#000000",
near=1,
far=20,
),
# Ground plane
Plane(
args=[100, 100],
position=[0, -0.01, 0],
rotation=[-1.57, 0, 0],
key="ground",
),
# Staircase mesh
Obj(
src="/static/stairs/stairs.obj",
position=[2, 0, 0],
rotation=[0, 0, 0],
materialType="standard",
material={
"color": "#cccccc",
"roughness": 0.8,
},
key="stairs",
),
# Ambient lighting
AmbientLight(intensity=1.0),
# Movable point lights
Movable(
PointLight(
intensity=3.0,
position=[2, 3, 2],
key="light-1",
)
),
Movable(
PointLight(
intensity=3.0,
position=[-2, 3, -2],
key="light-2",
)
),
)
# Animation loop for the robot
for i in range(10000):
# Calculate joint angles using sinusoidal functions
hip_angle = 0.3 * math.sin(i * 0.1)
thigh_angle = 0.785 - 0.25 * math.sin(i * 0.1)
calf_angle = -1.5 + 0.5 * math.sin(i * 0.1)
# Update robot position and joints
session.upsert @ Urdf(
src="/static/go1/go1.urdf",
position=[0, 0, 0.33],
rotation=[0, 0, 0],
jointValues={
# Front Left
"FL_hip_joint": hip_angle,
"FL_thigh_joint": thigh_angle,
"FL_calf_joint": calf_angle,
# Front Right
"FR_hip_joint": -hip_angle,
"FR_thigh_joint": thigh_angle,
"FR_calf_joint": calf_angle,
# Rear Left
"RL_hip_joint": -hip_angle,
"RL_thigh_joint": thigh_angle,
"RL_calf_joint": calf_angle,
# Rear Right
"RR_hip_joint": hip_angle,
"RR_thigh_joint": thigh_angle,
"RR_calf_joint": calf_angle,
},
key="go1-robot",
)
# Update at ~60 FPS
await asyncio.sleep(0.016)
app.run()
```
## Key Features
### Fog Effect
Creates atmospheric depth:
```python
Fog(
color="#000000", # Black fog
near=1, # Fog starts at distance 1
far=20, # Full fog at distance 20
)
```
### Ground Plane
A large plane rotated to be horizontal:
```python
Plane(
args=[100, 100], # 100x100 units
position=[0, -0.01, 0], # Slightly below origin
rotation=[-1.57, 0, 0], # Rotated 90° (π/2)
)
```
### Staircase Mesh
3D model with material properties:
```python
Obj(
src="/static/stairs/stairs.obj",
materialType="standard",
material={
"color": "#cccccc",
"roughness": 0.8,
},
)
```
## Robot Animation
The application updates continuously at approximately 60 frames per second, calculating joint values like:
```python
thigh_angle = 0.785 - 0.25 * math.sin(i * 0.1)
```
This creates realistic walking motion across the stair scene.
## Leg Coordination
The Go1 has a specific gait pattern:
- Front Left and Rear Right move together (same hip angle)
- Front Right and Rear Left move together (opposite hip angle)
This creates a natural trotting gait.
## Assets Required
Make sure you have the following assets:
- `go1.urdf` - Robot description file
- `stairs.obj` - Staircase 3D model
- Associated mesh files for the Go1 robot
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/robotics/urdf_go1_stairs.html

View File

@@ -0,0 +1,148 @@
# MIT Mini Cheetah URDF Tutorial
## Overview
This tutorial demonstrates serving a URDF (Unified Robot Description Format) file locally to visualize the MIT Mini Cheetah robot in Vuer with animated leg movements.
## Directory Structure
Set up your assets directory:
```
assets/mini_cheetah/
├── meshes/
│ ├── mini_abad.obj
│ ├── mini_body.obj
│ ├── mini_lower_link.obj
│ └── mini_upper_link.obj
└── mini_cheetah.urdf
```
## Download Assets
Use wget to fetch the URDF and mesh files:
```bash
mkdir -p assets/mini_cheetah/meshes
cd assets/mini_cheetah
# Download URDF file
wget https://raw.githubusercontent.com/vuer-ai/vuer/main/assets/mini_cheetah/mini_cheetah.urdf
# Download mesh files
cd meshes
wget https://raw.githubusercontent.com/vuer-ai/vuer/main/assets/mini_cheetah/meshes/mini_abad.obj
wget https://raw.githubusercontent.com/vuer-ai/vuer/main/assets/mini_cheetah/meshes/mini_body.obj
wget https://raw.githubusercontent.com/vuer-ai/vuer/main/assets/mini_cheetah/meshes/mini_lower_link.obj
wget https://raw.githubusercontent.com/vuer-ai/vuer/main/assets/mini_cheetah/meshes/mini_upper_link.obj
```
## Complete Code Example
```python
import math
import asyncio
from vuer import Vuer
from vuer.schemas import Scene, Urdf, AmbientLight, Movable, PointLight
# Configure app to serve static files from assets directory
app = Vuer(static_root="assets/mini_cheetah")
@app.spawn(start=True)
async def main(session):
# Setup scene with lighting
session.set @ Scene(
AmbientLight(intensity=0.8),
Movable(
PointLight(
intensity=2.0,
position=[1, 2, 1],
key="point-light-1",
)
),
Movable(
PointLight(
intensity=2.0,
position=[-1, 2, -1],
key="point-light-2",
)
),
)
# Animation loop
for i in range(1000):
# Calculate joint angles using sine waves
hip_angle = 0.5 * math.sin(i * 0.1)
thigh_angle = 0.785 - 0.25 * math.sin(i * 0.1)
calf_angle = -1.5 + 0.5 * math.sin(i * 0.1)
# Update robot with animated joints
session.upsert @ Urdf(
src="/static/mini_cheetah.urdf",
position=[0, 0, 0],
rotation=[0, 0, 0],
jointValues={
# Front Left leg
"FL_hip_joint": hip_angle,
"FL_thigh_joint": thigh_angle,
"FL_calf_joint": calf_angle,
# Front Right leg
"FR_hip_joint": -hip_angle,
"FR_thigh_joint": thigh_angle,
"FR_calf_joint": calf_angle,
# Rear Left leg
"RL_hip_joint": hip_angle,
"RL_thigh_joint": thigh_angle,
"RL_calf_joint": calf_angle,
# Rear Right leg
"RR_hip_joint": -hip_angle,
"RR_thigh_joint": thigh_angle,
"RR_calf_joint": calf_angle,
},
key="mini-cheetah",
)
# Update at ~60 FPS
await asyncio.sleep(0.016)
app.run()
```
## Joint Control
The Mini Cheetah has 12 joints (3 per leg):
- **Hip joint**: Abduction/adduction (side-to-side movement)
- **Thigh joint**: Hip flexion/extension (forward/backward)
- **Calf joint**: Knee flexion/extension
## Animation Details
The example creates a walking motion using sinusoidal functions:
```python
hip_angle = 0.5 * math.sin(i * 0.1)
thigh_angle = 0.785 - 0.25 * math.sin(i * 0.1)
calf_angle = -1.5 + 0.5 * math.sin(i * 0.1)
```
## Expected Result
When executed correctly, the tutorial produces a 3D visualization of the Mini Cheetah robot with animated leg movements displayed in a web interface at `http://localhost:8012`.
## Troubleshooting
### Robot not appearing
- Verify all mesh files are downloaded
- Check that `static_root` points to the correct directory
- Ensure URDF file references correct mesh paths
### Animation not smooth
- Adjust the sleep interval (currently 0.016s for ~60 FPS)
- Reduce animation speed by changing the multiplier in `i * 0.1`
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/robotics/urdf_mini_cheetah.html

View File

@@ -0,0 +1,134 @@
# Using URDF Files in Vuer
## Overview
Vuer enables loading URDF (Unified Robot Description Format) files for robotics visualization. The framework supports mesh files in `.dae`, `.stl`, `.obj`, and `.ply` formats.
## Basic Implementation
The code example demonstrates loading URDF models:
```python
from asyncio import sleep
from vuer import Vuer, VuerSession
from vuer.schemas import Urdf
app = Vuer()
@app.spawn(start=True)
async def main(proxy: VuerSession):
proxy.upsert @ Urdf(
src="https://docs.vuer.ai/en/latest/_static/perseverance/rover/m2020.urdf",
jointValues={},
rotation=[3.14 / 2, 0, 0],
position=[0, 0, -1.5],
key="perseverance",
)
# Keep the session alive
while True:
await sleep(1.0)
app.run()
```
## Key Parameters
### src
URL path to the URDF file. Can be a local path or remote URL.
### jointValues
Dictionary for joint configuration. Use empty `{}` for default joint positions.
Example with joint values:
```python
jointValues={
"joint_1": 0.5,
"joint_2": -0.3,
"knee_joint": 1.2,
}
```
### rotation
Euler angles `[x, y, z]` for model orientation in radians.
### position
3D coordinates `[x, y, z]` for model placement.
### key
Unique identifier for the model. Used for updates and removal.
## Supported Mesh Formats
Vuer supports URDF files with mesh files in the following formats:
- `.dae` (COLLADA)
- `.stl` (STereoLithography)
- `.obj` (Wavefront OBJ)
- `.ply` (Polygon File Format)
## Complete Example with Multiple Robots
```python
from asyncio import sleep
from vuer import Vuer, VuerSession
from vuer.schemas import Urdf, Scene, AmbientLight
app = Vuer()
@app.spawn(start=True)
async def main(session: VuerSession):
session.set @ Scene(
# Add lighting
AmbientLight(intensity=1.0),
# Load first robot
Urdf(
src="/static/robots/robot1.urdf",
position=[0, 0, 0],
rotation=[0, 0, 0],
key="robot-1",
),
# Load second robot
Urdf(
src="/static/robots/robot2.urdf",
position=[2, 0, 0],
rotation=[0, 0, 0],
key="robot-2",
),
)
# Keep the session alive
while True:
await sleep(1.0)
app.run()
```
## Serving Local URDF Files
To serve URDF files from your local filesystem:
```python
from vuer import Vuer
# Point to the directory containing your URDF files
app = Vuer(static_root="path/to/urdf/directory")
@app.spawn(start=True)
async def main(session):
session.upsert @ Urdf(
src="/static/my_robot.urdf", # Relative to static_root
position=[0, 0, 0],
key="my-robot",
)
while True:
await sleep(1.0)
app.run()
```
## Source
Documentation: https://docs.vuer.ai/en/latest/tutorials/robotics/urdf.html