Skip to the content
PCBKitNew board
2 layers35 × 15.9 mmUWB adaptor, the printed circuit board in 3D

Bachelor Thesis Paper: Sparse Pose Estimation data collection, evaluation backend, frontend, as well as all resources for the creation of the Hidden Dataset using commodity sensors.

Size
35 × 15.9 mm
Copper layers
2
Thickness
1.6 mm
Parts
14
Nets
43
Pads
125
Tracks, vias
203, 62
Pours
5
Routed
Yes
KiCad
KiCad 7 (file 20221018)
Created
3 Jan 2026
Updated
3 Apr 2026

Overview

UWB adaptor is an open-source printed circuit board by bastocon, from the bastocon/sparse-pose-benchmark repository on GitHub, published under the MIT licence. It is a 2-layer board of 35 × 15.9 mm with 14 parts on 43 nets, routed with 203 tracks and 62 vias.

It is built around the DWM1000 and MIC5216-3.3YM5-TR. Its parts include 4 resistors, 4 connectors, 3 capacitors, 1 IC and 1 diode. It belongs with the radio and wireless boards of this library.

Main components

2

README

README.md

Bachelor Thesis

Benchmarking Deep Learning-Based Pose Estimation from Sparse IMUs

Source description

These are the interesting subdirectories:

/data

Insert needed datasets here. It could be, that this folder needs to be created first.

text
data
├── smplx_models
│   └── smpl
│       └── SMPL_FEMALE.npz
│       └── ...
├── AMASS
│   └── ACCAD
│       └── ...
├── ...

/src/experimental

Contains all evaluated methods, and under /pip also the evaluate.py and preprocess.py used for the benchmark.

/src/platform

Contains the code for the platform, seperated in /frontend and /backend.

The server is located in /src/platform/backend/src/index.ts, and the default submissions directory in /src/platform/backend/submissions.

/src/tracking

Each subdirectory has its own README's.

  • /uwb_wearables/recording/processing. uwb_wearables in general contains all the code for hardware and firmware of the commodity sensors. The recording/processing directory in particular contains the code to process the raw uwb.csv and imu.csv, including the orientation estimator.
  • /processing contains all the post-processing. It also contains info.csv and shape.csv if you need the cut intervals, beta shape parameters or similar.
  • VirtualCaliper is the program used to generate the SMPL shape parameters.

Execution Environments

Docker for backend evaluation

Do one of these things:

  1. Setup or rebuild: docker-compose build

  2. To create a non-persistent session to execute the evaluation: docker-compose run --rm --remove-orphans pip-env

  3. Optional: If you want to be sure, that it builds correctly after changes, do: docker-compose build --no-cache

Docker for Visualization with aitviewer

Same as for the backend, but use vis-env. e.g. docker-compose run --rm --remove-orphans vis-env. Note that the visualizer.py files need to be run with xvfb-run -s "-screen 0 1280x720x24" python path/to/visualizer.py, as the docker does not has access to the display.

Conda/Micromamba

We have the following environments: uip, pip-env, mocap. You can find them under

  • /pip_env.yml. Please refer to /pip_env_README.md and worst case /docker/pip-env/Dockerfile in the comments for an installation guide. The setup for rbdl was not easy. Works with python 3.7.
  • /mocap_env.yml
  • /src/experimental/UIP/environment.yml. As this python version differs, rbdl might has to be re-build. Works with python 3.8.17.

Execution of Benchmark and Methods

Running evaluation of Benchmark

Use pip-env. Be in project root. These scripts automatically evaluate all .pt files named as the datasets that are in a folder. You always have to provide the path of the folder and not the files for this evaluation.

Preparation:

  • Have the predictions ready, and files named uip_db.pt, totalcapture.pt, amass.pt, gip_person1.pt, gip_perspn2.pt, hidden.pt in folder/ - no substructure.
  • Have the files config.json (optional but recommended), submission_info.json (really optional, used for the display of information on the website).

Example config.json:

text
{
    "eval_tran": true
}

Run the evaluation of the benchmark:

bash
python ./src/experimental/pip/evaluate.py eval --path <path_to_folder>

If you also run GIP (as its predicted as two single person), or want to re-evaluate the overall scores, additionally do this to calculate the overall scores.

bash
python ./src/experimental/pip/evaluate.py overall --path <path_to_folder>

The result will be in folder/evaluation.json. The first part shows the results per dataset per sequence, and the last rows ("overall") have the final results. More details can be found in the Additional Information section.

For clearity: An example file structure

text
/.../submissions/1_PIP
    ├── amass.py
    ├── totalcapture.pt
    ├── ...
    ├── config.json
    ├── submission_info.json

Tip: If you only want to test things and run different versions, create an archive folder inside your actual evaluation folder. As the backend only searches for the exact files in the top level, they are not evaluated. E.g. folder/totalcapture.pt will be evauated, but folder/archive/totalcapture.pt will not.

Running PIP method

Uses environment "pip-env".

Go into project root. Preprocess:

bash
python src/experimental/pip/preprocess.py

Evaluating PIP on a method:

bash
python src/experimental/pip/evaluate.py predict --dataset <dataset>

with dataset in [hidden, totalcapture, uip_db, amass, gip_person1, gip_person2]

Get the output in a unified format. It creates an output file in the project root that has to be moved where desired.

bash
python src/experimental/utils/change_pt_file.py correct_pip_output <path-to-results-file.pt>

Running UIP method

Use environment "uip" from src/experimental/UIP/environment.yml file, I used python 3.8.17. Go into /src/experimental/UIP

For preprocessing:

bash
python modules/dataset/preprocess.py

For evaluating UIP on a dataset:

bash
python modules/evaluate/evaluator.py --network UIP\
                    --ckpt_path data/processed/UIP/pretrained.pt\
                    --data_dir data/processed/UIP/ground_truth_datasets/HiddenDataset\
                    --eval_trans\
                    --normalize_uwb\
                    --add_guassian_noise\
                    --model_args_file config/model_args.json\
                    --eval_save_dir data/processed/UIP/evaluation_res/HiddenDataset

To change the UIP output from the per-sequence based file to one file for benchmark evaluation:

bash
python src/experimental/utils/change_pt_file.py correct_uip_output <path/to/uip-output-folder> <path/to/gt-file-for-betas-gender>

# Or specifically (notice that UIP creates folders with spaces, do not forget the "")
python src/experimental/utils/change_pt_file.py correct_uip_output "/local/home/**/data/processed/UIP/result/HiddenDataset/Ultra Inertial Poser" /local/home/**/data/processed/ground_truth_datasets/hidden_test_gt.pt

This produces an output, that has to be renamed and put into one submission folder for evaluation.

Check out the official UIP GitHub README for open questions.

Running PNP method

Use pip-env environment, same as in PIP method.

For a pleasant experience, start in project root. Comment the datasets you want to use in the process.py before execution. Preprocessing

bash
python src/experimental/PNP/process.py

Prediction: Comment in/out the datasets you want to run in test.py before execution.

bash
cd src/experimental/PNP
python test.py

Get the output in a unified format. It creates an output file in the project root that has to be moved where desired.

bash
python src/experimental/utils/change_pt_file.py correct_pnp_output <path-to-results-file.pt>

Utility Functions

Visualize

To visualize a sequence, and/or ground truth to it, use this:

bash
python ./tracking/processing/vis.py --input <gt-file.pt> --output <prediction.pt> --seq 1 --second-input <gip-person2.pt> --origin
  • All args are optional
  • --input expects a ground truth file, specifically a file in which there is pose of shape [N, T, 24, 3].
  • --output expects a prediction file, specifically a file which has keys 0, ..., N-1 and where each i has a pose of shape [T, 24, 3].
  • --seq The sequence ID to show
  • --second-input same as --input, but especially useful for visualization of a second person like in GIP-DB.
  • --origin to reset origin in x and z axis (no height).

Platform

Can be found in /src/platform, seperated into frontend and backend.

To test it:

bash
cd /src/platform/frontend
ng serve
bash
cd /src/platform/backend
npm run dev

Additional information

Evaluation Metrics Schema

This is the template for the evaluation.json file, generated for each method. All of the following values can be null/nan.

{ sequence_metrics: { [dataset: string]: { [sequenceId: number]: { frames: number, tran_win_count: number, angle_mean: number, angle_std: number, sip_mean: number, sip_std: number, joint_pos_mean: number, joint_pos_std: number, jitter_mean: number, jitter_std: number, abs_jitter_mean: number, abs_jitter_std: number, drift_mean: number, drift_std: number, foot_pen_mean: number, foot_pen_std: number, foot_sliding_mean: number, mpjve_mean: number, mpjve_std: number, trans_2m_mean: number, trans_5m_mean: number, }, ... } }, overall: { [dataset: string]: { frames: number, angle: number, sip: number, joint_pos: number, jitter: number, abs_jitter: number, drift: number, foot_pen: number, foot_sliding: number, mpjve: number, trans_2m: number, trans_5m: number, }, ... } }

Submission Info (saved on disk)

This is generaetd for each method from the server and optional, it defines the public information for each submission.

{ shortName: string, version: string, fullName: string, pubTitle: string, pubAuthors: string, pubVenue: string, pubUrl: string, description: string, hardware: string, parameters: string, availability: string, availabilityUrl: string, status: string, contactEmail: string }

License and Acknowledgement

This project is released under the MIT license. Our code is partially based on PIP.

Hidden Dataset

Recorded at SIP Lab, Computer Science Department, ETH Zurich, Switzerland.

General Information

The sequences are numbered AA01, AA02, AA03 where AA is the subject identifier. Not all subjects have all three sequences.

File Structure

Main directory

In the main directory are the test.pt and train.pt, which contain the dataset with the synthetic magnetometer variant. This is the default version of this dataset. pose is stored in axis angle format. Note that tran does not start at origin to ensure compatibility for the camera feed.

test.pt has the following keys:

python
acc, ori, betas, gender, vuwb, offset (= None)

train.pt has the following keys:

python
acc, ori, betas, gender, vuwb, offset (= None), pose, tran

Videos

This directory contains all the videos for each subject. Note that not the subject (TM**) does not have videos, and for some sequences only 3 of 4 cameras worked. The subfolders are front, back, left, right indicating from where you usually see the person from. As most participants looked at the instructor, front is the default viewing direction for most people, the other directions are derived from that. The videos are pre-cut, but you have to do the exact frame-synchronization.

Extras

In the Extras folder, one can find additional versions of the dataset, with more data access for advanced processing. It contains test_no-mag.pt and train_no-mag with the same test and train data and keys, but where the orientation estimation is done without magnetometer readings. This leads to a significantly higher orientation error and more difficulty to estimate pose from.

It also contains the sequences with the following raw data. We recommend checking out the code and how it was generated, before using them. Wo = World frame of OptiTrack, so in which it was recorded. Wx= World frame of Xsens, where the pose originates. vis = Visualization/export frame (Y-up), this is the system in which everything like pose is exported by default if nothing is mentioned otherwise. Check out the paper "Benchmarking Deep Learning-Based Pose Estimation" for a more detailed definition of the coordinate systems etc.

python
"pose": to_numpy(pose_vis),  # (N, 72)
"pose_wo": to_numpy(pose_wo),  # (N, 72) in wo frame
"pose_unoptimized_vis": to_numpy(archive_pose_vis),  # (N, 72) in vis frame, but no optimization"
"pose_raw_xsensframe": to_numpy(data1["poses"][begin_idx:end_idx+1]),  # (N, 72) in Xsens frame

"tran": to_numpy(tran_vis),  # (N, 3), Optitrack Translation in vis frame
"tran_wo": to_numpy(tran_wo),  # (N, 3), Optitrack Translation in wo frame
"tran_unoptimized_vis": to_numpy(archive_tran_vis),  # (N, 3) OptiTrack translation in vis frame, but no optimization
"tran_raw_xsensframe": to_numpy(data1["trans"][begin_idx:end_idx+1]),  # (N, 3) in Xsens frame

# sensor readings
"rot":  to_numpy(rot_vis),            # (N, S, 3, 3) rotmat
"rot_wo":  to_numpy(rot_wo),            # (N, S, 3, 3) rotmat in wo frame
"acc":  to_numpy(acc_vis),            # (N, S, 3)
"acc_wo":  to_numpy(acc_wo),            # (N, S, 3) in wo frame
"acc_sensor":  to_numpy(acc_sensor),            # (N, S, 3) sensor frame acc
"acc_gtrotated": to_numpy(acc_vis_opt),  # (N, S, 3) # acc rotated with optitrack rot to remove sensor drift
"uwb":  to_numpy(uwb),               # (N, S, S), sensor UWB, frame independant

# OptiTrack ground truth
'opt_rot': to_numpy(opt_rot_vis),     # (N, S, 3, 3) rotmat
'opt_rot_wo': to_numpy(opt_rot_wo),     # (N, S, 3, 3) rotmat in wo frame
'opt_rot_wo_raw': to_numpy(archive_opt_rot_wo),     # (N, S, 3, 3) rotmat in wo frame, but no filtering
'opt_acc': to_numpy(opt_acc),        # (N, S, 3)

Parts

14
QtyValueFootprintReferences
210kResistor_SMD:R_0402_1005MetricR1, R2
21uFCapacitor_SMD:C_0402_1005MetricC1, C2
2538850208siplab:Molex_SlimStack_53885-0208_2x10_P0.50mm_VerticalJ5, J6
2541020204siplab:Molex_SlimStack_54102-0204_2x10_P0.50mm_VerticalJ4, J7
1100kResistor_SMD:R_0402_1005MetricR3
1100nFCapacitor_SMD:C_0402_1005MetricC3
13kResistor_SMD:R_0402_1005MetricR4
1DWM1000RF_Module:DWM1000DWM1
1MIC5216-3.3YM5Package_TO_SOT_SMD:SOT-23-5U1
1REDLED_SMD:LED_0603_1608MetricD1

Questions

How big is the UWB adaptor PCB?

It measures 35 × 15.9 mm and has 2 copper layers, 1.6 mm thick.

What parts does the UWB adaptor use?

14 parts, built around the DWM1000 and MIC5216-3.3YM5-TR. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the UWB adaptor KiCad files?

From the bastocon/sparse-pose-benchmark repository on GitHub, at the commit this page was made from: the board is src/tracking/uwb_wearables/hardware/UWB_adaptor/UWB_adaptor.kicad_pcb and its schematic src/tracking/uwb_wearables/hardware/UWB_adaptor/UWB_adaptor.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the UWB adaptor design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

More from bastocon/sparse-pose-benchmark

1
  • 4 layers35 × 30.4 mmSiplab wristband, the printed circuit board in 3D

    Siplab wristband

    bastocon/sparse-pose-benchmark

    Bachelor Thesis Paper: Sparse Pose Estimation data collection, evaluation backend, frontend, as well as all resources for the creation of the Hidden Dataset using commodity sensors.

    67 partsMIT

Similar boards

  • 2 layers65 × 56.5 mmPitail, the printed circuit board in 3D

    Pitail

    mcb30/dw1000

    DecaWave DW1000 Linux kernel driver

    372 parts19
  • 2 layers115 × 115 mmDrone, the printed circuit board in 3D

    Drone

    rmingon/drone-uwb

    Drone design for automatic position in space with UWB

    49 parts13
  • 2 layers40.1 × 70.1 mmESP32-DWM1000-local, the printed circuit board in 3D

    ESP32-DWM1000-local

    jh247247/DW1000-fan-video

    Using UWB to make an indoor location system, to get a fan to point at me.

    53 parts3
  • 2 layers50.8 × 22.9 mmFeather UWB, the printed circuit board in 3D

    Feather UWB

    ProfFan/MagicLoc-DWM3000

    22 parts2
  • 2 layers45 × 45 mmUWB module, the printed circuit board in 3D

    UWB module

    repowered-electronics/UWB_Module_Hardware

    Hardware files for our DWM1000 based localization module

    50 parts2
  • 2 layers24.5 × 25 mmDWM1000 Breakout, the printed circuit board in 3D

    DWM1000 Breakout

    JEB12345/DWM100_Breakout

    A Breakout board to mount a DWM1000 module onto SUPERball's XBee WiFi slot on the Sensor Board

    18 parts1Apache-2.0
  • 4 layers26.5 × 57.4 mmMotorDriver, the printed circuit board in 3D

    MotorDriver

    Kmshanley/MiniRobots

    Firmware and PCB desgin for mini robots with UWB localization and lidar mapping

    50 parts1
  • 2 layers38.8 × 29.5 mmDwm1000, the printed circuit board in 3D

    Dwm1000

    winocc/DecaWiNo-board

    This is the git repository of the DecaWiNo board

    19 parts1