Gymnasticon enables obsolete and/or proprietary exercise bikes to work with Zwift and other training apps. Support for new bikes can be added easily. The diagram below shows an example of how it works with the Flywheel Home Bike.
Any software, bike computer or watch that supports standard Bluetooth LE and ANT+ power meter and cadence sensors should work, including:
Raspberry Pi Zero W is recommended for best user experience. Any recent Linux or macOS system should be able to run Gymnasticon.
Note: If using a Bluetooth LE bike (e.g. Flywheel) a Bluetooth LE 4.1+ adapter with multi-role capability is required. All Raspberry Pi devices listed above have this capability but not every BT 4.1+ adapter is guaranteed to have it. Alternatively, two BT 4.0+ adapters can also work: one for the client (to connect to the bike) and one for the server (to receive connections from Zwift or another app).
This is the easiest way to get up and running on a Raspberry Pi.
Prerequisites:
dd(1)
Steps:
dd
Config file:
If using a bike other than Flywheel or Peloton - create and adapt a gymnasticon.json
file within the main folder of the SD card. It should end up in the same folder as bootcode.bin
, cmdline.txt
, config.txt
, etc.
The following example configures Gymnasticon to look for a Schwinn IC4 bike and to reduce its power measurement values by 8%:
{
"bike": "ic4",
"power-scale": 0.92
}
The following example configures Gymnasticon to look for a Keiser M series bike:
{
"bike": "keiser"
}
See below for additional configuration options.
During first boot Gymnasticon enables the Overlay Filesystem for the root filesystem ("/") and mounts "/boot" as read-only. This reduces the risk of fatal filesystem corruption as result of e.g. power failures, but also extends the lifetime of the SD card by minimizing wear.
A clean shutdown of Gymnasticon is therefore not necessary. Just keep your Raspberry Pi plugged in and running.
It is still possible to setup networking and remote access so you can check logs, or participate in development work. But this mode is neither necessary, nor recommended for typical users.
Note: This modified Pi OS image will behave equivalent to stock Pi OS images with regards to the
wpa_supplicant.conf
andssh
files only during first boot. This means that the Wifi and SSH settings become part of the underlay filesystem and persist across subsequent reboots. Placing awpa_supplicant.conf
orssh
file onto the boot partition after the first boot will result in settings NOT being persisted across reboots. Also note that in this case thewpa_supplicant.conf
andssh
files are removed and not available during another reboot.
You can change the root filesystem between read-only and read-write mode, but also show the current mode using the command overctl
.
Flywheel bike
Peloton bike (with passive wiring)
Try the Quick Start first. Otherwise read on for how to install Gymnasticon and its dependencies manually.
Dependencies:
Node.JS 12.16.1+
On Linux (including Raspberry Pi)
sudo apt-get install libudev-dev
(required by node-bluetooth-hci-socket)Note: Your user must have permission to access the Bluetooth adapter and advertise services.
Install:
npm install -g gymnasticon
gymnasticon
To run as an unprivileged user:
# this gives cap_net_raw+eip to all node programs not just gymnasticon
sudo setcap cap_net_raw+eip $(eval readlink -f $(which node))
To run at boot time, restart on exit and to avoid giving cap_net_raw+eip
to the node binary it is recommended to run under systemd. See the deploy/gymnasticon.service
from this repository for an example systemd unit file.
sudo cp gymnasticon.service /etc/systemd/system
sudo systemctl enable gymnasticon
sudo systemctl start gymnasticon
To view the output of Gymnasticon running under systemd:
journalctl -u gymnasticon -f
Note: The CLI options below can also be used in the config file.
--bike ic4
on the command-line is the same as{"bike":"ic4"}
in the config file.
$ gymnasticon --help
__o
_ \<_
(_)/(_)
Gymnasticon
v1.4.0
usage: gymnasticon [OPTIONS]
Options:
--config <filename> load options from json file [string]
--bike <type>
[string] [choices: "flywheel", "peloton", "ic4", "keiser", "bot",
"autodetect"] [default: "autodetect"]
--bike-connect-timeout <seconds> [number] [default: 0]
--bike-receive-timeout <seconds> [number] [default: 4]
--bike-adapter <name> for bike connection [default: "hci0"]
--flywheel-address <macaddr>
--flywheel-name <name>
--peloton-path <path> usb serial device path
[string] [default: "/dev/ttyUSB0"]
--bot-power <watts> initial bot power [number]
--bot-cadence <rpm> initial bot cadence [number]
--bot-host <host> for power/cadence control over udp [string]
--bot-port <port> for power/cadence control over udp [number]
--server-adapter <name> for app connection [default: "hci0"]
--server-name <name> used for Bluetooth advertisement
[default: "Gymnasticon"]
--server-ping-interval <seconds> ping app when user not pedaling
[number] [default: 1]
--ant-device-id <id> ANT+ device id for bike power broadcast
[number] [default: 11234]
--power-scale <value> scale watts by this multiplier
[number] [default: 1]
--power-offset <value> add this value to watts [number] [default: 0]
--version Show version number [boolean]
-h, --help Show help [boolean]
git clone https://github.com/ptx2/gymnasticon.git
cd gymnasticon
npm run build
npm link
gymnasticon --help
It should be trivial to add support for other proprietary bikes, so long as there is a means of getting realtime-ish cadence/power data from them.
MIT
Read the development notes here.