Fix extension exporting bug
@ -18,3 +18,4 @@ Click on a link in the list below to go to that page:
|
|||||||
1. [Omnibus F4 V3 pinout](../../drone-stuff/omnibus-f4-v3-pinout)
|
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. [Omnibus F4 pro servo diode](../../drone-stuff/omnibus-f4-pro-servo-diode)
|
||||||
1. [Transmitter external module pinout](../../drone-stuff/transmitter-external-module-pinout)
|
1. [Transmitter external module pinout](../../drone-stuff/transmitter-external-module-pinout)
|
||||||
|
1. [Transportable C1 Chaser](../../drone-stuff/transportable-c1-chaser)
|
||||||
|
@ -7,11 +7,11 @@ 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.jpeg)](../../resources/f86da9a7aac1413ebd77825897164f7f.jpeg)
|
[![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.jpeg)](../../resources/815576429ece43789dbc70dfd33517a1.jpeg)
|
[![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.
|
||||||
|
@ -14,7 +14,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.jpeg)](../../resources/72d23239af1541d4b170271c1e9e21eb.jpeg)
|
[![pinout.jpeg](../../resources/72d23239af1541d4b170271c1e9e21eb.jpg)](../../resources/72d23239af1541d4b170271c1e9e21eb.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
45
content/drone-stuff/transportable-c1-chaser.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
+++
|
||||||
|
title = "Transportable C1 Chaser"
|
||||||
|
weight = 11
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
|
||||||
|
I thought that a C1 Chaser that can break apart for easy transport would be the ideal long-range wing, so I bought a second one and made some modifications to it.
|
||||||
|
I'm listing the modifications here so you can do the same if you want to.
|
||||||
|
|
||||||
|
|
||||||
|
## Spar
|
||||||
|
|
||||||
|
The biggest issue is making the spar removable.
|
||||||
|
The best way I've found to do that is to use IKEA drinking straws, they have an internal diameter of around 7.5mm, making them ideal for putting the spar through.
|
||||||
|
|
||||||
|
I've cut three straws to length and glued them in the spar channel, as you can see here:
|
||||||
|
|
||||||
|
[![](../../resources/5ac6bff04962497083b8403ed0fded98.jpg)](../../resources/5ac6bff04962497083b8403ed0fded98.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
[![](../../resources/65ff483180ad483795b32d0b65f72613.jpg)](../../resources/65ff483180ad483795b32d0b65f72613.jpg)
|
||||||
|
|
||||||
|
For glue, I use [E6000](https://www.banggood.com/ZHANLIDA-152550ml-E6000-B6000-Adhesive-Transparent-Glue-for-RC-Models-p-1604315.html?cur_warehouse=CN&ID=62834216283418&rmmds=search&custlinkid=667416&p=6W16207412782201611V) (sold as Goop in the US) for pretty much everything, but for this one you can use your favorite glue that you know won't dissolve EPO.
|
||||||
|
|
||||||
|
|
||||||
|
## Wings
|
||||||
|
|
||||||
|
TODO: I haven't really gotten there yet.
|
||||||
|
|
||||||
|
|
||||||
|
## Vertical stabilizers
|
||||||
|
|
||||||
|
The last part is securing the vertical stabilizers. I did this with two very small 3D printed pieces, I slot the stabilizers horizontally (on the left/right axis) onto the fuselage and then connect the wings, which keeps the stabilizers securely in place.
|
||||||
|
|
||||||
|
TODO: I'll add more photos here when this is glued and finalized.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
<p style="font-size:80%; font-style: italic">
|
||||||
|
Last updated on January 31, 2021. For any questions/feedback,
|
||||||
|
email me at <a href="mailto:hi@stavros.io">hi@stavros.io</a>.
|
||||||
|
</p>
|
@ -6,7 +6,7 @@ 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.jpeg)
|
![maxresdefault.jpeg](../../resources/d4819ca1c3d0490daaa12f62af09aa00.jpg)
|
||||||
|
|
||||||
|
|
||||||
## Wings
|
## Wings
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import dataclasses
|
||||||
|
import mimetypes
|
||||||
import re
|
import re
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
@ -6,7 +8,10 @@ from datetime import datetime
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import copy
|
from shutil import copy
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
|
|
||||||
def contains_word(word: str, text: str) -> bool:
|
def contains_word(word: str, text: str) -> bool:
|
||||||
@ -23,32 +28,39 @@ def slugify(text):
|
|||||||
return re.sub(r"[\W_]+", "-", text.lower()).strip("-")
|
return re.sub(r"[\W_]+", "-", text.lower()).strip("-")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
class Note:
|
class Note:
|
||||||
"""A helper type for a note."""
|
"""A helper type for a note."""
|
||||||
|
|
||||||
def __init__(
|
id: str
|
||||||
self,
|
parent_id: str
|
||||||
id,
|
parent_title: str
|
||||||
parent_id,
|
title: str
|
||||||
parent_title,
|
body: str
|
||||||
title,
|
updated_time: datetime
|
||||||
body,
|
tags: List[str] = dataclasses.field(default_factory=list)
|
||||||
updated_time,
|
|
||||||
tags=[],
|
|
||||||
):
|
|
||||||
self.id = id
|
|
||||||
self.parent_id = parent_id
|
|
||||||
self.parent_title = parent_title
|
|
||||||
self.title = title
|
|
||||||
self.body = body
|
|
||||||
self.updated_time = datetime.fromtimestamp(updated_time)
|
|
||||||
self.tags = tags
|
|
||||||
|
|
||||||
def get_url(self):
|
def get_url(self):
|
||||||
"""Return the note's relative URL."""
|
"""Return the note's relative URL."""
|
||||||
return slugify(self.parent_title) + "/" + slugify(self.title)
|
return slugify(self.parent_title) + "/" + slugify(self.title)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class Resource:
|
||||||
|
"""A helper type for a resource."""
|
||||||
|
|
||||||
|
title: str
|
||||||
|
# The actual extension that the file stored in Joplin has.
|
||||||
|
extension: str
|
||||||
|
mimetype: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def derived_ext(self):
|
||||||
|
"""Return an extension derived from the resource's mime type."""
|
||||||
|
ext = mimetypes.guess_extension(self.mimetype, strict=False)
|
||||||
|
return "" if ext is None else ext
|
||||||
|
|
||||||
|
|
||||||
class JoplinExporter:
|
class JoplinExporter:
|
||||||
"""The main exporter class."""
|
"""The main exporter class."""
|
||||||
|
|
||||||
@ -57,9 +69,8 @@ class JoplinExporter:
|
|||||||
joplin_dir = Path.home() / ".config/joplin-desktop"
|
joplin_dir = Path.home() / ".config/joplin-desktop"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# A dict of {resource_id: (title, extension)}.
|
self.resources: Dict[str, Resource] = {}
|
||||||
self.resources = {}
|
self.used_resources: Set[str] = set()
|
||||||
self.used_resources = set()
|
|
||||||
|
|
||||||
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."""
|
||||||
@ -99,16 +110,15 @@ class JoplinExporter:
|
|||||||
# Add the resource to the set of used resources, so we can only copy
|
# Add the resource to the set of used resources, so we can only copy
|
||||||
# the resources that are used.
|
# the resources that are used.
|
||||||
self.used_resources.add(resource_id)
|
self.used_resources.add(resource_id)
|
||||||
return "resources/" + resource_id + "." + resource[1]
|
return "resources/" + resource_id + resource.derived_ext
|
||||||
|
|
||||||
def copy_resources(self):
|
def copy_resources(self):
|
||||||
"""Copy all the used resources to the output directory."""
|
"""Copy all the used resources to the output directory."""
|
||||||
for resource_id in self.used_resources:
|
for resource_id in self.used_resources:
|
||||||
resource = self.resources[resource_id]
|
resource = self.resources[resource_id]
|
||||||
title, extension = resource
|
|
||||||
copy(
|
copy(
|
||||||
self.joplin_dir / "resources" / (f"{resource_id}.{extension}"),
|
self.joplin_dir / "resources" / (f"{resource_id}.{resource.extension}"),
|
||||||
self.static_dir,
|
self.static_dir / f"{resource_id}{resource.derived_ext}",
|
||||||
)
|
)
|
||||||
|
|
||||||
def read_data(self):
|
def read_data(self):
|
||||||
@ -128,8 +138,16 @@ class JoplinExporter:
|
|||||||
for note_id, tag_id in c.fetchall():
|
for note_id, tag_id in c.fetchall():
|
||||||
note_tags[note_id].append(tags[tag_id])
|
note_tags[note_id].append(tags[tag_id])
|
||||||
|
|
||||||
c.execute("""SELECT id, title, file_extension FROM resources;""")
|
c.execute("""SELECT id, title, mime, file_extension FROM resources;""")
|
||||||
self.resources = {id: (title, ext) for id, title, ext in c.fetchall()}
|
|
||||||
|
self.resources = {
|
||||||
|
id: Resource(
|
||||||
|
title=title,
|
||||||
|
extension=ext,
|
||||||
|
mimetype=mime,
|
||||||
|
)
|
||||||
|
for id, title, mime, ext in c.fetchall()
|
||||||
|
}
|
||||||
|
|
||||||
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.notes = defaultdict(list)
|
||||||
@ -141,7 +159,7 @@ class JoplinExporter:
|
|||||||
self.folders[parent_id],
|
self.folders[parent_id],
|
||||||
title,
|
title,
|
||||||
body,
|
body,
|
||||||
updated_time / 1000,
|
datetime.fromtimestamp(updated_time / 1000),
|
||||||
tags=note_tags[id],
|
tags=note_tags[id],
|
||||||
)
|
)
|
||||||
self.notes[note.parent_id].append(note)
|
self.notes[note.parent_id].append(note)
|
||||||
|
BIN
static/resources/5ac6bff04962497083b8403ed0fded98.jpg
Normal file
After Width: | Height: | Size: 237 KiB |
BIN
static/resources/65ff483180ad483795b32d0b65f72613.jpg
Normal file
After Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |