← Back to portfolio

Time-Series ML · Sensor Data · Web Bluetooth

Shot Gyro

A PlayStation 5 DualSense controller repurposed as a 6-axis IMU sensor for shooting-sports motion analysis — a webapp collects gyro/accelerometer data over Web HID, Label Studio annotates the shot phases, and change-point detection segments the signal.

  • Web HID
  • Time-Series
  • DualSense
  • Label Studio
  • ruptures
  • pandas
  • plotly
Shot Gyro — cover image

A games controller strapped to a shooter’s hand becomes a motion-capture rig. Shot Gyro turns a PlayStation 5 DualSense — which carries a 6-axis IMU — into a data-collection instrument for shooting-sports technique analysis. A browser app streams the gyro and accelerometer at ~125 Hz, the recordings are hand-annotated by shot phase in Label Studio, and a change-point detection pipeline segments the raw signal into individual shots.

The idea

Quantify a shooter’s motion without a lab.

A pistol shot is a short, repeatable sequence: rest, lift to the target, aiming, the shot break, and follow-through. Every phase leaves a fingerprint in the inertial signal — the lift is a slow angular sweep, the aim is a high-frequency tremor that settles, the shot break is a sharp impulse, and the follow-through is the recoil decay. If you can capture that signal cheaply and label the phases, you can start to measure, compare and coach technique.

The DualSense controller is an off-the-shelf IMU platform: a 3-axis gyroscope and 3-axis accelerometer streaming over Bluetooth HID at roughly 125 Hz, with no firmware to write and no driver to install — the browser talks to it directly. The work splits into three layers:

  1. Collect — a Web HID app connects to the controller, parses the HID input reports into physical units, visualizes the live signal on uPlot charts, and exports timestamped CSV.
  2. Label — the CSV is loaded into Label Studio, where each recording is hand-annotated across five shot phases over all six sensor channels.
  3. Analyse — a Jupyter notebook loads the labelled data, visualizes it with Plotly, and runs ruptures change-point detection to segment the gyro signal into individual shots automatically.

System architecture

The diagram shows the full path: the DualSense’s HID input reports flow through the Web HID app into CSV files, which Label Studio annotates and the analysis notebook segments with change-point detection.

flowchart LR DS["DualSense controller
6-axis IMU
gyro + accel · ~125 Hz"] subgraph web["Web HID app (browser)"] HID["navigator.hid
requestDevice + open"] PARSE["HID report parser
int16 → deg/s & m/s²"] CHART["uPlot live charts
gyro + accel"] CSV["CSV export
timestamp + 6 axes"] end subgraph ls["Label Studio"] ANN["TimeSeries annotation
Rest · Lift · Aiming · Shot · Follow"] end subgraph nb["Analysis notebook"] PD["pandas
resample · interpolate"] PL["Plotly
signal visualization"] RPT["ruptures Dynp (l2)
change-point detection"] end DS -->|"Bluetooth HID
input report 0x01"| HID HID --> PARSE PARSE --> CHART PARSE --> CSV CSV --> ANN ANN --> PD PD --> PL PD --> RPT

1. Data collection (webapp)

The collector is a single-page web app that talks to the DualSense directly through the Web HID API — no native driver, no Bluetooth stack configuration, just a browser (Chrome/Edge) and a paired controller.

The Shot Gyro web app showing live gyroscope and accelerometer charts streaming from a connected DualSense controller
The web app streaming live gyro and accelerometer data from a connected DualSense controller, with current values and CSV export.

The DualSense as a sensor

The controller contains a 6-axis IMU exposed through its standard HID input report (report ID 0x01):

  • Gyroscope — 3-axis angular velocity in degrees/second (raw int16 ÷ 1024).
  • Accelerometer — 3-axis acceleration in m/s² (raw int16, scaled by 8192 res/g × standard gravity).

The app requests the device with navigator.hid.requestDevice() filtered to the Sony vendor ID (0x054C) and the DualSense product ID (0x0CE6) — with DS4, DualSense Edge and PSVR2 controllers also accepted — opens the HID interface, and subscribes to inputreport events.

HID report parsing

Each input report is a DataView over a 74-byte buffer. The motion data sits at fixed offsets:

  • Gyroscope X/Y/Z — int16 little-endian at offsets 16/18/20, divided by 10.
  • Accelerometer X/Y/Z — int16 little-endian at offsets 22/24/26, converted through the accelerometer resolution (8192 counts per g) to m/s².

The parser also sends output reports back to the controller — a 77-byte Bluetooth output report with CRC32 checksum, sequence numbering and the 0x10 report type — to initialize the controller into a known state (lightbar colour, motor off) on connect.

Live visualization

Two uPlot charts render the gyro (pitch/yaw/roll) and accelerometer (X/Y/Z) in real time. The app uses pre-allocated 5000-point ring buffers with a slice/concat update pattern and batches redraws through requestAnimationFrame, so it keeps up with the ~125 Hz report rate without dropping frames.

CSV export

Every sample is stored with an ISO-8601 timestamp (millisecond precision) and exported as:

timestamp,gyro_x,gyro_y,gyro_z,accel_x,accel_y,accel_z
2026-03-27T17:41:12.345Z,0.12,-0.05,0.08,...

Recordings are named with the shot count and context (dualsense_motion_2026-03-27T1741_10_skott.csv) so the dataset is self-documenting.

2. Annotation (Label Studio)

The collected CSVs are loaded into Label Studio as time-series tasks. The annotation config (labelstudio/annotation_setup.xml) defines five labels mapped to the phases of a shot cycle, each painted directly onto the six sensor channels:

Label Meaning
Rest Controller stationary, shooter not in position
Lift Raising the pistol toward the target
Aiming Settling on target, fine angular corrections
Shot The trigger break and recoil impulse
Follow Follow-through, recoil decay and hold
Label Studio time-series annotation view showing gyro and accelerometer channels with hand-painted phase labels across a shooting sequence
Label Studio time-series view — the six sensor channels with hand-annotated shot-phase segments painted across a recording.

Each of the six channels (gyro_x/y/z, accel_x/y/z) is rendered with its own stroke colour, and the annotator brushes the phase labels over the regions of interest — producing a supervised segmentation ground truth that the analysis pipeline can be evaluated against.

3. Analysis (notebook)

notebooks/shot_analysis.ipynb is where the raw recordings are cleaned, visualized and segmented:

  • Load & resamplepandas reads the CSV, parses the timestamp index, resamples to a uniform 1 ms grid and interpolates. The DualSense reports arrive at ~1 ms but with duplicate timestamps, so resampling is what makes the signal analysable.
  • Visualize — Plotly line charts of the gyro and accel axes, both full-range and zoomed to the shooting window, plus a differenced view to highlight impulse events like the shot break.
  • Change-point detectionruptures with the Dynp (dynamic programming) search and an l2 cost model segments the gyro-Y signal into n_bkps pieces. Each detected breakpoint corresponds to a transition between shot phases, giving an automatic segmentation that can be compared against the hand-labelled ground truth.

The dataset

The recordings live in data/sensor_data/ and cover multiple sessions, shooter contexts and shot counts — from single-shot calibration recordings to 10-shot series with multiple lifts. Files are named with the session timestamp and a shot/condition suffix (e.g. _5_skott, _10shots_3raises, _4thdrag) so the collection context is preserved alongside the data.

Technologies used

Data collection

  • Web HID API (navigator.hid)
  • DualSense 6-axis IMU (gyro + accel)
  • Bluetooth HID input/output reports
  • CRC32 checksummed output reports
  • Single-file HTML + vanilla JS

Visualization

  • uPlot (high-performance charts)
  • requestAnimationFrame batching
  • Ring-buffer data structure
  • Plotly (notebook exploration)

Annotation

  • Label Studio (TimeSeries template)
  • Five-phase shot taxonomy
  • Per-channel stroke colours
  • Brush-based region labelling

Analysis

  • pandas (resample, interpolate)
  • ruptures (Dynp, l2 change-point)
  • Plotly Express
  • Jupyter / itables
  • uv (package management)

Status: the Web HID collector streams live DualSense IMU data and exports CSV, Label Studio annotations mark the five shot phases across a growing dataset of recordings, and the notebook's change-point pipeline segments the gyro signal automatically. Active work is on extending the segmentation into a supervised phase classifier trained on the labelled data.