Merge branch 'mdbook' into 'master'
Migrate to mdBook See merge request stavros/notes!1
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
themes/
|
themes/
|
||||||
public/
|
public/
|
||||||
|
book/
|
||||||
|
@ -1,12 +1,26 @@
|
|||||||
pages:
|
stages:
|
||||||
|
- build
|
||||||
|
- pages
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
image: python
|
image: python
|
||||||
script:
|
script:
|
||||||
- wget https://github.com/getzola/zola/releases/download/v0.12.2/zola-v0.12.2-x86_64-unknown-linux-gnu.tar.gz -O zola.tgz
|
- pip install pre-commit
|
||||||
- tar zxvf zola.tgz
|
- pre-commit run -a --hook-stage=manual
|
||||||
- mv zola /usr/local/bin/
|
- wget https://github.com/rust-lang/mdBook/releases/download/v0.4.13/mdbook-v0.4.13-x86_64-unknown-linux-gnu.tar.gz -O mdbook.tgz
|
||||||
- ./build.sh
|
- tar zxvf mdbook.tgz
|
||||||
|
- mv mdbook /usr/local/bin/
|
||||||
|
- ./build
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- public
|
- public
|
||||||
|
|
||||||
|
pages:
|
||||||
|
stage: pages
|
||||||
|
script: ls -lah public/
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- public
|
||||||
|
@ -21,8 +21,8 @@ repos:
|
|||||||
- --ignore=D100,D107,D203,D212
|
- --ignore=D100,D107,D203,D212
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
- id: migrations-check
|
- id: no-todos
|
||||||
language: system
|
name: Forbid TODOs
|
||||||
name: Export the notes.
|
entry: "TODO"
|
||||||
entry: bash -c "./joplinexport.py"
|
language: pygrep
|
||||||
pass_filenames: false
|
types: [python]
|
||||||
|
13
book.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[book]
|
||||||
|
authors = ["Stavros Korokithakis"]
|
||||||
|
language = "en"
|
||||||
|
multilingual = false
|
||||||
|
src = "content"
|
||||||
|
title = "Stavros' Notes"
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
curly-quotes = true
|
||||||
|
no-section-label = false
|
||||||
|
git-repository-url = "https://gitlab.com/stavros/notes/"
|
||||||
|
git-repository-icon = "fa-gitlab"
|
||||||
|
additional-css = ["static/custom.css"]
|
11
build
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
rm -rf public/
|
||||||
|
mdbook build -d public
|
||||||
|
|
||||||
|
# Make checkboxes editable, just in case the user wants to keep their own checklist.
|
||||||
|
find public/ -name "*.html" -type f -exec sed -i 's/input disabled=""/input/g' {} +
|
||||||
|
|
||||||
|
cp -R static/* public/
|
14
build.sh
@ -1,14 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -euxo pipefail
|
|
||||||
|
|
||||||
rm -rf themes/book/
|
|
||||||
git clone https://github.com/getzola/book.git themes/book/
|
|
||||||
|
|
||||||
sed -i '5i if (window.innerWidth < 900) { $menu.classList.toggle("menu-hidden"); $page.classList.toggle("page-without-menu"); }\n' themes/book/static/book.js
|
|
||||||
|
|
||||||
rm -rf public/
|
|
||||||
zola build
|
|
||||||
|
|
||||||
# Make checkboxes editable, just in case the user wants to keep their own checklist.
|
|
||||||
find public/ -name "*.html" -type f -exec sed -i 's/input disabled=""/input/g' {} +
|
|
38
content/SUMMARY.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
[Stavros' notes](welcome/stavros-notes.md)
|
||||||
|
- [Drone stuff](drone-stuff/index.md)
|
||||||
|
- [ArduPilot](ardupilot/index.md)
|
||||||
|
- [ArduPilot recommended settings](ardupilot/ardupilot-recommended-settings.md)
|
||||||
|
- [ArduPilot setup checklist](ardupilot/ardupilot-setup-checklist.md)
|
||||||
|
- [Building ArduPilot](ardupilot/building-ardupilot.md)
|
||||||
|
- [Configuring a switch as a relay](ardupilot/configuring-a-switch-as-a-relay.md)
|
||||||
|
- [Miscellaneous notes](ardupilot/miscellaneous-notes.md)
|
||||||
|
- [Reverse thrust](ardupilot/reverse-thrust.md)
|
||||||
|
- [TECS tuning calculator](ardupilot/tecs-tuning-calculator.md)
|
||||||
|
- [Transfer config between craft](ardupilot/transfer-config-between-craft.md)
|
||||||
|
- [Tuning the TECS](ardupilot/tuning-the-tecs.md)
|
||||||
|
- [Model build notes](model-build-notes/index.md)
|
||||||
|
- [Build notes for the FT Mighty Mini Arrow](model-build-notes/build-notes-for-the-ft-mighty-mini-arrow.md)
|
||||||
|
- [Mini Drak build condensed instructions](model-build-notes/mini-drak-build-condensed-instructions.md)
|
||||||
|
- [A simple guide to PID control](drone-stuff/a-simple-guide-to-pid-control.md)
|
||||||
|
- [E6000 hinges](drone-stuff/e6000-hinges.md)
|
||||||
|
- [FPV frequency chart](drone-stuff/fpv-frequency-chart.md)
|
||||||
|
- [General RC tips](drone-stuff/general-rc-tips.md)
|
||||||
|
- [Getting uninverted SBUS on a no-name FrSky-compatible receiver](drone-stuff/getting-uninverted-sbus-on-a-no-name-frsky-compatible-receiver.md)
|
||||||
|
- [Getting uninverted SBUS/SmartPort on the FrSky XSR receiver](drone-stuff/getting-uninverted-sbus-smartport-on-the-frsky-xsr-receiver.md)
|
||||||
|
- [INAV tuning tips](drone-stuff/inav-tuning-tips.md)
|
||||||
|
- [Miscellaneous](drone-stuff/miscellaneous.md)
|
||||||
|
- [Omnibus F4 pro servo diode](drone-stuff/omnibus-f4-pro-servo-diode.md)
|
||||||
|
- [Omnibus F4 V3 pinout](drone-stuff/omnibus-f4-v3-pinout.md)
|
||||||
|
- [QGroundControl to Mission Planner conversion script](drone-stuff/qgroundcontrol-to-mission-planner-conversion-script.md)
|
||||||
|
- [Transmitter external module pinout](drone-stuff/transmitter-external-module-pinout.md)
|
||||||
|
- [Transportable C1 Chaser](drone-stuff/transportable-c1-chaser.md)
|
||||||
|
- [Maker things](maker-things/index.md)
|
||||||
|
- [Battery discharge curves](maker-things/battery-discharge-curves.md)
|
||||||
|
- [Electronics tips](maker-things/electronics-tips.md)
|
||||||
|
- [GRBL_ESP32 tips](maker-things/grbl-esp32-tips.md)
|
||||||
|
- [How to properly level your 3D printer](maker-things/how-to-properly-level-your-3d-printer.md)
|
||||||
|
- [Software](software/index.md)
|
||||||
|
- [Monero GUI syncing stuck with Ledger](software/monero-gui-syncing-stuck-with-ledger.md)
|
||||||
|
- [Test and format SD cards](software/test-and-format-sd-cards.md)
|
@ -1,19 +0,0 @@
|
|||||||
+++
|
|
||||||
title = "ArduPilot"
|
|
||||||
weight = 2
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
Click on a link in the list below to go to that page:
|
|
||||||
|
|
||||||
1. [ArduPilot recommended settings](../../ardupilot/ardupilot-recommended-settings)
|
|
||||||
1. [ArduPilot setup checklist](../../ardupilot/ardupilot-setup-checklist)
|
|
||||||
1. [Building ArduPilot](../../ardupilot/building-ardupilot)
|
|
||||||
1. [Configuring a switch as a relay](../../ardupilot/configuring-a-switch-as-a-relay)
|
|
||||||
1. [Miscellaneous notes](../../ardupilot/miscellaneous-notes)
|
|
||||||
1. [Reverse thrust](../../ardupilot/reverse-thrust)
|
|
||||||
1. [TECS tuning calculator](../../ardupilot/tecs-tuning-calculator)
|
|
||||||
1. [Transfer config between craft](../../ardupilot/transfer-config-between-craft)
|
|
||||||
1. [Tuning the TECS](../../ardupilot/tuning-the-tecs)
|
|
@ -1,21 +1,17 @@
|
|||||||
+++
|
# ArduPilot recommended settings
|
||||||
title = "ArduPilot recommended settings"
|
|
||||||
weight = 1
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
This section contains some recommended settings for ArduPilot. Nothing is set in stone, these are just some defaults I've found to work well.
|
This section contains some recommended settings for ArduPilot. Nothing is set in stone, these are just some defaults I've found to work well.
|
||||||
|
|
||||||
## GPS
|
## GPS
|
||||||
|
|
||||||
```bash
|
```js
|
||||||
GPS_GNSS_MODE=71 # Enable GPS/SBAS/Galileo/GLONASS.
|
GPS_GNSS_MODE=71 # Enable GPS/SBAS/Galileo/GLONASS.
|
||||||
GPS_RATE_MS=100 # 10 Hz update rate.
|
GPS_RATE_MS=100 # 10 Hz update rate.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Crossfire/ELRS
|
## Crossfire/ELRS
|
||||||
|
|
||||||
```bash
|
```js
|
||||||
SERIALn_PROTOCOL=23 # Crossfire/ELRS.
|
SERIALn_PROTOCOL=23 # Crossfire/ELRS.
|
||||||
RC_OPTION=800 # 5 - Arming check throttle.
|
RC_OPTION=800 # 5 - Arming check throttle.
|
||||||
# 8 - CRSF telemetry passthrough.
|
# 8 - CRSF telemetry passthrough.
|
||||||
@ -26,7 +22,7 @@ RC_OPTION=800 # 5 - Arming check throttle.
|
|||||||
|
|
||||||
30% expo is a good starting point:
|
30% expo is a good starting point:
|
||||||
|
|
||||||
```bash
|
```js
|
||||||
MAN_EXPO_ROLL=30
|
MAN_EXPO_ROLL=30
|
||||||
MAN_EXPO_PITCH=30
|
MAN_EXPO_PITCH=30
|
||||||
MAN_EXPO_RUDDER=30
|
MAN_EXPO_RUDDER=30
|
||||||
@ -34,7 +30,7 @@ MAN_EXPO_RUDDER=30
|
|||||||
|
|
||||||
## Miscellaneous
|
## Miscellaneous
|
||||||
|
|
||||||
```bash
|
```js
|
||||||
INS_GYRO_FILTER=60 # Faster gyro updates.
|
INS_GYRO_FILTER=60 # Faster gyro updates.
|
||||||
SCHED_LOOP_RATE=100 # Faster scheduler updates.
|
SCHED_LOOP_RATE=100 # Faster scheduler updates.
|
||||||
```
|
```
|
||||||
@ -42,6 +38,6 @@ SCHED_LOOP_RATE=100 # Faster scheduler updates.
|
|||||||
* * *
|
* * *
|
||||||
|
|
||||||
<p style="font-size:80%; font-style: italic">
|
<p style="font-size:80%; font-style: italic">
|
||||||
Last updated on October 31, 2021. For any questions/feedback,
|
Last updated on November 19, 2021. For any questions/feedback,
|
||||||
email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# ArduPilot setup checklist
|
||||||
title = "ArduPilot setup checklist"
|
|
||||||
weight = 2
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
This is a short guide for setting up [ArduPilot](https://ardupilot.org/) on a flying wing. I use an Omnibus F4 that was previously set up for INAV (so motor on 1, elevons on 3/4), so most of this guide will be geared to that. If you use a different controller, your mileage may vary.
|
This is a short guide for setting up [ArduPilot](https://ardupilot.org/) on a flying wing. I use an Omnibus F4 that was previously set up for INAV (so motor on 1, elevons on 3/4), so most of this guide will be geared to that. If you use a different controller, your mileage may vary.
|
||||||
|
|
||||||
You should keep the [full list of ArduPilot parameters](https://ardupilot.org/plane/docs/parameters.html) open, for your reference while tuning.
|
You should keep the [full list of ArduPilot parameters](https://ardupilot.org/plane/docs/parameters.html) open, for your reference while tuning.
|
||||||
@ -17,7 +13,7 @@ It's called Parachute, and you can download it here:
|
|||||||
|
|
||||||
|
|
||||||
## Building ArduPilot
|
## Building ArduPilot
|
||||||
See [Building ArduPilot](../../ardupilot/building-ardupilot) for instructions on how to build the latest version.
|
See [Building ArduPilot](/ardupilot/building-ardupilot) for instructions on how to build the latest version.
|
||||||
|
|
||||||
|
|
||||||
## Hardware setup
|
## Hardware setup
|
||||||
@ -30,7 +26,7 @@ The values in this section are specific to the Omnibus F4, but the settings aren
|
|||||||
- [ ] Connect Fport to a UART. I chose UART 3 (SERIAL2). If you want to use UART 1, you should set the RC input jumper to PPM on the F4 to disconnect the SBUS inverter from the pin.
|
- [ ] Connect Fport to a UART. I chose UART 3 (SERIAL2). If you want to use UART 1, you should set the RC input jumper to PPM on the F4 to disconnect the SBUS inverter from the pin.
|
||||||
- [ ] To get Fport working with UART 3, you need to set `BRD_ALT_CONFIG=1`, to get UART 3 to act like a UART instead of I2C on the Omnibus F4.
|
- [ ] To get Fport working with UART 3, you need to set `BRD_ALT_CONFIG=1`, to get UART 3 to act like a UART instead of I2C on the Omnibus F4.
|
||||||
- [ ] Set the following for Fport on UART 3:
|
- [ ] Set the following for Fport on UART 3:
|
||||||
```bash
|
```js
|
||||||
SERIAL2_PROTOCOL=23 # RCIN
|
SERIAL2_PROTOCOL=23 # RCIN
|
||||||
SERIAL2_BAUD=115
|
SERIAL2_BAUD=115
|
||||||
SERIAL2_OPTIONS=4
|
SERIAL2_OPTIONS=4
|
||||||
@ -38,7 +34,7 @@ The values in this section are specific to the Omnibus F4, but the settings aren
|
|||||||
```
|
```
|
||||||
- [ ] Once Fport works, reverse the elevator with `RC2_REVERSED=1`.
|
- [ ] Once Fport works, reverse the elevator with `RC2_REVERSED=1`.
|
||||||
- [ ] Set up your servo functions and trims:
|
- [ ] Set up your servo functions and trims:
|
||||||
```bash
|
```js
|
||||||
SERVO1_FUNCTION=70 # Throttle
|
SERVO1_FUNCTION=70 # Throttle
|
||||||
SERVO1_MIN=1000
|
SERVO1_MIN=1000
|
||||||
SERVO1_MAX=2000
|
SERVO1_MAX=2000
|
||||||
@ -102,7 +98,7 @@ The values in this section are specific to the Omnibus F4, but the settings aren
|
|||||||
|
|
||||||
## Recommended settings.
|
## Recommended settings.
|
||||||
|
|
||||||
See the [recommended settings](../../ardupilot/ardupilot-recommended-settings) page for other recommended defaults.
|
See the [recommended settings](/ardupilot/ardupilot-recommended-settings) page for other recommended defaults.
|
||||||
|
|
||||||
## In the field
|
## In the field
|
||||||
- [ ] Run an autotune.
|
- [ ] Run an autotune.
|
||||||
@ -113,6 +109,6 @@ _(Many thanks to Michel Pastor for his help with everything in this note.)_
|
|||||||
* * *
|
* * *
|
||||||
|
|
||||||
<p style="font-size:80%; font-style: italic">
|
<p style="font-size:80%; font-style: italic">
|
||||||
Last updated on October 31, 2021. For any questions/feedback,
|
Last updated on November 19, 2021. For any questions/feedback,
|
||||||
email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Building ArduPilot
|
||||||
title = "Building ArduPilot"
|
|
||||||
weight = 3
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
Because building ArduPilot is a bit complicated, I've written a short script that uses Docker to build AP in a controlled environment.
|
Because building ArduPilot is a bit complicated, I've written a short script that uses Docker to build AP in a controlled environment.
|
||||||
|
|
||||||
Copy it from here, save it to a file called `docker_build.sh` in the root of the ArduPilot repo, and run it with `docker_build.sh <your board>`. Output files will be stored in `build/<yourboard>/bin/`, and you can flash them with the [INAV configurator](https://github.com/iNavFlight/inav-configurator/releases) by putting your board in DFU mode and uploading the `arduplane_with_bl.hex` file.
|
Copy it from here, save it to a file called `docker_build.sh` in the root of the ArduPilot repo, and run it with `docker_build.sh <your board>`. Output files will be stored in `build/<yourboard>/bin/`, and you can flash them with the [INAV configurator](https://github.com/iNavFlight/inav-configurator/releases) by putting your board in DFU mode and uploading the `arduplane_with_bl.hex` file.
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Configuring a switch as a relay
|
||||||
title = "Configuring a switch as a relay"
|
|
||||||
weight = 4
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
If you want to connect a relay of some sort (something that accepts a low/high signal, like a camera control) to a PWM output (the servo outputs), you need to do a few quick things. The actual numbers will vary depending on your FC, but here's what worked for me with a Matek F405-Wing:
|
If you want to connect a relay of some sort (something that accepts a low/high signal, like a camera control) to a PWM output (the servo outputs), you need to do a few quick things. The actual numbers will vary depending on your FC, but here's what worked for me with a Matek F405-Wing:
|
||||||
|
|
||||||
1. Set the channel you want the relay to trigger on as a controller for the first relay (here I'll assume you want to control the first relay on channel 11):
|
1. Set the channel you want the relay to trigger on as a controller for the first relay (here I'll assume you want to control the first relay on channel 11):
|
||||||
|
13
content/ardupilot/index.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Contents
|
||||||
|
|
||||||
|
Click on a link in the list below to go to that page:
|
||||||
|
|
||||||
|
1. [ArduPilot recommended settings](../../ardupilot/ardupilot-recommended-settings.html)
|
||||||
|
1. [ArduPilot setup checklist](../../ardupilot/ardupilot-setup-checklist.html)
|
||||||
|
1. [Building ArduPilot](../../ardupilot/building-ardupilot.html)
|
||||||
|
1. [Configuring a switch as a relay](../../ardupilot/configuring-a-switch-as-a-relay.html)
|
||||||
|
1. [Miscellaneous notes](../../ardupilot/miscellaneous-notes.html)
|
||||||
|
1. [Reverse thrust](../../ardupilot/reverse-thrust.html)
|
||||||
|
1. [TECS tuning calculator](../../ardupilot/tecs-tuning-calculator.html)
|
||||||
|
1. [Transfer config between craft](../../ardupilot/transfer-config-between-craft.html)
|
||||||
|
1. [Tuning the TECS](../../ardupilot/tuning-the-tecs.html)
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Miscellaneous notes
|
||||||
title = "Miscellaneous notes"
|
|
||||||
weight = 5
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
These are random AP-related notes that wouldn't fit anywhere else:
|
These are random AP-related notes that wouldn't fit anywhere else:
|
||||||
|
|
||||||
## DJI FPV configuration
|
## DJI FPV configuration
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Reverse thrust
|
||||||
title = "Reverse thrust"
|
|
||||||
weight = 6
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
To set up reverse thrust (for higher braking when landing, for example), follow the steps below:
|
To set up reverse thrust (for higher braking when landing, for example), follow the steps below:
|
||||||
|
|
||||||
- [ ] Set your BLHeli-compatible ESC to "Reversible soft" and make sure you're using DShot.
|
- [ ] Set your BLHeli-compatible ESC to "Reversible soft" and make sure you're using DShot.
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
+++
|
# TECS tuning calculator
|
||||||
title = "TECS tuning calculator"
|
|
||||||
weight = 7
|
To use this calculator, first follow the steps in [Tuning the TECS](/ardupilot/tuning-the-tecs).
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
To use this calculator, first follow the steps in [Tuning the TECS](../../ardupilot/tuning-the-tecs).
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function kmhToMs(kmh) { return Math.round(kmh / 3.6); }
|
function kmhToMs(kmh) { return Math.round(kmh / 3.6); }
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Transfer config between craft
|
||||||
title = "Transfer config between craft"
|
|
||||||
weight = 8
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
This is the regex I use with Parachute to transfer between planes only the parameters that are transferrable (ie non-plane-specific):
|
This is the regex I use with Parachute to transfer between planes only the parameters that are transferrable (ie non-plane-specific):
|
||||||
|
|
||||||
`^(ACRO_LOCKING|OSD.*|RC[\d_]+.*|FLTMODE.*|FLIGHT_OPTIONS|FS_.*|RTL_CLIMB_MIN|RTL_RADIUS|THR_PASS_STAB|THR_SLEWRATE|THR_SUPP_MAN|TKOFF_ACCEL_CNT|TKOFF_ALT|TKOFF_DIST|TKOFF_THR_DELAY|HOME_RESET_ALT|ALT_HOLD_RTL)$`
|
`^(ACRO_LOCKING|OSD.*|RC[\d_]+.*|FLTMODE.*|FLIGHT_OPTIONS|FS_.*|RTL_CLIMB_MIN|RTL_RADIUS|THR_PASS_STAB|THR_SLEWRATE|THR_SUPP_MAN|TKOFF_ACCEL_CNT|TKOFF_ALT|TKOFF_DIST|TKOFF_THR_DELAY|HOME_RESET_ALT|ALT_HOLD_RTL)$`
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Tuning the TECS
|
||||||
title = "Tuning the TECS"
|
|
||||||
weight = 9
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
|
|
||||||
To tune the TECS, a helpful resource is the official [TECS tuning guide](https://ardupilot.org/plane/docs/tecs-total-energy-control-system-for-speed-height-tuning-guide.html).
|
To tune the TECS, a helpful resource is the official [TECS tuning guide](https://ardupilot.org/plane/docs/tecs-total-energy-control-system-for-speed-height-tuning-guide.html).
|
||||||
Make sure you have run an autotune beforehand, and continue with the tuning below.
|
Make sure you have run an autotune beforehand, and continue with the tuning below.
|
||||||
@ -64,7 +60,7 @@ You're done with this step.
|
|||||||
### On the bench
|
### On the bench
|
||||||
After you have the above measurements, you're ready to tune things. You can use the automatic calculator:
|
After you have the above measurements, you're ready to tune things. You can use the automatic calculator:
|
||||||
|
|
||||||
### [TECS tuning calculator](../../ardupilot/tecs-tuning-calculator)
|
### [TECS tuning calculator](/ardupilot/tecs-tuning-calculator)
|
||||||
|
|
||||||
Otherwise, you can do things manually, following the steps below, but you should really use the calculator instead.
|
Otherwise, you can do things manually, following the steps below, but you should really use the calculator instead.
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# A simple guide to PID control
|
||||||
title = "A simple guide to PID control"
|
|
||||||
weight = 1
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I made some changes to my quadcopter the other day for [a new photography project I'm working on](https://www.makerfol.io/project/m8xrLUp-light-painting-with-drones/).
|
I made some changes to my quadcopter the other day for [a new photography project I'm working on](https://www.makerfol.io/project/m8xrLUp-light-painting-with-drones/).
|
||||||
Unfortunately, it turned out that it wasn't good enough, and that I'd have to tune my [PID loop](https://en.wikipedia.org/wiki/PID_controller), which I knew nothing about.
|
Unfortunately, it turned out that it wasn't good enough, and that I'd have to tune my [PID loop](https://en.wikipedia.org/wiki/PID_controller), which I knew nothing about.
|
||||||
After watching a few videos and reading a few things, I learnt enough to be dangerous, and to hopefully be able to explain the concepts simply, so I want to write them down here before I forget.
|
After watching a few videos and reading a few things, I learnt enough to be dangerous, and to hopefully be able to explain the concepts simply, so I want to write them down here before I forget.
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# E6000 hinges
|
||||||
title = "E6000 hinges"
|
|
||||||
weight = 2
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I love Goop/E6000 glue, it's very versatile and makes for a great bond.
|
I love Goop/E6000 glue, it's very versatile and makes for a great bond.
|
||||||
However, do remember to work with it outside, as it is not safe to breathe.
|
However, do remember to work with it outside, as it is not safe to breathe.
|
||||||
One of the coolest things you can do with it is make hinges, for control surfaces as well as for any hatches you may have.
|
One of the coolest things you can do with it is make hinges, for control surfaces as well as for any hatches you may have.
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
+++
|
# FPV frequency chart
|
||||||
title = "FPV frequency chart"
|
|
||||||
weight = 3
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
If you're curious about which frequencies to use for video when there are multiple people flying FPV, as well as which bands are used by various manufacturers, here's a handy chart:
|
If you're curious about which frequencies to use for video when there are multiple people flying FPV, as well as which bands are used by various manufacturers, here's a handy chart:
|
||||||
|
|
||||||
[![FPV frequency chart](../../resources/48cfa1097ca847c5a9ff8229005e7f50.png)](../../resources/48cfa1097ca847c5a9ff8229005e7f50.png)
|
[![FPV frequency chart](/resources/48cfa1097ca847c5a9ff8229005e7f50.png)](/resources/48cfa1097ca847c5a9ff8229005e7f50.png)
|
||||||
|
|
||||||
It was made by [5zero7 RC](https://youtu.be/wScS5XloviM) with information from [a Propwashed article](https://www.propwashed.com/video-frequency-management/).
|
It was made by [5zero7 RC](https://youtu.be/wScS5XloviM) with information from [a Propwashed article](https://www.propwashed.com/video-frequency-management/).
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# General RC tips
|
||||||
title = "General RC tips"
|
|
||||||
weight = 4
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
These are general tips for building RC planes/quads/whatever:
|
These are general tips for building RC planes/quads/whatever:
|
||||||
|
|
||||||
* Propellers have a direction: The top usually has letters like, for example, "6040" (which denotes the size and pitch of the propeller), and the top needs to always point towards where the plane will be flying (the front). No matter if you have a pusher or puller, the top of the propeller needs to be pointing forward.
|
* Propellers have a direction: The top usually has letters like, for example, "6040" (which denotes the size and pitch of the propeller), and the top needs to always point towards where the plane will be flying (the front). No matter if you have a pusher or puller, the top of the propeller needs to be pointing forward.
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
+++
|
# Getting uninverted SBUS on a no-name FrSky-compatible receiver
|
||||||
title = "Getting uninverted SBUS on a no-name FrSky-compatible receiver"
|
|
||||||
weight = 5
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I got an [RC receiver](https://www.banggood.com/2_4G-8CH-D8-Mini-FrSky-Compatibel-Receiver-With-PWM-PPM-SBUS-Output-p-1140478.html?rmmds=myorder&cur_warehouse=CN) from Banggood. There's uninverted SBUS on this pad:
|
I got an [RC receiver](https://www.banggood.com/2_4G-8CH-D8-Mini-FrSky-Compatibel-Receiver-With-PWM-PPM-SBUS-Output-p-1140478.html?rmmds=myorder&cur_warehouse=CN) from Banggood. There's uninverted SBUS on this pad:
|
||||||
|
|
||||||
[![rc-sbus.jpg](../../resources/ccc7571db5d147328860077fdc0aa745.jpg)](../../resources/ccc7571db5d147328860077fdc0aa745.jpg)
|
[![rc-sbus.jpg](/resources/ccc7571db5d147328860077fdc0aa745.jpg)](/resources/ccc7571db5d147328860077fdc0aa745.jpg)
|
||||||
|
|
||||||
To break this out to the SBUS pad, I had to remove/bridge the resistor that is circled in the image, and remove/bridge the FET on the other side:
|
To break this out to the SBUS pad, I had to remove/bridge the resistor that is circled in the image, and remove/bridge the FET on the other side:
|
||||||
|
|
||||||
[![rc-sbus-mosfet.jpg](../../resources/1b0f508a533e45b496c6636d49161b0c.jpg)](../../resources/1b0f508a533e45b496c6636d49161b0c.jpg)
|
[![rc-sbus-mosfet.jpg](/resources/1b0f508a533e45b496c6636d49161b0c.jpg)](/resources/1b0f508a533e45b496c6636d49161b0c.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
+++
|
# Getting uninverted SBUS/SmartPort on the FrSky XSR receiver
|
||||||
title = "Getting uninverted SBUS/SmartPort on the FrSky XSR receiver"
|
|
||||||
weight = 6
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
To get uninverted SBUS/SmartPort on the FrSky XSR/X4RS receiver, you can repurpose the CPPM pad.
|
To get uninverted SBUS/SmartPort on the FrSky XSR/X4RS receiver, you can repurpose the CPPM pad.
|
||||||
Remove the two small resistors shown in the image, and solder the two lower pads (together) to either the CPPM pad or the MOSFET pin shown in the photo:
|
Remove the two small resistors shown in the image, and solder the two lower pads (together) to either the CPPM pad or the MOSFET pin shown in the photo:
|
||||||
|
|
||||||
[![xsr-sbus.jpeg](../../resources/f86da9a7aac1413ebd77825897164f7f.jpg)](../../resources/f86da9a7aac1413ebd77825897164f7f.jpg)
|
[![xsr-sbus.jpeg](/resources/f86da9a7aac1413ebd77825897164f7f.jpg)](/resources/f86da9a7aac1413ebd77825897164f7f.jpg)
|
||||||
|
|
||||||
They should be soldered like this (remember to solder both resistor pads together):
|
They should be soldered like this (remember to solder both resistor pads together):
|
||||||
|
|
||||||
[![xsr-sbus2.jpeg](../../resources/815576429ece43789dbc70dfd33517a1.jpg)](../../resources/815576429ece43789dbc70dfd33517a1.jpg)
|
[![xsr-sbus2.jpeg](/resources/815576429ece43789dbc70dfd33517a1.jpg)](/resources/815576429ece43789dbc70dfd33517a1.jpg)
|
||||||
|
|
||||||
Now the CPPM pad will be uninverted SBUS/SmartPort instead.
|
Now the CPPM pad will be uninverted SBUS/SmartPort instead.
|
||||||
It seems to be a bit of a gamble whether you get SBUS or SmartPort, it might be firmware-dependent.
|
It seems to be a bit of a gamble whether you get SBUS or SmartPort, it might be firmware-dependent.
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# INAV tuning tips
|
||||||
title = "INAV tuning tips"
|
|
||||||
weight = 7
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
Here are some general INAV tuning tips and things I've learned throughout my builds. Keep in mind that *these only apply to wings* (and maybe planes), not quads:
|
Here are some general INAV tuning tips and things I've learned throughout my builds. Keep in mind that *these only apply to wings* (and maybe planes), not quads:
|
||||||
|
|
||||||
* To make turns in automatic modes smoother, use `set nav_fw_control_smoothness = 8`.
|
* To make turns in automatic modes smoother, use `set nav_fw_control_smoothness = 8`.
|
||||||
|
@ -1,23 +1,17 @@
|
|||||||
+++
|
# Contents
|
||||||
title = "Drone stuff"
|
|
||||||
weight = 3
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
Click on a link in the list below to go to that page:
|
Click on a link in the list below to go to that page:
|
||||||
|
|
||||||
1. [A simple guide to PID control](../../drone-stuff/a-simple-guide-to-pid-control)
|
1. [A simple guide to PID control](../../drone-stuff/a-simple-guide-to-pid-control.html)
|
||||||
1. [E6000 hinges](../../drone-stuff/e6000-hinges)
|
1. [E6000 hinges](../../drone-stuff/e6000-hinges.html)
|
||||||
1. [FPV frequency chart](../../drone-stuff/fpv-frequency-chart)
|
1. [FPV frequency chart](../../drone-stuff/fpv-frequency-chart.html)
|
||||||
1. [General RC tips](../../drone-stuff/general-rc-tips)
|
1. [General RC tips](../../drone-stuff/general-rc-tips.html)
|
||||||
1. [Getting uninverted SBUS on a no-name FrSky-compatible receiver](../../drone-stuff/getting-uninverted-sbus-on-a-no-name-frsky-compatible-receiver)
|
1. [Getting uninverted SBUS on a no-name FrSky-compatible receiver](../../drone-stuff/getting-uninverted-sbus-on-a-no-name-frsky-compatible-receiver.html)
|
||||||
1. [Getting uninverted SBUS/SmartPort on the FrSky XSR receiver](../../drone-stuff/getting-uninverted-sbus-smartport-on-the-frsky-xsr-receiver)
|
1. [Getting uninverted SBUS/SmartPort on the FrSky XSR receiver](../../drone-stuff/getting-uninverted-sbus-smartport-on-the-frsky-xsr-receiver.html)
|
||||||
1. [INAV tuning tips](../../drone-stuff/inav-tuning-tips)
|
1. [INAV tuning tips](../../drone-stuff/inav-tuning-tips.html)
|
||||||
1. [Miscellaneous](../../drone-stuff/miscellaneous)
|
1. [Miscellaneous](../../drone-stuff/miscellaneous.html)
|
||||||
1. [Omnibus F4 V3 pinout](../../drone-stuff/omnibus-f4-v3-pinout)
|
1. [Omnibus F4 V3 pinout](../../drone-stuff/omnibus-f4-v3-pinout.html)
|
||||||
1. [Omnibus F4 pro servo diode](../../drone-stuff/omnibus-f4-pro-servo-diode)
|
1. [Omnibus F4 pro servo diode](../../drone-stuff/omnibus-f4-pro-servo-diode.html)
|
||||||
1. [QGroundControl to Mission Planner conversion script](../../drone-stuff/qgroundcontrol-to-mission-planner-conversion-script)
|
1. [QGroundControl to Mission Planner conversion script](../../drone-stuff/qgroundcontrol-to-mission-planner-conversion-script.html)
|
||||||
1. [Transmitter external module pinout](../../drone-stuff/transmitter-external-module-pinout)
|
1. [Transmitter external module pinout](../../drone-stuff/transmitter-external-module-pinout.html)
|
||||||
1. [Transportable C1 Chaser](../../drone-stuff/transportable-c1-chaser)
|
1. [Transportable C1 Chaser](../../drone-stuff/transportable-c1-chaser.html)
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Miscellaneous
|
||||||
title = "Miscellaneous"
|
|
||||||
weight = 8
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
This is a bunch of miscellaneous info that wouldn't fit anywhere else:
|
This is a bunch of miscellaneous info that wouldn't fit anywhere else:
|
||||||
|
|
||||||
- The ZOHD Dart 250g with the stock motor draws 4.5A on 2S with the 5x5 propeller. It draws the same amperage at exactly 75% throttle with a 3S battery and the same propeller.
|
- The ZOHD Dart 250g with the stock motor draws 4.5A on 2S with the 5x5 propeller. It draws the same amperage at exactly 75% throttle with a 3S battery and the same propeller.
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
+++
|
# Omnibus F4 pro servo diode
|
||||||
title = "Omnibus F4 pro servo diode"
|
|
||||||
weight = 10
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
To isolate the servo 5V rail from the controller's 5V power supply, remove this diode:
|
To isolate the servo 5V rail from the controller's 5V power supply, remove this diode:
|
||||||
|
|
||||||
[![a435bcae86912205b6fac41731285b8d.png](../../resources/6d668e05d8a54580966b94a752f3b7db.png)](../../resources/6d668e05d8a54580966b94a752f3b7db.png)
|
[![a435bcae86912205b6fac41731285b8d.png](/resources/6d668e05d8a54580966b94a752f3b7db.png)](/resources/6d668e05d8a54580966b94a752f3b7db.png)
|
||||||
|
|
||||||
Now the servos' 5V rail can be powered from another 5V supply to avoid servo current backflow into the FC.
|
Now the servos' 5V rail can be powered from another 5V supply to avoid servo current backflow into the FC.
|
||||||
|
|
||||||
There's also a [schematic for this FC](../../resources/805930c3bedc4393ba947f0e0bfa369d.pdf).
|
There's also a [schematic for this FC](/resources/805930c3bedc4393ba947f0e0bfa369d.pdf).
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
+++
|
# Omnibus F4 V3 pinout
|
||||||
title = "Omnibus F4 V3 pinout"
|
|
||||||
weight = 9
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
This is the pinout of the Omnibus F4 V3:
|
This is the pinout of the Omnibus F4 V3:
|
||||||
|
|
||||||
[![53b3161d509dcc7bbfb43c89b16b0bae.png](../../resources/99f5c91454204c1d9740a8d9b876833b.png)](../../resources/99f5c91454204c1d9740a8d9b876833b.png)
|
[![53b3161d509dcc7bbfb43c89b16b0bae.png](/resources/99f5c91454204c1d9740a8d9b876833b.png)](/resources/99f5c91454204c1d9740a8d9b876833b.png)
|
||||||
|
|
||||||
Also:
|
Also:
|
||||||
|
|
||||||
![omnibus-f4-v5-pinout2.jpg](../../resources/410f3ce004c64fe9af68bfd6856d3e53.jpg)
|
![omnibus-f4-v5-pinout2.jpg](/resources/410f3ce004c64fe9af68bfd6856d3e53.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# QGroundControl to Mission Planner conversion script
|
||||||
title = "QGroundControl to Mission Planner conversion script"
|
|
||||||
weight = 11
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
If you have a parameter dump from QGroundControl, I wrote a small script that will convert it to a Mission Planner compatible file. You can also use [Parachute](https://gitlab.com/stavros/parachute) to do your backups/restores/conversions.
|
If you have a parameter dump from QGroundControl, I wrote a small script that will convert it to a Mission Planner compatible file. You can also use [Parachute](https://gitlab.com/stavros/parachute) to do your backups/restores/conversions.
|
||||||
|
|
||||||
Just save this script somewhere as `convert_qgc_params` and run it as `./convert_qgc_params <qgc params> <output file>`:
|
Just save this script somewhere as `convert_qgc_params` and run it as `./convert_qgc_params <qgc params> <output file>`:
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Transmitter external module pinout
|
||||||
title = "Transmitter external module pinout"
|
|
||||||
weight = 12
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
The transmitter (Taranis, Jumper, RadioMaster, etc) pinout is, from top to bottom:
|
The transmitter (Taranis, Jumper, RadioMaster, etc) pinout is, from top to bottom:
|
||||||
|
|
||||||
* PPM
|
* PPM
|
||||||
@ -14,7 +10,7 @@ The transmitter (Taranis, Jumper, RadioMaster, etc) pinout is, from top to botto
|
|||||||
|
|
||||||
It's illustrated in this photo:
|
It's illustrated in this photo:
|
||||||
|
|
||||||
[![pinout.jpeg](../../resources/72d23239af1541d4b170271c1e9e21eb.jpg)](../../resources/72d23239af1541d4b170271c1e9e21eb.jpg)
|
[![pinout.jpeg](/resources/72d23239af1541d4b170271c1e9e21eb.jpg)](/resources/72d23239af1541d4b170271c1e9e21eb.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Transportable C1 Chaser
|
||||||
title = "Transportable C1 Chaser"
|
|
||||||
weight = 13
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I have a [C1 Chaser](https://www.banggood.com/C1-Chaser-1200mm-Wingspan-EPO-Flying-Wing-FPV-Racer-Aircraft-RC-Airplane-KIT-p-1102080.html?custlinkid=667416&p=6W16207412782201611V), and it's a fantastic wing.
|
I have a [C1 Chaser](https://www.banggood.com/C1-Chaser-1200mm-Wingspan-EPO-Flying-Wing-FPV-Racer-Aircraft-RC-Airplane-KIT-p-1102080.html?custlinkid=667416&p=6W16207412782201611V), and it's a fantastic wing.
|
||||||
It flies great, and is very efficient. The only problem I had with it was that it's too long to easily carry around, as it has a 1.2m wingspan.
|
It flies great, and is very efficient. The only problem I had with it was that it's too long to easily carry around, as it has a 1.2m wingspan.
|
||||||
|
|
||||||
@ -19,10 +15,10 @@ If you find the spar has too much jiggle, I've found that applying some CA glue
|
|||||||
|
|
||||||
I've cut three straws to length, sanded the straws and the spar channel a little with coarse sandpaper, and glued the former in the latter, as you can see here (the straw in the photo is not cut to length yet):
|
I've cut three straws to length, sanded the straws and the spar channel a little with coarse sandpaper, and glued the former in the latter, as you can see here (the straw in the photo is not cut to length yet):
|
||||||
|
|
||||||
[![](../../resources/5ac6bff04962497083b8403ed0fded98.jpg)](../../resources/5ac6bff04962497083b8403ed0fded98.jpg)
|
[![](/resources/5ac6bff04962497083b8403ed0fded98.jpg)](/resources/5ac6bff04962497083b8403ed0fded98.jpg)
|
||||||
|
|
||||||
|
|
||||||
[![](../../resources/65ff483180ad483795b32d0b65f72613.jpg)](../../resources/65ff483180ad483795b32d0b65f72613.jpg)
|
[![](/resources/65ff483180ad483795b32d0b65f72613.jpg)](/resources/65ff483180ad483795b32d0b65f72613.jpg)
|
||||||
|
|
||||||
Make sure to leave a few mm from the inside edge of the wing (so the straw doesn't touch the edge, again not pictured in the photo), so the spar's edge doesn't rub against the straw, to avoid splitting it.
|
Make sure to leave a few mm from the inside edge of the wing (so the straw doesn't touch the edge, again not pictured in the photo), so the spar's edge doesn't rub against the straw, to avoid splitting it.
|
||||||
Also, leave the spar in the straws while gluing, so the straws don't lose their shape (but make sure you don't get glue on the spar and end up gluing it to the straw).
|
Also, leave the spar in the straws while gluing, so the straws don't lose their shape (but make sure you don't get glue on the spar and end up gluing it to the straw).
|
||||||
@ -31,7 +27,7 @@ For glue, I use [E6000](https://www.banggood.com/ZHANLIDA-152550ml-E6000-B6000-A
|
|||||||
|
|
||||||
This is what the final result will look like:
|
This is what the final result will look like:
|
||||||
|
|
||||||
[![](../../resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)](../../resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)
|
[![](/resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)](/resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)
|
||||||
|
|
||||||
|
|
||||||
## Wings
|
## Wings
|
||||||
@ -44,7 +40,7 @@ Already, the notch the C1 has stops the wing from rotating up, but it does not s
|
|||||||
Second, you obviously need the wing to be stable against left/right motion, or it will slide off the spar.
|
Second, you obviously need the wing to be stable against left/right motion, or it will slide off the spar.
|
||||||
To solve these problems, I [designed a simple connector with two halves](https://cad.onshape.com/documents/bd7ed4d575e32e06d46234b6/w/ab2adb2ae56e261604342410/e/ad8c70c01b2f8865eb84f5c6), one of which goes onto the fuselage and one onto the wing:
|
To solve these problems, I [designed a simple connector with two halves](https://cad.onshape.com/documents/bd7ed4d575e32e06d46234b6/w/ab2adb2ae56e261604342410/e/ad8c70c01b2f8865eb84f5c6), one of which goes onto the fuselage and one onto the wing:
|
||||||
|
|
||||||
[![](../../resources/dd331e351cd0492794619526ccb89a3f.jpg)](../../resources/dd331e351cd0492794619526ccb89a3f.jpg)
|
[![](/resources/dd331e351cd0492794619526ccb89a3f.jpg)](/resources/dd331e351cd0492794619526ccb89a3f.jpg)
|
||||||
|
|
||||||
The connector has two components, one is a cylindrical channel for a carbon tube (which you can glue to one of the pieces, as in the photo) that stops the wing from rotating around the spar, and the other is a channel for an o-ring, which keeps the two halves from moving left to right.
|
The connector has two components, one is a cylindrical channel for a carbon tube (which you can glue to one of the pieces, as in the photo) that stops the wing from rotating around the spar, and the other is a channel for an o-ring, which keeps the two halves from moving left to right.
|
||||||
|
|
||||||
@ -57,7 +53,7 @@ Also, make sure to not use glue the part of the connector that's not going to be
|
|||||||
|
|
||||||
This is the end result:
|
This is the end result:
|
||||||
|
|
||||||
[![](../../resources/b765e8d8e3db4eceaad1f33862fb7bcc.jpg)](../../resources/b765e8d8e3db4eceaad1f33862fb7bcc.jpg)
|
[![](/resources/b765e8d8e3db4eceaad1f33862fb7bcc.jpg)](/resources/b765e8d8e3db4eceaad1f33862fb7bcc.jpg)
|
||||||
|
|
||||||
To mount the wings, just insert the spar into the fuselage, insert the wings (making sure both tubes go into their respective holes), and place the o-ring into both halves of the connector.
|
To mount the wings, just insert the spar into the fuselage, insert the wings (making sure both tubes go into their respective holes), and place the o-ring into both halves of the connector.
|
||||||
That gives you a secure and quick assembly.
|
That gives you a secure and quick assembly.
|
||||||
@ -70,12 +66,12 @@ The last part is securing the vertical stabilizers. I did this with [two very sm
|
|||||||
First, press the stabilizer-side part (the Π-shaped one) onto the stabilizer on the place where you want it (I put it as shown in the photo), and cut slightly *inside* the indentation it creates.
|
First, press the stabilizer-side part (the Π-shaped one) onto the stabilizer on the place where you want it (I put it as shown in the photo), and cut slightly *inside* the indentation it creates.
|
||||||
Then, glue it into place:
|
Then, glue it into place:
|
||||||
|
|
||||||
[![](../../resources/9e4279dbc32a4c28886b8dbb5e308f86.jpg)](../../resources/9e4279dbc32a4c28886b8dbb5e308f86.jpg)
|
[![](/resources/9e4279dbc32a4c28886b8dbb5e308f86.jpg)](/resources/9e4279dbc32a4c28886b8dbb5e308f86.jpg)
|
||||||
|
|
||||||
Then, insert the fuselage-side part (the inverted-T-shaped one) into the stabilizer-side part, align the stabilizer with the fuselage and press it in, to create the indentation onto the fuselage EPO, so you know where to cut.
|
Then, insert the fuselage-side part (the inverted-T-shaped one) into the stabilizer-side part, align the stabilizer with the fuselage and press it in, to create the indentation onto the fuselage EPO, so you know where to cut.
|
||||||
Insert the part into the cut and glue it in:
|
Insert the part into the cut and glue it in:
|
||||||
|
|
||||||
[![](../../resources/ac25d2c2031441549f266d83ed6ac030.jpg)](../../resources/ac25d2c2031441549f266d83ed6ac030.jpg)
|
[![](/resources/ac25d2c2031441549f266d83ed6ac030.jpg)](/resources/ac25d2c2031441549f266d83ed6ac030.jpg)
|
||||||
|
|
||||||
When everything has set, you can install the stabilizers by simply slotting the two parts into each other and mounting the wing.
|
When everything has set, you can install the stabilizers by simply slotting the two parts into each other and mounting the wing.
|
||||||
That way, the stabilizer isn't going anywhere, and you can install and remove it very quickly.
|
That way, the stabilizer isn't going anywhere, and you can install and remove it very quickly.
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
+++
|
|
||||||
title = "Maker things"
|
|
||||||
weight = 4
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
Click on a link in the list below to go to that page:
|
|
||||||
|
|
||||||
1. [Battery discharge curves](../../maker-things/battery-discharge-curves)
|
|
||||||
1. [Electronics tips](../../maker-things/electronics-tips)
|
|
||||||
1. [GRBL_ESP32 tips](../../maker-things/grbl-esp32-tips)
|
|
||||||
1. [How to properly level your 3D printer](../../maker-things/how-to-properly-level-your-3d-printer)
|
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Battery discharge curves
|
||||||
title = "Battery discharge curves"
|
|
||||||
weight = 1
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I wanted to buy some Sony VTC6 batteries, and I was wary of fakes, so I wrote a [battery discharge calculator](https://gitlab.com/stavros/assault-and-battery/) with an associated hardware component (just a simple current and voltage sensor). I then took some measurements of my known-good batteries, and the new ones I bought.
|
I wanted to buy some Sony VTC6 batteries, and I was wary of fakes, so I wrote a [battery discharge calculator](https://gitlab.com/stavros/assault-and-battery/) with an associated hardware component (just a simple current and voltage sensor). I then took some measurements of my known-good batteries, and the new ones I bought.
|
||||||
|
|
||||||
The methodology was the following: I connected the battery to the sensor, and the sensor to a configurable load. I set the load to draw a certain amount of amps until it reached a cutoff voltage, and then to stop. I then plotted mAh drawn versus voltage, as well as amps drawn.
|
The methodology was the following: I connected the battery to the sensor, and the sensor to a configurable load. I set the load to draw a certain amount of amps until it reached a cutoff voltage, and then to stop. I then plotted mAh drawn versus voltage, as well as amps drawn.
|
||||||
@ -16,13 +12,13 @@ Here are the graphs:
|
|||||||
|
|
||||||
This is a genuine (as far as I can tell) Sony VTC6, fairly used in high amp draw situations (I use it in my plane), in a 3S configuration:
|
This is a genuine (as far as I can tell) Sony VTC6, fairly used in high amp draw situations (I use it in my plane), in a 3S configuration:
|
||||||
|
|
||||||
![curve_old-3s_2021-09-08_02-53-53.png](../../resources/71aaa540c06d48e59559d05627ceffa4.png)
|
![curve_old-3s_2021-09-08_02-53-53.png](/resources/71aaa540c06d48e59559d05627ceffa4.png)
|
||||||
|
|
||||||
You can see that it output around 2600 mAh before I stopped it at 3V, which is quite good.
|
You can see that it output around 2600 mAh before I stopped it at 3V, which is quite good.
|
||||||
|
|
||||||
Here's a brand new genuine VTC6, again in a 3S configuration:
|
Here's a brand new genuine VTC6, again in a 3S configuration:
|
||||||
|
|
||||||
![curve_new-vtc6-3s_2021-09-09_13-06-52.png](../../resources/9a2ed9fc5d474edfab2ec610e994c059.png)
|
![curve_new-vtc6-3s_2021-09-09_13-06-52.png](/resources/9a2ed9fc5d474edfab2ec610e994c059.png)
|
||||||
|
|
||||||
This time I ran it all the way down to 2.8, and you can see it output the full 3000 mAh.
|
This time I ran it all the way down to 2.8, and you can see it output the full 3000 mAh.
|
||||||
|
|
||||||
@ -31,13 +27,13 @@ This time I ran it all the way down to 2.8, and you can see it output the full 3
|
|||||||
|
|
||||||
This is a pretty blatantly fake "Sony VTC6", brand new, in a 2S configuration:
|
This is a pretty blatantly fake "Sony VTC6", brand new, in a 2S configuration:
|
||||||
|
|
||||||
![curve_new-vtc6_2021-09-08_18-54-58.png](../../resources/2d20e92b9b2247e39de7458e0b341d45.png)
|
![curve_new-vtc6_2021-09-08_18-54-58.png](/resources/2d20e92b9b2247e39de7458e0b341d45.png)
|
||||||
|
|
||||||
The performance falls off a cliff after around 3.6V, and it only outputs 1600 mAh before it dies completely.
|
The performance falls off a cliff after around 3.6V, and it only outputs 1600 mAh before it dies completely.
|
||||||
|
|
||||||
Trying to draw 6-7A is even more spectacular (and it gets very hot to the touch):
|
Trying to draw 6-7A is even more spectacular (and it gets very hot to the touch):
|
||||||
|
|
||||||
![curve_new-vtc6-6a_2021-09-08_23-57-29.png](../../resources/b3a7a012f9d5418e9e2e9867fd23df61.png)
|
![curve_new-vtc6-6a_2021-09-08_23-57-29.png](/resources/b3a7a012f9d5418e9e2e9867fd23df61.png)
|
||||||
|
|
||||||
Notice the huge voltage sag right as the load starts drawing.
|
Notice the huge voltage sag right as the load starts drawing.
|
||||||
|
|
||||||
@ -45,7 +41,7 @@ Notice the huge voltage sag right as the load starts drawing.
|
|||||||
|
|
||||||
This is a white CNHL 4S 4000 mAh LiPo battery, slightly used:
|
This is a white CNHL 4S 4000 mAh LiPo battery, slightly used:
|
||||||
|
|
||||||
![curve_cnhl-4ah-used_2021-09-11_20-29-53.png](../../resources/ba59455ecc2946fd8b2f001dfa32378a.png)
|
![curve_cnhl-4ah-used_2021-09-11_20-29-53.png](/resources/ba59455ecc2946fd8b2f001dfa32378a.png)
|
||||||
|
|
||||||
You can see that it's pretty decent, outputting nearly all of its nominal mAh, decently linearly, with a slightly faster drop after 3.7 V.
|
You can see that it's pretty decent, outputting nearly all of its nominal mAh, decently linearly, with a slightly faster drop after 3.7 V.
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Electronics tips
|
||||||
title = "Electronics tips"
|
|
||||||
weight = 2
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
This page contains various notes and tips about electronics.
|
This page contains various notes and tips about electronics.
|
||||||
|
|
||||||
## Decoupling capacitors
|
## Decoupling capacitors
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# GRBL_ESP32 tips
|
||||||
title = "GRBL_ESP32 tips"
|
|
||||||
weight = 3
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I made a CNC that uses [a custom board I designed](https://gitlab.com/stavros/esp32-cnc), and which runs [GRBL_ESP32](https://github.com/bdring/Grbl_Esp32/). I couldn't find the following info easily, so I've written it here:
|
I made a CNC that uses [a custom board I designed](https://gitlab.com/stavros/esp32-cnc), and which runs [GRBL_ESP32](https://github.com/bdring/Grbl_Esp32/). I couldn't find the following info easily, so I've written it here:
|
||||||
|
|
||||||
- You can specify the enable pin for the drivers with the `STEPPERS_DISABLE_PIN` option. This should be used like `#define STEPPERS_DISABLE_PIN GPIO_NUM_2`.
|
- You can specify the enable pin for the drivers with the `STEPPERS_DISABLE_PIN` option. This should be used like `#define STEPPERS_DISABLE_PIN GPIO_NUM_2`.
|
||||||
|
@ -1,28 +1,24 @@
|
|||||||
+++
|
# How to properly level your 3D printer
|
||||||
title = "How to properly level your 3D printer"
|
|
||||||
weight = 4
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I see many people on our 3D printer Facebook group ask about adhesion issues with their printer. 99% of the time, this is because they have leveled improperly, and not because of the bed material.
|
I see many people on our 3D printer Facebook group ask about adhesion issues with their printer. 99% of the time, this is because they have leveled improperly, and not because of the bed material.
|
||||||
|
|
||||||
I have taken photos of filament when the nozzle was leveled at various heights from the bed. I greatly recommend [an adjustable Z endstop](https://www.thingiverse.com/thing:1370547), which will save you lots of time when leveling/tramming.
|
I have taken photos of filament when the nozzle was leveled at various heights from the bed. I greatly recommend [an adjustable Z endstop](https://www.thingiverse.com/thing:1370547), which will save you lots of time when leveling/tramming.
|
||||||
|
|
||||||
In this first photo, I have leveled too high (meaning the nozzle is too high compared to the bed). You can see that the filament is cylindrical, which means that it has just dropped onto the bed (or minimally touched it), leading to very poor adhesion. You can imagine that, if the filament is just dropped onto the bed, it won’t adhere well:
|
In this first photo, I have leveled too high (meaning the nozzle is too high compared to the bed). You can see that the filament is cylindrical, which means that it has just dropped onto the bed (or minimally touched it), leading to very poor adhesion. You can imagine that, if the filament is just dropped onto the bed, it won’t adhere well:
|
||||||
|
|
||||||
![too-high.jpg](../../resources/576a1fedf9f144a69fe262866e9f268a.jpg)
|
![too-high.jpg](/resources/576a1fedf9f144a69fe262866e9f268a.jpg)
|
||||||
|
|
||||||
The next photo is also a bit too high. It’s not as high as the previous photo, so it has partially adhered, but there are gaps between the rows and adhesion still won’t be great:
|
The next photo is also a bit too high. It’s not as high as the previous photo, so it has partially adhered, but there are gaps between the rows and adhesion still won’t be great:
|
||||||
|
|
||||||
![too-high-2.jpg](../../resources/57cca138661644a99f3e9422665cbbb5.jpg)
|
![too-high-2.jpg](/resources/57cca138661644a99f3e9422665cbbb5.jpg)
|
||||||
|
|
||||||
The next photo has been leveled too low. The filament is mushed against the bed, but it’s mushed too much, leading to transparent-looking rows of filament. The specific filament I’m using tends to look transparent even when leveled properly, but this is too low regardless:
|
The next photo has been leveled too low. The filament is mushed against the bed, but it’s mushed too much, leading to transparent-looking rows of filament. The specific filament I’m using tends to look transparent even when leveled properly, but this is too low regardless:
|
||||||
|
|
||||||
![too-low.jpg](../../resources/1aac14963f294f74b1288a02e24eaead.jpg)
|
![too-low.jpg](/resources/1aac14963f294f74b1288a02e24eaead.jpg)
|
||||||
|
|
||||||
For the last photo, I’ve leveled it pretty much perfectly. You can see that the rows aren’t cylindrical at all, instead they’re long strips that are touching each other properly and don’t look too transparent. If you insert a piece of paper between the bed and the nozzle, you will be able to move it with some difficulty, but it won’t move very freely.
|
For the last photo, I’ve leveled it pretty much perfectly. You can see that the rows aren’t cylindrical at all, instead they’re long strips that are touching each other properly and don’t look too transparent. If you insert a piece of paper between the bed and the nozzle, you will be able to move it with some difficulty, but it won’t move very freely.
|
||||||
|
|
||||||
![just-perfect.jpg](../../resources/d95ef0cfd696407b82734616ca963205.jpg)
|
![just-perfect.jpg](/resources/d95ef0cfd696407b82734616ca963205.jpg)
|
||||||
|
|
||||||
There you have it! If your filament looks cylindrical, follow your printer’s manual to reduce the distance between bed and nozzle. If it looks transparent and missing in places completely, you need to increase the distance. If it looks mushed and has the proper color, and the rows are touching each other just so, you’re perfect and ready to print!
|
There you have it! If your filament looks cylindrical, follow your printer’s manual to reduce the distance between bed and nozzle. If it looks transparent and missing in places completely, you need to increase the distance. If it looks mushed and has the proper color, and the rows are touching each other just so, you’re perfect and ready to print!
|
||||||
|
|
||||||
|
8
content/maker-things/index.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Contents
|
||||||
|
|
||||||
|
Click on a link in the list below to go to that page:
|
||||||
|
|
||||||
|
1. [Battery discharge curves](../../maker-things/battery-discharge-curves.html)
|
||||||
|
1. [Electronics tips](../../maker-things/electronics-tips.html)
|
||||||
|
1. [GRBL_ESP32 tips](../../maker-things/grbl-esp32-tips.html)
|
||||||
|
1. [How to properly level your 3D printer](../../maker-things/how-to-properly-level-your-3d-printer.html)
|
@ -1,12 +0,0 @@
|
|||||||
+++
|
|
||||||
title = "Model build notes"
|
|
||||||
weight = 5
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
Click on a link in the list below to go to that page:
|
|
||||||
|
|
||||||
1. [Build notes for the FT Mighty Mini Arrow](../../model-build-notes/build-notes-for-the-ft-mighty-mini-arrow)
|
|
||||||
1. [Mini Drak build condensed instructions](../../model-build-notes/mini-drak-build-condensed-instructions)
|
|
@ -1,12 +1,8 @@
|
|||||||
+++
|
# Build notes for the FT Mighty Mini Arrow
|
||||||
title = "Build notes for the FT Mighty Mini Arrow"
|
|
||||||
weight = 1
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
These notes are a condensed version of the [FT Arrow build video](https://www.youtube.com/watch?v=cD2Ca2oskVs).
|
These notes are a condensed version of the [FT Arrow build video](https://www.youtube.com/watch?v=cD2Ca2oskVs).
|
||||||
|
|
||||||
![maxresdefault.jpeg](../../resources/d4819ca1c3d0490daaa12f62af09aa00.jpg)
|
![maxresdefault.jpeg](/resources/d4819ca1c3d0490daaa12f62af09aa00.jpg)
|
||||||
|
|
||||||
|
|
||||||
## Wings
|
## Wings
|
||||||
|
6
content/model-build-notes/index.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Contents
|
||||||
|
|
||||||
|
Click on a link in the list below to go to that page:
|
||||||
|
|
||||||
|
1. [Build notes for the FT Mighty Mini Arrow](../../model-build-notes/build-notes-for-the-ft-mighty-mini-arrow.html)
|
||||||
|
1. [Mini Drak build condensed instructions](../../model-build-notes/mini-drak-build-condensed-instructions.html)
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Mini Drak build condensed instructions
|
||||||
title = "Mini Drak build condensed instructions"
|
|
||||||
weight = 2
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
Sources:
|
Sources:
|
||||||
|
|
||||||
1. [Håvard's Mini Drak build video](https://www.youtube.com/watch?v=L4_dJxiQUjs)
|
1. [Håvard's Mini Drak build video](https://www.youtube.com/watch?v=L4_dJxiQUjs)
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
+++
|
# Contents
|
||||||
title = "Software"
|
|
||||||
weight = 6
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
Click on a link in the list below to go to that page:
|
Click on a link in the list below to go to that page:
|
||||||
|
|
||||||
1. [Monero GUI syncing stuck with Ledger](../../software/monero-gui-syncing-stuck-with-ledger)
|
1. [Monero GUI syncing stuck with Ledger](../../software/monero-gui-syncing-stuck-with-ledger.html)
|
||||||
1. [Test and format SD cards](../../software/test-and-format-sd-cards)
|
1. [Test and format SD cards](../../software/test-and-format-sd-cards.html)
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Monero GUI syncing stuck with Ledger
|
||||||
title = "Monero GUI syncing stuck with Ledger"
|
|
||||||
weight = 1
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
This is about the Monero desktop GUI, but probably also applies to Monerujo.
|
This is about the Monero desktop GUI, but probably also applies to Monerujo.
|
||||||
|
|
||||||
If you're trying to sync the blockchain with your Ledger device, you might be getting the conflicting messages of "Waiting for daemon to sync" and "Daemon is synchronized", which then just stays there forever and doesn't move.
|
If you're trying to sync the blockchain with your Ledger device, you might be getting the conflicting messages of "Waiting for daemon to sync" and "Daemon is synchronized", which then just stays there forever and doesn't move.
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Test and format SD cards
|
||||||
title = "Test and format SD cards"
|
|
||||||
weight = 2
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
I wrote a short bash script that tests SD cards with [F3](https://3ds.hacks.guide/f3-(linux).html) to see if they're fake, deletes everything on them, creates a new partition table and one exFAT partition on them.
|
I wrote a short bash script that tests SD cards with [F3](https://3ds.hacks.guide/f3-(linux).html) to see if they're fake, deletes everything on them, creates a new partition table and one exFAT partition on them.
|
||||||
|
|
||||||
Here it is:
|
Here it is:
|
||||||
|
BIN
content/static/resources/1aac14963f294f74b1288a02e24eaead.jpg
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
content/static/resources/1b0f508a533e45b496c6636d49161b0c.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
content/static/resources/2d20e92b9b2247e39de7458e0b341d45.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
content/static/resources/410f3ce004c64fe9af68bfd6856d3e53.jpg
Normal file
After Width: | Height: | Size: 326 KiB |
BIN
content/static/resources/48cfa1097ca847c5a9ff8229005e7f50.png
Normal file
After Width: | Height: | Size: 251 KiB |
BIN
content/static/resources/576a1fedf9f144a69fe262866e9f268a.jpg
Normal file
After Width: | Height: | Size: 123 KiB |
BIN
content/static/resources/57cca138661644a99f3e9422665cbbb5.jpg
Normal file
After Width: | Height: | Size: 146 KiB |
BIN
content/static/resources/5ac6bff04962497083b8403ed0fded98.jpg
Normal file
After Width: | Height: | Size: 237 KiB |
BIN
content/static/resources/65ff483180ad483795b32d0b65f72613.jpg
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
content/static/resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg
Normal file
After Width: | Height: | Size: 568 KiB |
BIN
content/static/resources/6d668e05d8a54580966b94a752f3b7db.png
Normal file
After Width: | Height: | Size: 358 KiB |
BIN
content/static/resources/71aaa540c06d48e59559d05627ceffa4.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
content/static/resources/72d23239af1541d4b170271c1e9e21eb.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
content/static/resources/805930c3bedc4393ba947f0e0bfa369d.pdf
Normal file
BIN
content/static/resources/815576429ece43789dbc70dfd33517a1.jpg
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
content/static/resources/99f5c91454204c1d9740a8d9b876833b.png
Normal file
After Width: | Height: | Size: 748 KiB |
BIN
content/static/resources/9a2ed9fc5d474edfab2ec610e994c059.png
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
content/static/resources/9e4279dbc32a4c28886b8dbb5e308f86.jpg
Normal file
After Width: | Height: | Size: 330 KiB |
BIN
content/static/resources/ac25d2c2031441549f266d83ed6ac030.jpg
Normal file
After Width: | Height: | Size: 440 KiB |
BIN
content/static/resources/b3a7a012f9d5418e9e2e9867fd23df61.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
content/static/resources/b765e8d8e3db4eceaad1f33862fb7bcc.jpg
Normal file
After Width: | Height: | Size: 314 KiB |
BIN
content/static/resources/ba59455ecc2946fd8b2f001dfa32378a.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
content/static/resources/ccc7571db5d147328860077fdc0aa745.jpg
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
content/static/resources/d4819ca1c3d0490daaa12f62af09aa00.jpg
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
content/static/resources/d95ef0cfd696407b82734616ca963205.jpg
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
content/static/resources/dd331e351cd0492794619526ccb89a3f.jpg
Normal file
After Width: | Height: | Size: 371 KiB |
BIN
content/static/resources/f86da9a7aac1413ebd77825897164f7f.jpg
Normal file
After Width: | Height: | Size: 96 KiB |
@ -1,11 +0,0 @@
|
|||||||
+++
|
|
||||||
title = "Welcome"
|
|
||||||
weight = 1
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
Click on a link in the list below to go to that page:
|
|
||||||
|
|
||||||
1. [Stavros' notes](../../welcome/stavros-notes)
|
|
5
content/welcome/index.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Contents
|
||||||
|
|
||||||
|
Click on a link in the list below to go to that page:
|
||||||
|
|
||||||
|
1. [Stavros' notes](../../welcome/stavros-notes.html)
|
@ -1,9 +1,5 @@
|
|||||||
+++
|
# Stavros' notes
|
||||||
title = "Stavros' notes"
|
|
||||||
weight = 1
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
Welcome to my notes.
|
Welcome to my notes.
|
||||||
|
|
||||||
This site is autogenerated from a bunch of [Joplin](https://joplinapp.org/) notes.
|
This site is autogenerated from a bunch of [Joplin](https://joplinapp.org/) notes.
|
||||||
@ -19,6 +15,6 @@ Otherwise, enjoy my notes!
|
|||||||
* * *
|
* * *
|
||||||
|
|
||||||
<p style="font-size:80%; font-style: italic">
|
<p style="font-size:80%; font-style: italic">
|
||||||
Last updated on November 20, 2020. For any questions/feedback,
|
Last updated on November 20, 2021. For any questions/feedback,
|
||||||
email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
||||||
</p>
|
</p>
|
||||||
|
240
joplinexport.py
@ -12,6 +12,7 @@ from typing import Dict
|
|||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Set
|
from typing import Set
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
def contains_word(word: str, text: str) -> bool:
|
def contains_word(word: str, text: str) -> bool:
|
||||||
@ -28,21 +29,83 @@ def slugify(text):
|
|||||||
return re.sub(r"[\W_]+", "-", text.lower()).strip("-")
|
return re.sub(r"[\W_]+", "-", text.lower()).strip("-")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class Folder:
|
||||||
|
"""A helper type for a folder."""
|
||||||
|
|
||||||
|
id: str
|
||||||
|
parent_id: str
|
||||||
|
title: str
|
||||||
|
|
||||||
|
def is_private(self) -> bool:
|
||||||
|
"""Return whether this folder is private."""
|
||||||
|
return contains_word("private", self.title)
|
||||||
|
|
||||||
|
def get_url(self) -> str:
|
||||||
|
"""Return the folder's relative URL."""
|
||||||
|
return slugify(self.title)
|
||||||
|
|
||||||
|
def get_summary_line(self, level: int) -> str:
|
||||||
|
"""Get the appropriate summary file line for this folder."""
|
||||||
|
return (" " * (level - 1)) + f"- [{self.title}]({self.get_url()}/index.md)"
|
||||||
|
|
||||||
|
def __lt__(self, other: Union["Folder", "Note"]) -> bool:
|
||||||
|
"""Support comparison, for sorting."""
|
||||||
|
if isinstance(other, Note):
|
||||||
|
# Folders always come before notes.
|
||||||
|
return True
|
||||||
|
return self.title.lower() < other.title.lower()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
"""Pretty-print this class."""
|
||||||
|
return f"Folder: <{self.title}>"
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class Note:
|
class Note:
|
||||||
"""A helper type for a note."""
|
"""A helper type for a note."""
|
||||||
|
|
||||||
id: str
|
id: str
|
||||||
parent_id: str
|
folder: Folder
|
||||||
parent_title: str
|
|
||||||
title: str
|
title: str
|
||||||
body: str
|
body: str
|
||||||
updated_time: datetime
|
updated_time: datetime
|
||||||
tags: List[str] = dataclasses.field(default_factory=list)
|
tags: List[str] = dataclasses.field(default_factory=list)
|
||||||
|
|
||||||
def get_url(self):
|
def is_private(self) -> bool:
|
||||||
|
"""
|
||||||
|
Check whether a note is private.
|
||||||
|
|
||||||
|
This function checks a note's title and tags and returns whether it
|
||||||
|
should be considered private or whether it should be published.
|
||||||
|
"""
|
||||||
|
hidden_keywords = ["private", "wip", "draft"]
|
||||||
|
for keyword in hidden_keywords:
|
||||||
|
if contains_word(keyword, self.title) or keyword in self.tags:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_url(self) -> str:
|
||||||
"""Return the note's relative URL."""
|
"""Return the note's relative URL."""
|
||||||
return slugify(self.parent_title) + "/" + slugify(self.title)
|
return slugify(self.folder.title) + "/" + slugify(self.title)
|
||||||
|
|
||||||
|
def get_summary_line(self, level: int) -> str:
|
||||||
|
"""
|
||||||
|
Get the appropriate summary file line for this note.
|
||||||
|
|
||||||
|
The introduction is level 0, and is treated differently here.
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
" " * (level - 1)
|
||||||
|
) + f"{'- ' if level > 0 else ''}[{self.title}]({self.get_url()}.md)"
|
||||||
|
|
||||||
|
def __lt__(self, other: Union["Folder", "Note"]) -> bool:
|
||||||
|
"""Support comparison, for sorting."""
|
||||||
|
return self.title.lower() < other.title.lower()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
"""Pretty-print this class."""
|
||||||
|
return f"Note: <{self.title}>"
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
@ -65,20 +128,29 @@ class JoplinExporter:
|
|||||||
"""The main exporter class."""
|
"""The main exporter class."""
|
||||||
|
|
||||||
content_dir = Path("content")
|
content_dir = Path("content")
|
||||||
static_dir = Path("static/resources")
|
static_dir = Path("content/static/resources")
|
||||||
joplin_dir = Path.home() / ".config/joplin-desktop"
|
joplin_dir = Path.home() / ".config/joplin-desktop"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.resources: Dict[str, Resource] = {}
|
self.resources: Dict[str, Resource] = {}
|
||||||
self.used_resources: Set[str] = set()
|
self.used_resources: Set[str] = set()
|
||||||
|
|
||||||
|
# A mapping of {"note_id": Note()}.
|
||||||
|
self.note_lookup_dict: Dict[str, Note] = {}
|
||||||
|
|
||||||
|
# A mapping of {"folder_id": Folder()}.
|
||||||
|
self.folders: Dict[str, Folder] = {}
|
||||||
|
|
||||||
|
# A mapping of {"folder_id": [Note(), Note()]}.
|
||||||
|
self.notes: Dict[str, List[Note]] = defaultdict(list)
|
||||||
|
|
||||||
def clean_content_dir(self):
|
def clean_content_dir(self):
|
||||||
"""Reset the content directory to a known state to begin."""
|
"""Reset the content directory to a known state to begin."""
|
||||||
rmtree(self.content_dir)
|
rmtree(self.content_dir, ignore_errors=True)
|
||||||
rmtree(self.static_dir)
|
rmtree(self.static_dir, ignore_errors=True)
|
||||||
self.content_dir.mkdir()
|
self.content_dir.mkdir(parents=True)
|
||||||
self.static_dir.mkdir()
|
self.static_dir.mkdir(parents=True)
|
||||||
with open(self.content_dir / "_index.md", mode="w") as outfile:
|
with open(self.content_dir / "index.md", mode="w") as outfile:
|
||||||
outfile.write('+++\nredirect_to = "welcome/stavros-notes/"\n+++')
|
outfile.write('+++\nredirect_to = "welcome/stavros-notes/"\n+++')
|
||||||
|
|
||||||
def resolve_note_links(self, note: Note) -> str:
|
def resolve_note_links(self, note: Note) -> str:
|
||||||
@ -93,7 +165,7 @@ class JoplinExporter:
|
|||||||
new_url = item_id
|
new_url = item_id
|
||||||
if match.group(2):
|
if match.group(2):
|
||||||
new_url += match.group(2)
|
new_url += match.group(2)
|
||||||
return f"](../../{new_url})"
|
return f"](/{new_url})"
|
||||||
|
|
||||||
return re.sub(r"\]\(:/([a-f0-9]{32})(#.*?)?\)", replacement, note.body)
|
return re.sub(r"\]\(:/([a-f0-9]{32})(#.*?)?\)", replacement, note.body)
|
||||||
|
|
||||||
@ -128,8 +200,14 @@ class JoplinExporter:
|
|||||||
conn = sqlite3.connect(self.joplin_dir / "database.sqlite")
|
conn = sqlite3.connect(self.joplin_dir / "database.sqlite")
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
c.execute("""SELECT id, title FROM folders;""")
|
c.execute("""SELECT id, title, parent_id FROM folders;""")
|
||||||
self.folders = {id: title for id, title in c.fetchall()}
|
self.folders = {
|
||||||
|
id: Folder(id, parent_id, title) for id, title, parent_id in c.fetchall()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.folders = {
|
||||||
|
id: folder for id, folder in self.folders.items() if not folder.is_private()
|
||||||
|
}
|
||||||
|
|
||||||
# Get the tags by ID.
|
# Get the tags by ID.
|
||||||
c.execute("""SELECT id, title FROM tags;""")
|
c.execute("""SELECT id, title FROM tags;""")
|
||||||
@ -152,81 +230,106 @@ class JoplinExporter:
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.execute("""SELECT id, parent_id, title, body, updated_time FROM notes;""")
|
c.execute("""SELECT id, parent_id, title, body, updated_time FROM notes;""")
|
||||||
self.notes = defaultdict(list)
|
|
||||||
self.note_lookup_dict = {}
|
|
||||||
for id, parent_id, title, body, updated_time in c.fetchall():
|
for id, parent_id, title, body, updated_time in c.fetchall():
|
||||||
|
if parent_id not in self.folders:
|
||||||
|
# This note is in a private folder, continue.
|
||||||
|
continue
|
||||||
|
|
||||||
note = Note(
|
note = Note(
|
||||||
id,
|
id,
|
||||||
parent_id,
|
|
||||||
self.folders[parent_id],
|
self.folders[parent_id],
|
||||||
title,
|
title,
|
||||||
body,
|
body,
|
||||||
datetime.fromtimestamp(updated_time / 1000),
|
datetime.fromtimestamp(updated_time / 1000),
|
||||||
tags=note_tags[id],
|
tags=note_tags[id],
|
||||||
)
|
)
|
||||||
self.notes[note.parent_id].append(note)
|
if note.is_private():
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.notes[note.folder.id].append(note)
|
||||||
self.note_lookup_dict[note.id] = note
|
self.note_lookup_dict[note.id] = note
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def write_summary(self):
|
||||||
|
"""Write the SUMMARY.md that mdBook needs."""
|
||||||
|
# We construct a note tree by adding each note into its parent.
|
||||||
|
note_tree: Dict[str, List[Union[Note, Folder]]] = defaultdict(list)
|
||||||
|
|
||||||
|
# The note tree is a list of notes with their parents:
|
||||||
|
# [
|
||||||
|
# [parent1, parent2, note1]
|
||||||
|
# [parent1, parent3, note2]
|
||||||
|
# ]
|
||||||
|
# Then, we sort these by alphabetical order, and we're done.
|
||||||
|
note_tree = []
|
||||||
|
introduction: Optional[Note] = None # The "introduction" note.
|
||||||
|
folders: List[Folder] = list
|
||||||
|
for note_list in self.notes.values():
|
||||||
|
for note in note_list:
|
||||||
|
if note.folder.title == "Welcome":
|
||||||
|
introduction = note
|
||||||
|
continue
|
||||||
|
note_item = [note]
|
||||||
|
item: Union[Folder, Note] = note
|
||||||
|
while True:
|
||||||
|
if isinstance(item, Note):
|
||||||
|
item = item.folder
|
||||||
|
elif isinstance(item, Folder):
|
||||||
|
item = self.folders.get(item.parent_id)
|
||||||
|
if not item:
|
||||||
|
break
|
||||||
|
note_item.insert(0, item)
|
||||||
|
|
||||||
|
# Append the folders to the list if they weren't there before, as that's
|
||||||
|
# the only way this algorithm can generate headlines.
|
||||||
|
if folders != note_item[:-1]:
|
||||||
|
folders = note_item[:-1]
|
||||||
|
note_tree.append(folders)
|
||||||
|
|
||||||
|
note_tree.append(note_item)
|
||||||
|
note_tree.sort()
|
||||||
|
|
||||||
|
# Generate the summary file.
|
||||||
|
items = []
|
||||||
|
for note_list in note_tree:
|
||||||
|
level = len(note_list)
|
||||||
|
if isinstance(note_list[-1], Folder):
|
||||||
|
# The last item in the list is a folder, which means this is a header.
|
||||||
|
items.append(note_list[-1].get_summary_line(level))
|
||||||
|
else:
|
||||||
|
# This is a regular note.
|
||||||
|
note = note_list[-1]
|
||||||
|
print(f"Exporting {note.title}...")
|
||||||
|
items.append(note.get_summary_line(level))
|
||||||
|
|
||||||
|
with (self.content_dir / "SUMMARY.md").open("w") as outfile:
|
||||||
|
outfile.write("# Summary\n\n")
|
||||||
|
# Special-case the introduction.
|
||||||
|
outfile.write(introduction.get_summary_line(0) + "\n")
|
||||||
|
outfile.write("\n".join(items))
|
||||||
|
|
||||||
def export(self):
|
def export(self):
|
||||||
"""Export all the notes to a static site."""
|
"""Export all the notes to a static site."""
|
||||||
self.read_data()
|
self.read_data()
|
||||||
|
|
||||||
# Private notes shouldn't be published.
|
folder_list = sorted(self.folders.values())
|
||||||
folder_list = list(
|
|
||||||
i for i in self.folders.items() if not contains_word("private", i[1])
|
|
||||||
)
|
|
||||||
|
|
||||||
# Sort "Welcome" last.
|
|
||||||
folder_list.sort(
|
|
||||||
key=lambda x: x[1].lower().strip() if x[1] != "Welcome" else "0"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.clean_content_dir()
|
self.clean_content_dir()
|
||||||
|
|
||||||
def is_private(note) -> bool:
|
for folder in folder_list:
|
||||||
"""
|
|
||||||
Check whether a note is private.
|
|
||||||
|
|
||||||
This function checks a note's title and tags and returns whether it
|
|
||||||
should be considered private or whether it should be published.
|
|
||||||
"""
|
|
||||||
hidden_keywords = ["private", "wip", "draft"]
|
|
||||||
for keyword in hidden_keywords:
|
|
||||||
if contains_word(keyword, note.title) or keyword in note.tags:
|
|
||||||
print(
|
|
||||||
f"Note is unpublished, skipping: {folder_title} - {note.title}."
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
for folder_counter, folder in enumerate(folder_list, start=1):
|
|
||||||
folder_id, folder_title = folder
|
|
||||||
dir = self.content_dir / slugify(folder_title)
|
|
||||||
dir.mkdir(parents=True)
|
|
||||||
contents = []
|
contents = []
|
||||||
note_counter = 0
|
dir = self.content_dir / folder.get_url()
|
||||||
for note in sorted(self.notes[folder_id], key=lambda n: n.title):
|
dir.mkdir(parents=True)
|
||||||
if is_private(note):
|
for note in sorted(self.notes[folder.id], key=lambda n: n.title):
|
||||||
print(
|
print(f"Exporting {folder.title} - {note.title}...")
|
||||||
f"Note is unpublished, skipping: {folder_title} - {note.title}."
|
contents.append((note.title, f"{note.get_url()}.html"))
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
print(f"Exporting {folder_title} - {note.title}...")
|
|
||||||
note_counter += 1
|
|
||||||
contents.append((note.title, note.get_url()))
|
|
||||||
with (self.content_dir / (note.get_url() + ".md")).open(
|
with (self.content_dir / (note.get_url() + ".md")).open(
|
||||||
mode="w"
|
mode="w"
|
||||||
) as outfile:
|
) as outfile:
|
||||||
outfile.write(
|
outfile.write(
|
||||||
f"""+++
|
f"""# {note.title}
|
||||||
title = "{note.title}"
|
|
||||||
weight = {note_counter}
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
{self.resolve_note_links(note)}
|
{self.resolve_note_links(note)}
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
@ -238,18 +341,12 @@ email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
with (dir / "_index.md").open(mode="w") as outfile:
|
with (dir / "index.md").open(mode="w") as outfile:
|
||||||
contents_list = "\n1. ".join(
|
contents_list = "\n1. ".join(
|
||||||
f"[{title}](../../{url})" for title, url in contents
|
f"[{title}](../../{url})" for title, url in contents
|
||||||
)
|
)
|
||||||
outfile.write(
|
outfile.write(
|
||||||
f"""+++
|
f"""# Contents
|
||||||
title = "{folder_title}"
|
|
||||||
weight = {folder_counter}
|
|
||||||
sort_by = "weight"
|
|
||||||
insert_anchor_links = "right"
|
|
||||||
+++
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
Click on a link in the list below to go to that page:
|
Click on a link in the list below to go to that page:
|
||||||
|
|
||||||
@ -257,6 +354,7 @@ Click on a link in the list below to go to that page:
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.write_summary()
|
||||||
self.copy_resources()
|
self.copy_resources()
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[build]
|
[build]
|
||||||
publish = "public"
|
publish = "public"
|
||||||
command = "./build.sh"
|
command = "./build"
|
||||||
|
|
||||||
[build.environment]
|
[build.environment]
|
||||||
ZOLA_VERSION = "0.12.2"
|
ZOLA_VERSION = "0.12.2"
|
||||||
|
@ -1 +0,0 @@
|
|||||||
/ /welcome/stavros-notes/ 301!
|
|
3
static/custom.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
h2, h3 {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|