systems.builtin.deterministic.continuous.SymbolicQuadrotor2DLidar

systems.builtin.deterministic.continuous.SymbolicQuadrotor2DLidar(
    *args,
    **kwargs,
)

Symbolic representation of a planar (2D) quadrotor with lidar-based partial observations.

Models a quadrotor constrained to move in the y-z plane with dynamics derived from first principles. The system has 4 states (vertical position, pitch angle, and their derivatives) and 2 control inputs (thrust from each rotor). Unlike full-state feedback, this system uses a lidar sensor that measures distances to the ground at 4 different angles, providing partial observability that requires state estimation (e.g., Kalman filtering) for control. This implementation uses symbolic computation via SymPy to enable automatic Jacobian derivation for neural Lyapunov control synthesis.

Based on the Stanford ASL neural-network-lyapunov quadrotor2d example: https://github.com/StanfordASL/neural-network-lyapunov/blob/master/neural_network_lyapunov/examples/quadrotor2d/quadrotor_2d.py

State Vector (nx=4): - y: vertical position [m] - theta: pitch angle [rad] - y_dot: vertical velocity [m/s] - theta_dot: angular velocity [rad/s]

Control Inputs (nu=2): - u1: thrust from rotor 1 [N] - u2: thrust from rotor 2 [N]

Output Vector (ny=4): - Lidar ray distances at 4 different angles [m] - Measured from quadrotor to ground, ranging from [0, H] - Angles span from theta - angle_max to theta + angle_max

Dynamics: The system is second-order, so forward() returns accelerations: - dy_dot = (1/m) * cos(theta) * (u1 + u2) - g - b * y_dot - dtheta_dot = (L/I) * (u1 - u2) - b * theta_dot

where b is an optional damping coefficient (default: 0).

Observation Model: Lidar rays measure distance to ground at different angles: - phi_i = theta - angle_offset_i - ray_i = (y + origin_height) / cos(phi_i) - Clamped to [0, H] and masked when out of valid range

Equilibrium: - State: [0, 0, 0, 0] (hovering at origin) - Control: [mg/2, mg/2] (equal thrust counteracting gravity) - Output: Lidar readings at equilibrium depend on ray angles. Center rays measure approximately origin_height, while angled rays measure slightly longer distances (e.g., ~1.12m for rays at ±26.8° when origin_height=1.0)

Parameters: length: Distance from center of mass to rotor [m]. Default: 0.25 mass: Total quadrotor mass [kg]. Default: 0.486 inertia: Moment of inertia about pitch axis [kg⋅m²]. Default: 0.00383 gravity: Gravitational acceleration [m/s²]. Default: 9.81 b: Damping coefficient for both translational and angular velocities. Default: 0.0 H: Maximum lidar range [m]. Default: 5.0 angle_max: Maximum angle offset for lidar rays [rad]. Default: 0.149π origin_height: Height offset added to vertical position [m]. Default: 1.0

Note: This symbolic implementation is compatible with the hardcoded Quadrotor2DLidarDynamics class when using matching parameters. The observation function h(x) uses smooth approximations (via tanh and smooth_clamp) instead of hard thresholding to maintain differentiability for automatic Jacobian computation.