UNPKG

dualsense-ts

Version:

The natural interface for your DualSense and DualSense Access controllers, with Typescript

106 lines 4.47 kB
"use strict"; /** * High-level orientation tracker for the DualSense controller. * * Wraps the Madgwick AHRS filter and provides: * - Fused orientation as Euler angles and quaternion * - Accelerometer-only tilt (no drift, no yaw — useful for * gravity-reference applications like steering) * - Automatic unit conversion from the library's [-1, 1] calibrated * values to the rad/s and g units the filter expects * * DualSense IMU hardware constants: * Gyroscope: ±2000 deg/s full scale → 1.0 = 2000 deg/s * Accelerometer: ±4 g full scale → 0.25 ≈ 1 g */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Orientation = void 0; const madgwick_1 = require("./madgwick"); const quaternion_1 = require("./quaternion"); /** * Convert our [-1, 1] calibrated gyro value to rad/s. * Full scale is ±2000 deg/s = ±34.9066 rad/s. */ const GYRO_SCALE = 2000 * (Math.PI / 180); // ≈ 34.9066 class Orientation { // ---- Configuration ---- /** Madgwick filter gain. Can be adjusted at runtime. */ get beta() { return this.filter.beta; } set beta(v) { this.filter.beta = v; } constructor(params) { // ---- Public state (read these in your game loop) ---- /** Fused orientation as Euler angles (radians, updated each sample). */ this.pitch = 0; this.yaw = 0; this.roll = 0; /** Fused orientation as a unit quaternion [w, x, y, z]. */ this.quaternion = [...quaternion_1.IDENTITY]; /** * Tilt derived from the accelerometer gravity vector alone. * No drift, but also no yaw — only pitch and roll. * Noisy during motion; best used when the controller is relatively still. */ this.tiltPitch = 0; this.tiltRoll = 0; this.filter = new madgwick_1.MadgwickFilter(params?.beta ?? 0.1); } /** Reset to identity orientation (call when zeroing the view). */ reset() { this.filter.reset(); this.pitch = 0; this.yaw = 0; this.roll = 0; this.quaternion = [...quaternion_1.IDENTITY]; this.tiltPitch = 0; this.tiltRoll = 0; } /** * Incorporate one IMU sample. Called automatically by the Dualsense * class on each HID report — you don't normally call this yourself. * * @param gx Calibrated gyro X (pitch), [-1, 1] * @param gy Calibrated gyro Y (yaw), [-1, 1] * @param gz Calibrated gyro Z (roll), [-1, 1] * @param ax Calibrated accel X, [-1, 1] * @param ay Calibrated accel Y, [-1, 1] * @param az Calibrated accel Z, [-1, 1] * @param dt Time delta in seconds */ update(gx, gy, gz, ax, ay, az, dt) { // Remap DualSense axes to Madgwick's Z-up convention. // DualSense: X = right, Y = up (gravity), Z = forward // Madgwick: X = right, Y = forward, Z = up (gravity) // Mapping: filter(X, Y, Z) = DS(X, -Z, Y) this.filter.update(gx * GYRO_SCALE, // filter X = DS X (pitch axis) -gz * GYRO_SCALE, // filter Y = -DS Z (negated forward) gy * GYRO_SCALE, // filter Z = DS Y (gravity axis → up) ax, // accel X unchanged -az, // accel Y = -DS Z ay, // accel Z = DS Y (gravity) dt); // Extract Euler angles and remap back to DualSense frame this.quaternion = this.filter.q; const euler = (0, quaternion_1.toEuler)(this.quaternion); this.pitch = euler.pitch; // filter X rotation → DS pitch (forward/back) this.yaw = euler.roll; // filter Z rotation → DS yaw (left/right turn) this.roll = -euler.yaw; // filter Y rotation → DS roll (side tilt, negated) // Accelerometer-only tilt (gravity reference) // DualSense axes: X = lateral, Y = vertical (up at rest), Z = forward // Pitch = forward/back tilt (around X): gravity shifts from Y toward Z // Roll = side-to-side tilt (around Z): gravity shifts from Y toward X const aNorm = Math.sqrt(ax * ax + ay * ay + az * az); if (aNorm > 0) { const nax = ax / aNorm; const nay = ay / aNorm; const naz = az / aNorm; this.tiltPitch = Math.atan2(-naz, nay); this.tiltRoll = Math.atan2(nax, Math.sqrt(nay * nay + naz * naz)); } } } exports.Orientation = Orientation; //# sourceMappingURL=orientation.js.map