See it live here
The Multirotor Rate Converter aims to provide multirotor enthusiasts with a tool to convert flight controller (FC) rates from one type to another.
Users can input their own rates or the rates of popular pilots to visually compare them. Additionally, the tool allows for the automatic conversion of these rates to a format of another flight controller software.
The rate calculations are derived directly from the Betaflight Configurator repository. This tool simply borrows their rate calculation file and gives it a new place to show off its curves.
There are two methods for rate calculation:
- API-Based Calculation: This method takes 10 data points from the source curve and uses non-linear least squares to(try to) find the best fit for the desired rate type.
- Local Gradient Descent: This method uses 500 data points and Mean Squared Error (MSE) to identify the best fit.
The on-device gradient descent calculation was developed as a proof of concept to potentially reduce monthly server costs. However, the API-based calculation is faster and the max rate is generally more accurate to the input.
- Implementation of different themes.
- Integration of a throttle slider.
- Implement tests for all functionalities.
For local testing without docker, you can run the project and serve the web app using just python and flask
- python3.8
- virtual environment (
venv
) - pip
if you dont have git installed you can visit this link to the repo and download the zip file by clicking code
> download zip
git clone https://github.com/Marc-Anderson/multirotor-rate-converter.git
cd multirotor-rate-converter
python3 -m venv .venv
source .venv/bin/activate
pip3 install -r requirements.txt
python3 wsgi.py
Note: to avoid issues with browser caching, use an incognito window or perform a hard refresh occasionally.
build an image and spin up a container containing the web app using docker compose. these development instructions will keep all files within the project folder
- linux, wsl2 in windows or multipass on macos
- docker
- non-root user
- git(recommeded)
if you dont have git installed you can visit this link to the repo and download the zip file by clicking code
> download zip
git clone https://github.com/Marc-Anderson/multirotor-rate-converter.git
cd multirotor-rate-converter
# make the setup file executable
sudo chmod +x ./setup.sh
# run the setup script
./setup.sh
# follow the instructions for `dev`
Click To Expand: instructions for manually creating folder structure with required permissions instead
some users prefer not to run setup scripts for security reasons. the below steps walk you through the manual creation of the required folder structure
mkdir docker_volumes
you must create these logs and gunicorn socket folders as defined in the .env
file if you dont create these on the host they will be owned by root and containers will not be able to access them
mkdir -p ./docker_volumes/var/log/nginx-docker
mkdir -p ./docker_volumes/var/log/gunicorn-docker
mkdir -p ./docker_volumes/run/gunicorn-docker
chmod 770 -R ./docker_volumes/
docker compose --env-file ./.env.dev up -d --build
5. access the application in your browser at the ip address of your host, port 3000
(e.g. 127.0.0.1:3000
).
docker compose --env-file ./.env.dev down
- linux vps
- docker
- ufw
- fail2ban (recommended)
- non-root user
- ssh public key for user
- a domain name
- ssl certificate(domain key, and private key)
ssl certificates and renewal is an involved process. you may be able to deploy and manage them with certbot or caddy but for this deployment we use ssl certificate files which do not renew automatically
- you can download your certificates from your dns provider which expire every 30-90 days
- place these certificates in
./ssl_certificates/yourdomain.com
- you will need to upload new certificates once per month and restart the containers for nginx to recognize them
- alternative options:
Click To Expand: overview of server config
this guide isnt going to cover this entirely but here is a brief overview with commands
# 1. create a new droplet on digitalocean
# 2. select the marketplace images > docker
# 3. choose the smallest possible vps
# 4. log into the console as root from the website ui
# 5. continue with the below steps
# define a non-root username and ssh public key
# default password will be your username
USERNAME=docker_user
SSH_KEY_NAME="computer"
SSH_PUBLIC_KEY=""
# EXAMPLE_SSH_PUBLIC_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBZzHpY7r6bRpN2u/9eLsPYkbZK8ZwCff9yM7qXzjV5b [email protected]"
TEMP_PASSWORD=$USERNAME
# make sure you provided a public key
if [ -z "$SSH_PUBLIC_KEY" ]; then
echo "Error: SSH_PUBLIC_KEY is empty."
exit 1
fi
# update package list and install required tools
sudo apt-get update && sudo apt-get install -y ufw git fail2ban
# disable firewall
sudo ufw disable
# reset firewall to remove all rules
sudo echo "y" | sudo ufw reset
# allow but limit ssh
sudo ufw limit 22/tcp
# re-enable firewall
sudo echo "y" | sudo ufw enable
# confirm firewall status for JUST ssh
sudo ufw status
# create user and add them to the sudo group
useradd --create-home --shell /bin/bash --groups sudo "${USERNAME}"
# add the user to the docker group if it exists
if command -v docker >/dev/null 2>&1; then usermod -aG docker "${USERNAME}"; fi
# give the user a default password
echo "${USERNAME}:${TEMP_PASSWORD}" | chpasswd
# force password reset on next login
# password defaults to username
chage --lastday 0 "${USERNAME}"
# create ssh directory for new user
home_directory="$(eval echo ~${USERNAME})"
mkdir --parents "${home_directory}/.ssh"
# add specified public key to authorized keys for new user with the key description as a comment
echo "# ${SSH_KEY_NAME}" >> "${home_directory}/.ssh/authorized_keys"
echo $SSH_PUBLIC_KEY >> "${home_directory}/.ssh/authorized_keys"
# update the permissions of the ssh folder and files
chmod 0700 "${home_directory}/.ssh"
chmod 0600 "${home_directory}/.ssh/authorized_keys"
chown --recursive "${USERNAME}":"${USERNAME}" "${home_directory}/.ssh"
# switch to the new user
sudo su - $USERNAME
if you dont have git installed you can visit this link to the repo and download the zip file by clicking code
> download zip
git clone https://github.com/Marc-Anderson/multirotor-rate-converter.git
cd multirotor-rate-converter
you should have an domain key, and a private key from your domain registrar. rename both files as below and place them in the new folder, place that folder in the ssl_certificates
folder
ssl certificates should be organized in their own domains folder. we're only working with one domain right now, but this keeps us organized in case we introduce multiple domains in the future
# ./ssl_certificates/example.com/domain.cert.pem
# ./ssl_certificates/example.com/private.key.pem
you can do this manually or replace example.com below with your domain name and use these commands
domain_name=example.com
sed -i "s/^DOC_DOMAIN=.*/DOC_DOMAIN=$domain_name/" .env.prod
# make the setup file executable and run it
sudo chmod +x ./setup.sh
./setup.sh
Click To Expand: instructions for manually creating users, folder structure with required permissions instead
sudo groupadd -g 1700 -o docker_grp
7. create local gunicorn user, add the nginx user to the docker group, and disable any shell for security:
sudo useradd --shell /usr/sbin/nologin --uid 1802 doc_gunicorn
# by default the nginx container user is 101 `systemd-resolve` so thats the user we will use here
sudo usermod -aG docker_grp systemd-resolve
8. create nginx/gunicorn log directories and set the correct permissions matching the .env.prod
file:
sudo mkdir -p /var/log/nginx-docker
sudo chown 101:101 /var/log/nginx-docker
sudo chmod 750 -R /var/log/nginx-docker
sudo mkdir -p /var/log/gunicorn-docker
sudo chown doc_gunicorn:root /var/log/gunicorn-docker
sudo chmod 750 -R /var/log/gunicorn-docker
sudo mkdir -p /run/gunicorn-docker
sudo chown doc_gunicorn:docker_grp /run/gunicorn-docker
sudo chmod 770 -R /run/gunicorn-docker
10. create ssl directory directory under your domain /etc/nginx/ssl/example.com
and copy your ssl certificates to it
replace example.com below with your domain name
# update your domain name here
domain_name=example.com
sudo mkdir -p /etc/nginx/ssl/$domain_name
# can this be root:root?
sudo chown 101:101 -R /etc/nginx/ssl
sudo chmod 750 -R /etc/nginx
sudo cp -r ./ssl_certificates/$domain_name/* /etc/nginx/ssl/$domain_name
# set permissions for certificate and private keys
sudo chown 101:101 /etc/nginx/ssl/$domain_name/domain.cert.pem
sudo chown 101:101 /etc/nginx/ssl/$domain_name/private.key.pem
sudo chmod 644 /etc/nginx/ssl/$domain_name/domain.cert.pem
sudo chmod 640 /etc/nginx/ssl/$domain_name/private.key.pem
if you dont do this, fail2ban wont be able to find the logs so it can block people abusing the server
# copy the default fail2ban config file to a jail.local file
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# add a reference to the new nginx log location for our docker container to the bottom of the file
sudo nano /etc/fail2ban/jail.local
# new nginx log location for docker container
[docker-nginx]
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx-docker/*log
if you dont do this, the logs for gunicorn may grow out of control and take over your servers storage
# create a new logrotate file for gunicorn and add a log configuration
sudo nano /etc/logrotate.d/gunicorn
# logrotate settings for gunicorn
# rotate gunicorn logs to prevent them from consuming all of the storage
/var/log/gunicorn/*.log {
monthly
maxsize 20M
# keep n rotated logs
rotate 3
# add date to archives
dateext
missingok
compress
delaycompress
# dont rotate if empty
notifempty
# copy log and remove content instead of deleting it
copytrucate
}
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
sudo ufw enable
docker compose --env-file ./.env.prod up -d --build
# docker compose --env-file ./.env.prod up --build
docker compose --env-file ./.env.prod down