{"id":24701634,"url":"https://github.com/jonnor/toothbrush","last_synced_at":"2026-05-21T05:08:05.238Z","repository":{"id":270857447,"uuid":"911665657","full_name":"jonnor/toothbrush","owner":"jonnor","description":"Toothbrush tracker/timer using accelerometer and machine learning","archived":false,"fork":false,"pushed_at":"2025-02-08T23:56:41.000Z","size":21631,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-19T04:17:40.454Z","etag":null,"topics":["digital-signal-processing","embedded","embedded-machine-learning","emlearn","esp32","human-activity-recognition","machine-learning","microcontroller","tinyml"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonnor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["jonnor"]}},"created_at":"2025-01-03T14:58:01.000Z","updated_at":"2025-02-08T23:56:44.000Z","dependencies_parsed_at":"2025-02-10T00:01:29.860Z","dependency_job_id":null,"html_url":"https://github.com/jonnor/toothbrush","commit_stats":null,"previous_names":["jonnor/toothbrush"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonnor%2Ftoothbrush","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonnor%2Ftoothbrush/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonnor%2Ftoothbrush/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonnor%2Ftoothbrush/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonnor","download_url":"https://codeload.github.com/jonnor/toothbrush/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244902927,"owners_count":20529115,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["digital-signal-processing","embedded","embedded-machine-learning","emlearn","esp32","human-activity-recognition","machine-learning","microcontroller","tinyml"],"created_at":"2025-01-27T05:24:59.680Z","updated_at":"2026-05-21T05:08:05.232Z","avatar_url":"https://github.com/jonnor.png","language":"Jupyter Notebook","funding_links":["https://github.com/sponsors/jonnor"],"categories":[],"sub_categories":[],"readme":"\n# Automatic toothbrush timer\n\nThis toothbrush timer tracks how long you spend on actively brushing your teeth.\nIt uses an accelerometer to measure motion, and analyzes it using a simple machine learning model.\nThe device helps you get to the 2 minute mark, which is the recommend duration!\n\nThis is a demo project for [emlearn-micropython](https://github.com/emlearn/emlearn-micropython),\na library efficient Machine Learning and Digital Signal Processing for [MicroPython](https://micropython.org/).\nThe intent is to be a fun and simple, but realistic application, of machine learning on microcontrollers,\nin the area of Human Activity Recognition.\n\n![One-page visual explainer](doc/img/toothbrush-onepage.png)\n\n## In use\n\nHere is a [short demo video](https://www.youtube.com/shorts/U8TeewQ9t-k).\n\n[![Demo video](doc/img/toothbrush-demo-short_200w.jpg)](https://www.youtube.com/shorts/U8TeewQ9t-k)\n\n\n## Status\n***Proof of Concept***. Tested working on device.\n\n- Firmware is complete and functional\n- Basic documentation on how to reproduce exists\n- Software and training pipeline *needs some cleanup*\n\nFor more details, see [TODO.md](./doc/TODO.md)\n\n## License\nMIT\n\n\n## Hardware\n\nTo assemble the device, one needs the following.\n\n- [M5Stick C PLUS2](https://shop.m5stack.com/products/m5stickc-plus2-esp32-mini-iot-development-kit) from M5Stack\n- 3d-printed toothbrush holder. [.STL export](mechanics/toothbrush-handle-print.stl) | [FreeCAD project](mechanics/toothbrush-handle.FCStd)\n- Zipties\n- Double-sided tape\n\n![Parts before assembly](./doc/img/toothbrush-parts_crop.jpg).\n\n#### Stand\n\nThere is also an optional stand for a magnetic charging connector.\nIt uses a [Plexgear Magnetic USB-C adapter](https://www.kjell.com/no/produkter/kabler-og-kontakter/usb-kabler/plexgear-magnetisk-usb-c-adapter-p44923).\nHopefully something similar can be found online.\n\n[FreeCAD project](mechanics/toothbrush-stand.FCStd)\n\n![Toothbrush with stand](./doc/img/toothbrush-withstand_crop.jpg).\n\n\n## How it is built\n\nThe code that runs on device is found in [firmware/](./firmware).\nThe code used on PC to train machine learning model is found in [software/](./software)\n\n#### Data recording\n\nTo record data we used the `har_record.py` script from [emlearn-micropython har_trees example](https://github.com/emlearn/emlearn-micropython/tree/master/examples/har_trees). \nWe also recorded video of the brushing activity using a mobile phone.\nThis was used to establish the ground truth.\nSee [doc/data_collection.md](doc/data_collection.md) for details.\n\nThe raw data from device is stored in `data/jonnor-brushing-1/har_record/`.\n\n#### Data labeling\n\nWe use [Label Studio](https://labelstud.io) to annotate the videos.\nThe labeling annotation definition can be found in [doc/labeling.xml](doc/labeling.xml).\n\nThe labeled data should be exported as .CSV file.\n\n#### Data set preparation\n\nWhen the data recording and data labeling has been completed, the data can be combined into a dataset.\n\n```\nFIXME: clean up these steps. Move from notebooks into .py files\n```\n\nThe output goes to `data/jonnor-brushing-1/combined.parquet`.\n\n\n#### Model training\n\nTo train the model we used the `har_train.py` script from [emlearn-micropython har_trees example](https://github.com/emlearn/emlearn-micropython/tree/master/examples/har_trees).\n```\nMIN_SAMPLES_LEAF=0.20,0.30 python har_train.py --dataset toothbrush_jonnor --window-length 50 --window-hop 50\n```\n\n#### Firmware\n\nThe firmware has the following overall architecture:\n\n![Firmware architecture diagram](doc/img/toothbrush-firmware-architecture.png)\n\nHere is the states of the state machine, that defines the overall behavior of the device:\n![State machine diagram](doc/img/toothbrush-statemachine.png)\n\n\n## Installing\n\n#### Development environment\n\nYou must have Python 3.10+ installed.\nUsing a virtual environment is recommended.\n\nInstall project dependencies\n\n```\npip install -e .\n```\n\n\n## For M5Stack M5Stick C PLUS 2 \n\nFlash device with MicroPython for ESP32\n\n```\nmpflash flash --version 1.24\n```\n\nCopy dependencies to device\n\n```\nmpremote mip install https://emlearn.github.io/emlearn-micropython/builds/master/xtensawin_6.3/emlearn_trees.mpy\nmpremote mip install github:jonnor/micropython-npyfile\nmpremote mip install github:jonnor/micropython-mpu6886\nmpremote mip install https://github.com/emlearn/emlearn-micropython/raw/refs/heads/master/examples/har_trees/timebased.py\nmpremote mip install https://github.com/emlearn/emlearn-micropython/raw/refs/heads/master/examples/har_trees/recorder.py\n```\n\n## For XIAO BLE Sense NRF52840 \n\nFlash device with MicroPython\n\n```\nTODO: provide pre-built firmware\n```\n\nCopy dependencies to device\n```\nmpremote mip install --target lib github:jonnor/micropython-npyfile\nmpremote mip install --target lib https://github.com/emlearn/emlearn-micropython/raw/refs/heads/master/examples/har_trees/timebased.py\nmpremote mip install --target lib https://github.com/emlearn/emlearn-micropython/raw/refs/heads/master/examples/har_trees/recorder.py\nmpremote cp firmware/lsm6ds.py :lib/\n```\n\n\n#### Copy application to device\n\nCopy the firmware files\n```\nmpremote cp firmware/core.py firmware/buzzer_music.py firmware/process.py firmware/brushing.trees.csv firmware/main.py :\n```\n\nStart the application and observe log\n```\nmpremote run firmware/main.py\n```\n\nRestart device, will disconnect log\n```\nmpremote reset\n```\n\n\n## Developing\n\n\n#### Running firmware tests on PC\n\nWith MicroPython Unix port, one can run the firmware tests on PC.\n\n```\nmicropython firmware/test_toothbrush.py\n```\n\n#### Running firmware tests on device\n\n```\nTODO: check tests on device, document how to run\n```\n\n#### Training model\n\n```\nTODO: document how to run\nSee the Gitlab CI actions\n```\n\n#### Modifying dataset\n\n```\nSee doc/data_collection.md\n```\n\n#### Porting to other devices\n\nAll the hardware-specific code is located in `main.py`.\nSo modifying that is all that should be needed to adapt to another device.\nIf there is no buzzer with PWM, you may also want to change `OutputManager`.\n\nNote that the accelerometer driver should use the FIFO,\nto enable sampling data independently from the firmware execution. \n[More information](https://github.com/orgs/micropython/discussions/15512).\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonnor%2Ftoothbrush","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonnor%2Ftoothbrush","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonnor%2Ftoothbrush/lists"}