Merge branch 'mdbook' into 'master'

Migrate to mdBook

See merge request stavros/notes!1
This commit is contained in:
Stavros Korokithakis 2021-11-20 02:13:37 +00:00
commit 121e22d2c5
80 changed files with 411 additions and 408 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
themes/
public/
book/

View File

@ -1,12 +1,26 @@
pages:
stages:
- build
- pages
build:
stage: build
image: python
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
- tar zxvf zola.tgz
- mv zola /usr/local/bin/
- ./build.sh
- pip install pre-commit
- pre-commit run -a --hook-stage=manual
- 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
- tar zxvf mdbook.tgz
- mv mdbook /usr/local/bin/
- ./build
artifacts:
paths:
- public
pages:
stage: pages
script: ls -lah public/
only:
- master
artifacts:
paths:
- public

View File

@ -21,8 +21,8 @@ repos:
- --ignore=D100,D107,D203,D212
- repo: local
hooks:
- id: migrations-check
language: system
name: Export the notes.
entry: bash -c "./joplinexport.py"
pass_filenames: false
- id: no-todos
name: Forbid TODOs
entry: "TODO"
language: pygrep
types: [python]

13
book.toml Normal file
View 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
View 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/

View File

@ -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
View 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)

View File

@ -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)

View File

@ -1,21 +1,17 @@
+++
title = "ArduPilot recommended settings"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
# ArduPilot recommended settings
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
```bash
```js
GPS_GNSS_MODE=71 # Enable GPS/SBAS/Galileo/GLONASS.
GPS_RATE_MS=100 # 10 Hz update rate.
```
## Crossfire/ELRS
```bash
```js
SERIALn_PROTOCOL=23 # Crossfire/ELRS.
RC_OPTION=800 # 5 - Arming check throttle.
# 8 - CRSF telemetry passthrough.
@ -26,7 +22,7 @@ RC_OPTION=800 # 5 - Arming check throttle.
30% expo is a good starting point:
```bash
```js
MAN_EXPO_ROLL=30
MAN_EXPO_PITCH=30
MAN_EXPO_RUDDER=30
@ -34,7 +30,7 @@ MAN_EXPO_RUDDER=30
## Miscellaneous
```bash
```js
INS_GYRO_FILTER=60 # Faster gyro 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">
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>.
</p>

View File

@ -1,9 +1,5 @@
+++
title = "ArduPilot setup checklist"
weight = 2
sort_by = "weight"
insert_anchor_links = "right"
+++
# ArduPilot setup checklist
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.
@ -17,7 +13,7 @@ It's called Parachute, and you can download it here:
## 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
@ -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.
- [ ] 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:
```bash
```js
SERIAL2_PROTOCOL=23 # RCIN
SERIAL2_BAUD=115
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`.
- [ ] Set up your servo functions and trims:
```bash
```js
SERVO1_FUNCTION=70 # Throttle
SERVO1_MIN=1000
SERVO1_MAX=2000
@ -102,7 +98,7 @@ The values in this section are specific to the Omnibus F4, but the settings aren
## 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
- [ ] 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">
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>.
</p>

View File

@ -1,9 +1,5 @@
+++
title = "Building ArduPilot"
weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++
# Building ArduPilot
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.

View File

@ -1,9 +1,5 @@
+++
title = "Configuring a switch as a relay"
weight = 4
sort_by = "weight"
insert_anchor_links = "right"
+++
# Configuring a switch as a relay
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):

View 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)

View File

@ -1,9 +1,5 @@
+++
title = "Miscellaneous notes"
weight = 5
sort_by = "weight"
insert_anchor_links = "right"
+++
# Miscellaneous notes
These are random AP-related notes that wouldn't fit anywhere else:
## DJI FPV configuration

View File

@ -1,9 +1,5 @@
+++
title = "Reverse thrust"
weight = 6
sort_by = "weight"
insert_anchor_links = "right"
+++
# Reverse thrust
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.

View File

@ -1,10 +1,6 @@
+++
title = "TECS tuning calculator"
weight = 7
sort_by = "weight"
insert_anchor_links = "right"
+++
To use this calculator, first follow the steps in [Tuning the TECS](../../ardupilot/tuning-the-tecs).
# TECS tuning calculator
To use this calculator, first follow the steps in [Tuning the TECS](/ardupilot/tuning-the-tecs).
<script>
function kmhToMs(kmh) { return Math.round(kmh / 3.6); }

View File

@ -1,9 +1,5 @@
+++
title = "Transfer config between craft"
weight = 8
sort_by = "weight"
insert_anchor_links = "right"
+++
# Transfer config between craft
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)$`

View File

@ -1,9 +1,5 @@
+++
title = "Tuning the TECS"
weight = 9
sort_by = "weight"
insert_anchor_links = "right"
+++
# Tuning the TECS
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.
@ -64,7 +60,7 @@ You're done with this step.
### On the bench
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.

View File

@ -1,9 +1,5 @@
+++
title = "A simple guide to PID control"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
# A simple guide to PID control
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.
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.

View File

@ -1,9 +1,5 @@
+++
title = "E6000 hinges"
weight = 2
sort_by = "weight"
insert_anchor_links = "right"
+++
# E6000 hinges
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.
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.

View File

@ -1,12 +1,8 @@
+++
title = "FPV frequency chart"
weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++
# FPV frequency 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/).

View File

@ -1,9 +1,5 @@
+++
title = "General RC tips"
weight = 4
sort_by = "weight"
insert_anchor_links = "right"
+++
# General RC tips
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.

View File

@ -1,16 +1,12 @@
+++
title = "Getting uninverted SBUS on a no-name FrSky-compatible receiver"
weight = 5
sort_by = "weight"
insert_anchor_links = "right"
+++
# Getting uninverted SBUS on a no-name FrSky-compatible receiver
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:
[![rc-sbus-mosfet.jpg](../../resources/1b0f508a533e45b496c6636d49161b0c.jpg)](../../resources/1b0f508a533e45b496c6636d49161b0c.jpg)
[![rc-sbus-mosfet.jpg](/resources/1b0f508a533e45b496c6636d49161b0c.jpg)](/resources/1b0f508a533e45b496c6636d49161b0c.jpg)

View File

@ -1,17 +1,13 @@
+++
title = "Getting uninverted SBUS/SmartPort on the FrSky XSR receiver"
weight = 6
sort_by = "weight"
insert_anchor_links = "right"
+++
# Getting uninverted SBUS/SmartPort on the FrSky XSR receiver
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:
[![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):
[![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.
It seems to be a bit of a gamble whether you get SBUS or SmartPort, it might be firmware-dependent.

View File

@ -1,9 +1,5 @@
+++
title = "INAV tuning tips"
weight = 7
sort_by = "weight"
insert_anchor_links = "right"
+++
# INAV tuning tips
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`.

View File

@ -1,23 +1,17 @@
+++
title = "Drone stuff"
weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++
## Contents
# Contents
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. [E6000 hinges](../../drone-stuff/e6000-hinges)
1. [FPV frequency chart](../../drone-stuff/fpv-frequency-chart)
1. [General RC tips](../../drone-stuff/general-rc-tips)
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/SmartPort on the FrSky XSR receiver](../../drone-stuff/getting-uninverted-sbus-smartport-on-the-frsky-xsr-receiver)
1. [INAV tuning tips](../../drone-stuff/inav-tuning-tips)
1. [Miscellaneous](../../drone-stuff/miscellaneous)
1. [Omnibus F4 V3 pinout](../../drone-stuff/omnibus-f4-v3-pinout)
1. [Omnibus F4 pro servo diode](../../drone-stuff/omnibus-f4-pro-servo-diode)
1. [QGroundControl to Mission Planner conversion script](../../drone-stuff/qgroundcontrol-to-mission-planner-conversion-script)
1. [Transmitter external module pinout](../../drone-stuff/transmitter-external-module-pinout)
1. [Transportable C1 Chaser](../../drone-stuff/transportable-c1-chaser)
1. [A simple guide to PID control](../../drone-stuff/a-simple-guide-to-pid-control.html)
1. [E6000 hinges](../../drone-stuff/e6000-hinges.html)
1. [FPV frequency chart](../../drone-stuff/fpv-frequency-chart.html)
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.html)
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.html)
1. [Miscellaneous](../../drone-stuff/miscellaneous.html)
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.html)
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.html)
1. [Transportable C1 Chaser](../../drone-stuff/transportable-c1-chaser.html)

View File

@ -1,9 +1,5 @@
+++
title = "Miscellaneous"
weight = 8
sort_by = "weight"
insert_anchor_links = "right"
+++
# Miscellaneous
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.

View File

@ -1,16 +1,12 @@
+++
title = "Omnibus F4 pro servo diode"
weight = 10
sort_by = "weight"
insert_anchor_links = "right"
+++
# Omnibus F4 pro servo 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.
There's also a [schematic for this FC](../../resources/805930c3bedc4393ba947f0e0bfa369d.pdf).
There's also a [schematic for this FC](/resources/805930c3bedc4393ba947f0e0bfa369d.pdf).
* * *

View File

@ -1,16 +1,12 @@
+++
title = "Omnibus F4 V3 pinout"
weight = 9
sort_by = "weight"
insert_anchor_links = "right"
+++
# Omnibus F4 V3 pinout
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:
![omnibus-f4-v5-pinout2.jpg](../../resources/410f3ce004c64fe9af68bfd6856d3e53.jpg)
![omnibus-f4-v5-pinout2.jpg](/resources/410f3ce004c64fe9af68bfd6856d3e53.jpg)

View File

@ -1,9 +1,5 @@
+++
title = "QGroundControl to Mission Planner conversion script"
weight = 11
sort_by = "weight"
insert_anchor_links = "right"
+++
# QGroundControl to Mission Planner conversion script
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>`:

View File

@ -1,9 +1,5 @@
+++
title = "Transmitter external module pinout"
weight = 12
sort_by = "weight"
insert_anchor_links = "right"
+++
# Transmitter external module pinout
The transmitter (Taranis, Jumper, RadioMaster, etc) pinout is, from top to bottom:
* PPM
@ -14,7 +10,7 @@ The transmitter (Taranis, Jumper, RadioMaster, etc) pinout is, from top to botto
It's illustrated in this photo:
[![pinout.jpeg](../../resources/72d23239af1541d4b170271c1e9e21eb.jpg)](../../resources/72d23239af1541d4b170271c1e9e21eb.jpg)
[![pinout.jpeg](/resources/72d23239af1541d4b170271c1e9e21eb.jpg)](/resources/72d23239af1541d4b170271c1e9e21eb.jpg)

View File

@ -1,9 +1,5 @@
+++
title = "Transportable C1 Chaser"
weight = 13
sort_by = "weight"
insert_anchor_links = "right"
+++
# Transportable C1 Chaser
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.
@ -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):
[![](../../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.
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:
[![](../../resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)](../../resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)
[![](/resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)](/resources/6c9034ecf9d9414d87fbc6b4ec2fa28e.jpg)
## 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.
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.
@ -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:
[![](../../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.
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.
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.
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.
That way, the stabilizer isn't going anywhere, and you can install and remove it very quickly.

View File

@ -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)

View File

@ -1,9 +1,5 @@
+++
title = "Battery discharge curves"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
# Battery discharge curves
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.
@ -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:
![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.
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.
@ -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:
![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.
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.
@ -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:
![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.

View File

@ -1,9 +1,5 @@
+++
title = "Electronics tips"
weight = 2
sort_by = "weight"
insert_anchor_links = "right"
+++
# Electronics tips
This page contains various notes and tips about electronics.
## Decoupling capacitors

View File

@ -1,9 +1,5 @@
+++
title = "GRBL_ESP32 tips"
weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++
# GRBL_ESP32 tips
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`.

View File

@ -1,28 +1,24 @@
+++
title = "How to properly level your 3D printer"
weight = 4
sort_by = "weight"
insert_anchor_links = "right"
+++
# How to properly level your 3D printer
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.
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 wont adhere well:
![too-high.jpg](../../resources/576a1fedf9f144a69fe262866e9f268a.jpg)
![too-high.jpg](/resources/576a1fedf9f144a69fe262866e9f268a.jpg)
The next photo is also a bit too high. Its not as high as the previous photo, so it has partially adhered, but there are gaps between the rows and adhesion still wont 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 its mushed too much, leading to transparent-looking rows of filament. The specific filament Im 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, Ive leveled it pretty much perfectly. You can see that the rows arent cylindrical at all, instead theyre long strips that are touching each other properly and dont 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 wont 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 printers 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, youre perfect and ready to print!

View 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)

View File

@ -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)

View File

@ -1,12 +1,8 @@
+++
title = "Build notes for the FT Mighty Mini Arrow"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
# Build notes for the FT Mighty Mini Arrow
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

View 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)

View File

@ -1,9 +1,5 @@
+++
title = "Mini Drak build condensed instructions"
weight = 2
sort_by = "weight"
insert_anchor_links = "right"
+++
# Mini Drak build condensed instructions
Sources:
1. [Håvard's Mini Drak build video](https://www.youtube.com/watch?v=L4_dJxiQUjs)

View File

@ -1,12 +1,6 @@
+++
title = "Software"
weight = 6
sort_by = "weight"
insert_anchor_links = "right"
+++
## Contents
# Contents
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. [Test and format SD cards](../../software/test-and-format-sd-cards)
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.html)

View File

@ -1,9 +1,5 @@
+++
title = "Monero GUI syncing stuck with Ledger"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
# Monero GUI syncing stuck with Ledger
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.

View File

@ -1,9 +1,5 @@
+++
title = "Test and format SD cards"
weight = 2
sort_by = "weight"
insert_anchor_links = "right"
+++
# Test and format SD cards
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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@ -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
View 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)

View File

@ -1,9 +1,5 @@
+++
title = "Stavros' notes"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
# Stavros' notes
Welcome to my 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">
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>.
</p>

View File

@ -12,6 +12,7 @@ from typing import Dict
from typing import List
from typing import Optional
from typing import Set
from typing import Union
def contains_word(word: str, text: str) -> bool:
@ -28,21 +29,83 @@ def slugify(text):
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
class Note:
"""A helper type for a note."""
id: str
parent_id: str
parent_title: str
folder: Folder
title: str
body: str
updated_time: datetime
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 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
@ -65,20 +128,29 @@ class JoplinExporter:
"""The main exporter class."""
content_dir = Path("content")
static_dir = Path("static/resources")
static_dir = Path("content/static/resources")
joplin_dir = Path.home() / ".config/joplin-desktop"
def __init__(self):
self.resources: Dict[str, Resource] = {}
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):
"""Reset the content directory to a known state to begin."""
rmtree(self.content_dir)
rmtree(self.static_dir)
self.content_dir.mkdir()
self.static_dir.mkdir()
with open(self.content_dir / "_index.md", mode="w") as outfile:
rmtree(self.content_dir, ignore_errors=True)
rmtree(self.static_dir, ignore_errors=True)
self.content_dir.mkdir(parents=True)
self.static_dir.mkdir(parents=True)
with open(self.content_dir / "index.md", mode="w") as outfile:
outfile.write('+++\nredirect_to = "welcome/stavros-notes/"\n+++')
def resolve_note_links(self, note: Note) -> str:
@ -93,7 +165,7 @@ class JoplinExporter:
new_url = item_id
if 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)
@ -128,8 +200,14 @@ class JoplinExporter:
conn = sqlite3.connect(self.joplin_dir / "database.sqlite")
c = conn.cursor()
c.execute("""SELECT id, title FROM folders;""")
self.folders = {id: title for id, title in c.fetchall()}
c.execute("""SELECT id, title, parent_id FROM folders;""")
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.
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;""")
self.notes = defaultdict(list)
self.note_lookup_dict = {}
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(
id,
parent_id,
self.folders[parent_id],
title,
body,
datetime.fromtimestamp(updated_time / 1000),
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
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):
"""Export all the notes to a static site."""
self.read_data()
# Private notes shouldn't be published.
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"
)
folder_list = sorted(self.folders.values())
self.clean_content_dir()
def is_private(note) -> 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, 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)
for folder in folder_list:
contents = []
note_counter = 0
for note in sorted(self.notes[folder_id], key=lambda n: n.title):
if is_private(note):
print(
f"Note is unpublished, skipping: {folder_title} - {note.title}."
)
continue
print(f"Exporting {folder_title} - {note.title}...")
note_counter += 1
contents.append((note.title, note.get_url()))
dir = self.content_dir / folder.get_url()
dir.mkdir(parents=True)
for note in sorted(self.notes[folder.id], key=lambda n: n.title):
print(f"Exporting {folder.title} - {note.title}...")
contents.append((note.title, f"{note.get_url()}.html"))
with (self.content_dir / (note.get_url() + ".md")).open(
mode="w"
) as outfile:
outfile.write(
f"""+++
title = "{note.title}"
weight = {note_counter}
sort_by = "weight"
insert_anchor_links = "right"
+++
f"""# {note.title}
{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(
f"[{title}](../../{url})" for title, url in contents
)
outfile.write(
f"""+++
title = "{folder_title}"
weight = {folder_counter}
sort_by = "weight"
insert_anchor_links = "right"
+++
## Contents
f"""# Contents
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()

View File

@ -2,7 +2,7 @@
[build]
publish = "public"
command = "./build.sh"
command = "./build"
[build.environment]
ZOLA_VERSION = "0.12.2"

View File

@ -1 +0,0 @@
/ /welcome/stavros-notes/ 301!

3
static/custom.css Normal file
View File

@ -0,0 +1,3 @@
h2, h3 {
margin-top: 1.5em;
}