5700U
-based laptop for almost three years now and it’s been a great experience, but I wanted to explore the desktop side of things, especially since my meanderings into edge computing have shown that ARM
-based servers are at an interesting inflection point for running small AI models, and I just had no real data on AMD
‘s capabilities in that space.
Ryzen-based mini-PCs have been around for a while, but the previous generation of mobile processors (like the 4700U
and 5700U
) never quite managed to get traction in that space. Now, with Intel leaving the NUC
segment to its licensees and a resurgence of interest in small, powerful desktops with good integrated GPU
s (thanks in large part to the Steam Deck and its custom APU
), there’s a lot of possibilities to explore.
In short, I was looking for something that had a better iGPU
and could handle virtualization workloads without excessive power consumption, since my experiences with borg
and the U59 has shown me that Intel CPUs have spread out into extremes where they either consume too much power for the performance they deliver or are just built too cheaply.
So when I stumbled upon the AceMagic AM18 and saw that it was based on the 7840HS
–a 4nm process, 8C/16T processor that can go up to 5.1GHz–I decided to give it a try.
Disclaimer: AceMagic sent me a review unit (for which I thank them), and this article follows my Review Policy. Also, as usual, I purposely avoid doing any detailed price comparisons.
However, with ollama
starting to support AMD graphics this week and my having some trouble in (and lack of time for) dealing with ROCm
and ZLUDA
, I decided to split this review in two:
ROCm
) will circle back to the AI and homelab side of thingsSo let’s get started.
The AceMagic AM18 is, as you would expect, nice and compact, following the usual NUC
-like flattened cube form factor with ports on the front and back. It’s a bit larger than a NUC
and has a large cooling fan on top, but it’s small enough to fit under a monitor or under a TV (which is actually where I kept it the week it arrived).
The model I received had the following specs:
DDR5
RAM
(in a nice dual-channel configuration using Crucial CT16G56C46S5.M8D1
SODIMM
s, rated for 5600MT/s, and, interestingly enough, mentioned by Crucial as having on-die ECC
support)NVME
SSD (in a PCIe 4.0 slot) that identifies itself as a RS512GSSD710
from TenaFe and (unusually for mini-pcs) has a built-in temperature sensor.USB-A
3.0 ports (two in the front, two in the back. Confusingly, the back ones are black and the front ones are blue)USB-C
in the front, HDMI
and DisplayPort
in the back–I would have preferred two HDMI
ports, but they are all rated for 8K@60Hz, and use the amusingly named “Pink Sardine” AMD
chipset.)RTL8852BE
Wi-Fi 6/Bluetooth 5.2, which sits underneath the SSD
.USB-C
100W PSU
, rated at 20V/5A.The front also has a TTRS
audio jack and a power button. There are no Kensington lock slots, which might deter business users, but the machine is small enough to be easily hidden away.
I also got a VESA
mount, display cables, etc., but, interestingly, no SATA
cables or brackets–the reason for that only became clear when I opened up the machine:
The machine is relatively easy to open for cleaning and expansion–the top four decorative screws provide easy access to the fan for cleaning (but not removal), whereas (sadly) you need to remove the rubber feet to get at the bottom screws that allow you to pop the bottom cover.
Once you remove the bottom, it’s easy to see why there is no SATA
cable supplied–the single NVME
slot is all that you get for storage expansion, and even though the plastic is moulded to hold a 2.5” drive, the bottom fan is mounted in that slot.
It’s not necessary to remove the internal bracket to access the Wi-Fi card, but I did it anyway, and it revealed the CMOS
battery, a UART
header tucked near the USB
ports (which seems really interesting to play with later) and a (pinless) debug header, plus a red CMOS
clearing jumper and assorted wiring.
Before you ask (since I have purposefully delayed mentioning it), the RGB
lighting can be controlled only via the front button, and can fortunately be turned off entirely.
I did find the white setting to quite useful when trying to work around the machine under my TV, and I suspect it will come in even handier when I move it to my server closet.
BIOS
SettingsThe machine arrived with a basic Windows 10 Home install that has been customized to (at least) include some chipset drivers and Google Chrome:
I am not a fan of anything being added to the Windows images except drivers (and AceMagic has recently had to change their base images), but I understand that there are markets where this is a requirement or preference. I did not find anything wrong with the install, but since I need at least Windows Pro for working and my plan was to use it as a Linux machine, I wiped the install and set up Bazzite on the internal SSD
, and then later replaced the internal SSD
with a 1TB one to run Proxmox (which I will write about in a follow-up post).
I did, however, take a look at the BIOS
settings, and found them to be quite comprehensive:
Things I liked to see, and intend to use in a server configuration:
PXE
bootIOMMU
and PCIe
featuresUnlike my 5700U
machine, I did’t see any obvious way to pre-allocate RAM to the iGPU
, but I suspect that’s just because it is a different chipset.
If you’re curious, I have an annex with the output from sensors
and lshw
that I am using as a basis for tweaking the Proxmox setup I’ll be posting about in the second part of this review.
Since the machine arrived on a day when I had not a whit of clear desk space in my office on account of my testing another 3D printer it went directly to my living room, where I plugged it into a power monitoring socket next to my TV.
Linux setup was as easy as installing the bazzite-gnome-deck
spin of Bazzite, rebooting, and then setting the resolution to 1080p–and after going through the initial install wizard and configuring Steam, it felt pretty much like any game console would.
A pleasant surprise was that the M780
iGPU
detected my TV without any issues–it is a relatively old LG
that goes up to 4K 120Hz with HDR
support, and I was able to set it at anywhere between 1080p/60Hz to 4K/120Hz without any issues.
I eventually trimmed it down to 1080p/120Hz to make sure I could get a decent frame rate–the AMD
Radeon M780
iGPU
can handle the full resolution for regular desktop work, but there was no point in harming the gaming experience1.
I then paired an Xbox controller via Bluetooth, and started downloading my Steam library.
That helped me get an early start on testing power consumption and Wi-Fi speeds–impressively, it was able to download my Steam library at a peak 480Mbps, which is only slightly less what my streaming server gets on a wired Gigabit connection–and I don’t have Wi-Fi 6 in my house yet:
The power consumption was also quite good, and I was able to measure it at various loads:
Operating System | Power (W) | Notes |
---|---|---|
Bazzite (Fedora 39) | 60.3 | Gaming (Steam, average over the games listed) |
50.9 | Steam downloads over Wi-Fi |
|
45.6 | Gaming (Emulation) |
|
21.7 | Booting |
|
11.2 | Idle, TV/display on |
|
0.1 | Suspend |
This will, of course, be expanded upon in the server part of this review, but I was quite pleased to see that the machine was able to idle at around 12W and consume less than 100W under heavy load.
As to noise, and being extraordinarily fan-averse to the point of preferring streaming over local gaming, I was quite pleased to find that the fan was generally barely audible even when gaming, and I could only notice it for a few seconds at a time when under heavy load.
But I did place the machine squarely under the center speaker of my audio setup, so it was a bit of a moot point–I suspect it would be more noticeable (and annoying) if I had it right beside me–but I will eventually do more detailed measurements when I get around to posting the server part of this review.
The good thing is that tweaking the fan curves in the BIOS
is a feasible option on this machine–plus the sheer size of the top fan (in mini-PC terms, it’s pretty massive) means that it is relatively quiet and completely non-whiny even when running at full speed.
Throughout that first week I installed a few games and emulators to test over the evenings, and was able to play a few hours of Halo Infinite, Borderlands 3, Hades and Stray without any issues.
I also synced my RetroDECK setup and experimented with a few emulators, and everything worked fine other than dual control presses in the 8bitdo Ultimate Controller I tried to use for a particular game–but that’s just the combination of a couple of rough edges in Bazzite and RetroDECK.
As you’d expect, everything flagged as Steam compatible “just worked”. I only had trouble with Horizon: Zero Dawn, which is known to be fickle and does work on my streaming setup, but I suspect it’s just a matter of getting a few more Proton/AMD
updates down the line:
I also emulated that which cannot be named anymore on the very evening it was rendered extinct, and it was… glorious, both in 1080p and in 4K (although I think the M780
is smack in the middle between smooth 1080p/30fps and 4K/30fps). Even without any immediate way to tweak the frame rate, I suspect 1080p/60fps is well within reach.
I will be doing more detailed benchmarking in the follow-up post, but I did want to run a throughput test on the shipping PCIe
4.0 SSD
for later comparison:
# fio --filename=/<path>/file --size=5GB --direct=1 --rw=randrw --bs=64k --ioengine=libaio --iodepth=64 --runtime=120 --numjobs=4 --time_based --group_reporting --name=random-read-write --eta-newline=1
random-read-write: (groupid=0, jobs=4): err= 0: pid=7251: Sun Mar 17 18:20:12 2024
read: IOPS=115k, BW=7218MiB/s (7568MB/s)(846GiB/120001msec)
slat (usec): min=4, max=2551, avg= 9.39, stdev= 2.54
clat (usec): min=10, max=4139, avg=1091.34, stdev=72.41
lat (usec): min=17, max=4155, avg=1100.73, stdev=72.50
clat percentiles (usec):
| 1.00th=[ 938], 5.00th=[ 979], 10.00th=[ 1004], 20.00th=[ 1037],
| 30.00th=[ 1057], 40.00th=[ 1074], 50.00th=[ 1090], 60.00th=[ 1106],
| 70.00th=[ 1123], 80.00th=[ 1156], 90.00th=[ 1188], 95.00th=[ 1205],
| 99.00th=[ 1270], 99.50th=[ 1287], 99.90th=[ 1418], 99.95th=[ 1532],
| 99.99th=[ 2057]
bw ( MiB/s): min= 7004, max= 7437, per=100.00%, avg=7221.87, stdev=17.80, samples=956
iops : min=112078, max=119006, avg=115549.98, stdev=284.76, samples=956
write: IOPS=115k, BW=7215MiB/s (7565MB/s)(845GiB/120001msec); 0 zone resets
slat (usec): min=6, max=2872, avg=23.47, stdev= 6.27
clat (nsec): min=1272, max=4136.1k, avg=1092150.09, stdev=72495.42
lat (usec): min=9, max=4156, avg=1115.62, stdev=72.91
clat percentiles (usec):
| 1.00th=[ 938], 5.00th=[ 979], 10.00th=[ 1004], 20.00th=[ 1037],
| 30.00th=[ 1057], 40.00th=[ 1074], 50.00th=[ 1090], 60.00th=[ 1106],
| 70.00th=[ 1123], 80.00th=[ 1156], 90.00th=[ 1188], 95.00th=[ 1205],
| 99.00th=[ 1270], 99.50th=[ 1287], 99.90th=[ 1418], 99.95th=[ 1532],
| 99.99th=[ 2057]
bw ( MiB/s): min= 7014, max= 7312, per=100.00%, avg=7218.74, stdev= 9.64, samples=956
iops : min=112230, max=117002, avg=115499.83, stdev=154.17, samples=956
lat (usec) : 2=0.01%, 20=0.01%, 50=0.01%, 100=0.01%, 250=0.01%
lat (usec) : 500=0.01%, 750=0.01%, 1000=8.92%
lat (msec) : 2=91.07%, 4=0.01%, 10=0.01%
cpu : usr=9.18%, sys=90.07%, ctx=11180, majf=0, minf=54
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
issued rwts: total=13858307,13852536,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=64
Run status group 0 (all jobs):
READ: bw=7218MiB/s (7568MB/s), 7218MiB/s-7218MiB/s (7568MB/s-7568MB/s), io=846GiB (908GB), run=120001-120001msec
WRITE: bw=7215MiB/s (7565MB/s), 7215MiB/s-7215MiB/s (7565MB/s-7565MB/s), io=845GiB (908GB), run=120001-120001msec
That’s a whopping 115k IOPS
, which is very impressive for a vendor-supplied SSD
and should be more than enough for most workloads. It might even be slower than the one I got for testing Proxmox… but we’ll see.
From a gaming perspective (and from someone who just can’t retire from gaming), the AceMagic AM18 is very solid, and as a first hands-on experience with a 7840HS
-based machine, it’s quite impressive in terms of performance and power consumption.
This becomes ever more apparent if I compare it with my NVIDIA RTX 3060-based streaming setup, which is nominally more powerful and acting as a streaming server but, in the end, provides a similar gaming experience on my TV at the expense of a lot more power (and heat).
And yes, the AceMagic AM18 can be a Steam/Moonlight server as well–I tried it out of curiosity and it worked fine on lighter games, but the reason I wanted to test it was really to understand the limits of the AMD
APU
architecture, and I’m trying really hard not to go down any more rabbit holes right now.
But if you came here looking for a small, powerful, and quiet desktop that can, perhaps, replace your conventional console, I’d have to say maybe. And that’s simply because comparing the AceMagic AM18 directly with a console is a bit unfair in either direction.
If you’re still looking for a bias on my part instead of a fully formulated opinion, then I’d say that spec-wise it is a good match for the current generation of consoles if you don’t care about AAA 4K gaming or console exclusives2.
And I’d leave it at that until Proton gets more optimizations for this new crop of Ryzen APU
s.
But at this power envelope, I’m really impressed. It’s not Apple Silicon, but definitely the next best thing in terms of average performance per watt.
The only teething issue I had was apparent lack of HDMI-CEC
support–I do have an HDMI
switch in between that also has other (working) devices plugged into it, and I still had to fiddle with buttons to switch inputs. I suspect that’s a combination of the M780
iGPU
and Bazzite, and there were no obvious BIOS
settings to tweak. ↩︎
And if I think about it, the idea of replacing a console with a Steam-based home theatre PC is something I might do myself some day. ↩︎
Again, like last year, weekly notes were a way to keep my mind off my work situation, keep track of progress on projects, and to generally refer back to later when I was looking for a specific thing (like some of the scripts I hacked together, which are easier to find in context).
And since I really don’t like using most of the current set of note taking applications full of clutter (ahem Obsidian) and vastly prefer having them public, they are very, very easy to maintain.
But the optimistic mood they helped sustain was broken this week by yet another corporate re-org, and even having fully recovered from spending most of last year in a state of shock at the layoffs–or perhaps especially because of that, I decided to accelerate things this time around and do something else for a change. Literally.
I’ve been slowly gravitating towards smaller and smaller hardware over time, and although my homelab is still in an expansion phase, ARM
nodes already outnumber Intel nodes on my Proxmox cluster.
Low power, high performance hardware with a very tight power envelope is something that really appeals to me, and even the code I’ve written (or tweaked) has been going lower and lower down the stack.
Add to that well over a decade of doing analytics and “traditional” AI, plus the LLM
hype fest, and everything’s pretty much converging towards my spending more and more “free” time (as well as my independently advisory hours, which are another thing I don’t write about) around those topics.
It’s very early days, but yes, edge LLM
s (and, let’s be honest, more useful models) are feasible now within very specific parameters, and that’s something I’d like to pursue–likely with a few detours into other hardware-centric projects, since I have literally dozens of small MCU
boards to play with.
Besides, amid all the insanity of web technology, it just feels nice to write C++
again, even if I’m slower at it.
Regular readers have noticed that I’ve been doing more and more product reviews. That’s always been something I enjoyed doing because a) I greatly enjoy writing and b) the object or software under review provides me with a focal point around which I can wrap not just my (sometimes extreme) curiosity and my (definitely not neurotypical) attention to detail.
There will be a few more reviews coming (there’s a software/music one that I have as yet failed to complete due to lack of proper inspiration, for instance), and derivative pieces as I dig further into things.
I have no intent to let those take over the site, or even turn a profit (that’s the gist of the policy), but they did take over my notes in the sense that they provided a bit of extra escapism from work and afforded me the ability to accelerate a couple of my personal projects–and that’s the kind of balance between research, tinkering and writing that I think I need to get over the upcoming months.
This page is a reference table for resources I’m keeping tabs on.
That grand, spacious (and long ignored) branch of computing that, these days, deals not just with thinking machines (so-called “hard” AI), but mostly with enhancing the usefulness of machines in general by exploring mechanisms to express and manipulate harvested knowledge.
Or just pretty pictures and weird chatbots.
Field | Category | Date | Link | Notes |
---|---|---|---|---|
General | Examples | 2024-03 | flash-attention-minimal | a minimal implementation of Flash Attention |
Frameworks | 2023-12 | MLX | An array framework for Apple silicon |
|
mlx-examples | MLX examples |
|||
2023-05 | marvin | A generic wrapper for various AI APIs |
||
Jupyter | 2023-04 | jupyter-ai | an official Jupyter plugin that can handle multiple AI back-ends (although it seems less flexible than the others right now) |
|
Libraries | 2023-06 | unstructured | a library for handling and segmenting unstructured data of various kinds, from text to common file formats |
|
2023-03 | ml-ane-transformers | Apple’s transformers library, optimized for the Neural Engine |
||
2009-06 | Alchemy | A toolkit providing a series of algorithms for statistical relational learning and probabilistic logic inference, based on Markov logic representation |
||
Techniques | 2022-12 | awesome-chatgpt-prompts | might be a short-lived resource, but an interesting one |
|
Tools | 2024-01 | pico-tflmicro | a port of TensorFlow Lite Micro to the Raspberry Pi Pico |
|
2023-05 | explainerdashboard | a web app that explains the workings of a (scikit-learn compatible) machine learning model |
||
2023-04 | basaran | An Open-Source alternative to the OpenAI text completion API, with a compatible streaming API for privately hosted models. |
||
2023-03 | NVIDIA Triton Inference Server | A high-performance inference server |
||
2022-12 | Project Bumblebee | Pre-trained and transformer neural models in Elixir. |
||
Generative Audio | models | 2023-04 | bark | a text-prompted genereative audio model |
Large Language Models | Applications | 2023-07 | Chie | A cross-platform dekstop application with chat history and extension support |
Copilots | 2023-06 | Obsidian Copilot | an interesting take on how to use semantic search and OpenSearch’s BM25 implementation |
|
Demos | 2024-01 | WhisperFusion | an ensemble setup with WhisperSpeech, WhisperLive and Phi |
|
Frameworks | 2023-11 | Tanuki | yet another LLM framework using decorators for data validation |
|
2023-07 | litellm | a simple, lightweight LLM wrapper |
||
AutoChain | Yet another alternative to langchain |
|||
griptape | a |
|||
llama_index | a data framework for LLM applications |
|||
txtai | has spinoffs for chat, workflows for medical/scientific papers, semantic search for developers and semantic search for headlines and story text |
|||
llmflows | Yet another alternative to langchain, but with an interesting approach at defining workflows |
|||
2023-05 | langchain | a composable approach for building LLM applications |
||
guidance | Control modern language models more effectively and efficiently than traditional prompting or chaining. |
|||
Front-Ends | 2024-01 | jan | an open-source ChatGPT alternative that runs 100% offline (uses nitro) |
|
2023-12 | SecureAI-Tools | a self-hosted local inference front-end for chatting with document collections |
||
gpt4all | another self-hosted local inference front-end |
|||
Jupyter | 2023-04 | LLMBook | A VS Code notebook interface for LLMs |
|
jupytee | a Jupyter plugin that can handle code generation and image generation, but not switching models (GPT-4) |
|||
genai | a Jupyter plugin that can handle code generation and fixes based on tracebacks |
|||
ipython-gpt | a Jupyter plugin that can handle multiple models |
|||
Libraries | 2024-02 | DataDreamer | library for prompting, synthetic data generation, and training workflows |
|
2023-10 | MemGPT | a memory management/summarization technique for unbounded context |
||
2023-09 | instructor | a clever library that simplifies invoking OpenAI function calls |
||
2023-06 | simpleaichat | A simple wrapper for the ChatGPT AI |
||
2023-05 | guardrails | a package for validating and correcting the outputs of large language models |
||
Models | 2024-01 | TinyLlama | pretraining of a 1.1B Llama model on 3 trillion tokens. |
|
2023-12 | ml-ferret | a multi-modal model from Apple |
||
2023-04 | turbopilot | a GitHub CoPilot replacement that can run locally (CPU only) |
||
Reference | 2023-12 | Native JSON Output from GPT-4 | tips on how to use OpenAI JSON and function calling |
|
GPT Prompt Archive | A set of sample base prompts for various LLMs |
|||
2023-03 | Using LLaMA with M1 Mac | Manual instructions for Apple Silicon |
||
Resources | 2023-12 | Prompt Engineering Guide | a set of lecture notes and detailed examples of prompting techniques |
|
promptbase | Another set of prompting techniques and detailed examples |
|||
2023-04 | awesome-decentralized-llm | a collection of LLM resources that operate independently |
||
Samples | 2024-01 | SimpleTinyLlama | a simple PyTorch-based implementation |
|
devlooper | a program synthesis agent that autonomously fixes its output by running tests |
|||
2023-12 | gpt-researcher | an agent that does online research on any given topic |
||
LibreChat | A self-hosted ChatGPT alternative |
|||
sharepoint-indexing-azure-cognitive-search | provides an example of how to use Graph navigation and Cognitive Search indexing |
|||
gpt4all | open-source LLM chatbots |
|||
GPT in 60 Lines of NumPy | a tutorial on how to build a GPT model from scratch |
|||
Bash One-Liners for LLMs | a collection of one-liners for various LLMs |
|||
2023-11 | David Attenborough narrates your life | A pretty hilarious image-to-description example |
||
Demystifying Advanced RAG Pipelines | An LLM-powered advanced RAG pipeline built from scratch |
|||
Wanderlust OpenAI example using Solara | A simple interactive web shell with some nice features |
|||
Tools | 2024-03 | gpt-pilot | a prototype development tool that leverages GPT |
|
R2R | a framework for or rapid development and deployment of production-ready RAG systems with SQLite support |
|||
2024-02 | geppetto | a bot for integrating ChatGPT and DALL-E into Slack |
||
GPTFast | a set of acceleration techniques |
|||
notesollama | a plugin for Apple Notes that uses the Accessibility APIs |
|||
llm-ls | a local language server that leverages LLMs |
|||
llm-vscode | a VSCode extension that uses llm-ls |
|||
crewAI | a framework for orchestrating autonomous AI agents |
|||
llmware | a framework for developing LLM-based applications including Retrieval Augmented Generation |
|||
hqq | an implementation of Half-Quadratic Quantization (HQQ) |
|||
reor | a note taking tool that performs RAG using a local LLM |
|||
NeuralFlow | a Python script for plotting the intermediate layer outputs of Mistral 7B |
|||
2024-01 | ollama-bot | a rudimentary IRC bot that communicates with a local instance of ollama |
||
koboldcpp | nn easy-to-use AI text-generation software for GGML and GGUF models based on llama.cpp |
|||
gguf-tools | a set of tools for manipulating GGUF format files |
|||
nitro | a self-hosted inference engine for edge computing with an OpenAI API |
|||
emacs-copilot | an Emacs extension for using a local LLM |
|||
nlm-ingestor | a set of parsers for common file formats |
|||
lorax | a framework that allows users to serve thousands of fine-tuned models on a single GPU |
|||
privy | An open-source alternative to GitHub copilot that runs locally. |
|||
2023-12 | microagents | an interesting experiment on self-editing agents |
||
BricksLLM | an OpenAI gateway in Go to create API keys with rate limits, cost limits and TTLs |
|||
macOSpilot-ai-assistant | An Electron app for macOS |
|||
TinyChatEngine | A local (edge) inference engine in C++ without any dependencies |
|||
LocalAI | A local, drop-in replacement for the OpenAI API |
|||
Serve | A containerized solution for using local LLMs via web chat |
|||
wyGPT | another C++ local inference tool |
|||
2023-10 | localpilot | a MITM proxy that lets you use the GitHub Copilot extension with other LLMs |
||
2023-09 | embedchain | another framework to create bots from existing datasets |
||
llm_agents | a simplified agent framework (doesn’t use OpenAI functions) |
|||
2023-08 | pykoi | a unified interface for data and feedback collection, including model comparisons |
||
PromptTools | self-hostable toools for evaluating LLMs, vector databases, and prompts |
|||
2023-07 | a1gpt | A C++ implementation of a GPT-2 inference engine |
||
khoj | an intriguing personal assistant based on local data |
|||
promptfoo | A tool for testing and evaluating LLM prompt quality. |
|||
2023-06 | SuperAGI | another AutoGPT-like harness for building GPT agents |
||
2023-05 | ChainForge | a visual programming environment for benchmarking prompts across multiple LLMs |
||
langflow | a node-based GUI for quick iteration of langchain flows |
|||
2023-04 | Auto-GPT | an attempt to provide ChatGPT with a degree of autonomy |
||
2023-03 | dalai | An automated installer for LLaMA |
||
llama.cpp | A C++ port of Facebook’s LLaMA model. Still requires roughly 240GB of (unoptimized) weights, but can run on a 64GB Mac. |
|||
minillm | A GPU-focused Python wrapper for LLaMa |
|||
simple-llama-finetuner | A way to do LoRA adaptation of LLaMa |
|||
chatbot-ui | a more or less sensibly designed self-hosted ChatGPT UI |
|||
content-chatbot | A way to quickly create custom embeddings off a web site |
|||
chatblade | a CLI wrapper for ChatGPT |
|||
GPTQ-for-LLaMa | a way to quantize the LLaMA weights to 4-bit precision |
|||
llama-rs | A Rust port of llama.cpp |
|||
alpaca-lora | Another way to do LoRA adaptation of LLaMa |
|||
Vector Databases | 2023-08 | vectordb | A simple vector database that can run in-process |
|
marqo | A vector database that performs vector generation internally |
|||
2023-07 | chroma | an embedding database |
||
USearch | A Single-File Vector Search Engine |
|||
Workflows | danswer | a pretty complete GPT/search integration solution with GitHub, Slack and Confluence/JIRA connectors |
||
Multi-modal Models | Samples | 2024-02 | ml-mgie | instruction-based image self-editing |
NeRFs | Tools | 2022-12 | nerfstudio | A tool for manipulating Neural Radiance Fields (NeRF) and rendering the scenes out as video |
Speech Recognition | Models | 2024-01 | WhisperLive | a real-time text-to-speech system based on Whisper |
2023-11 | distil-whisper | a distilled version of whisper that is 6 times faster |
||
2022-12 | whisper | a general purpose speech recognition model |
||
2022-02 | whisper.cpp | a C++ implementation of whisper that can run in consumer hardware |
||
Tools | 2023-12 | insanely-fast-whisper | An opinionated CLI for audio transcription |
|
Speech Synthesis | Models | 2024-01 | Real-Time-Voice-Cloning | a PyTorch implementation of a voice cloning model |
WhisperSpeech | a text-to-speech system built by inverting Whisper |
|||
2023-12 | StyleTTS2 | A text to speech model that supports style diffusion |
||
Stable Diffusion | Apps | 2023-03 | swift-coreml-diffusers | Hugging face’s own app, using Swift and CoreML for Apple Silicon |
2022-11 | Draw Things | Pre-packaged app for iOS, downloads and allows re-use of .ckpt files. |
||
DiffusionBee | Pre-packaged app for macOS (M1 and Intel) |
|||
CGI | 2023-03 | Blender-ControlNet | A Blender plugin to generate ControlNet inputs for posing figures |
|
2022-12 | dream-textures | A Blender plugin for texturing models based on a text description. |
||
Implementations | 2023-10 | OnnxStream | Stable Diffusion XL 1.0 Base on a Raspberry Pi Zero 2 (or in 298MB of RAM) |
|
Libraries | 2024-01 | sd4j | a Java library for Stable Diffusion that uses ONNX |
|
Models | 2023-03 | Upscale Model Database | Too wide a choice, perhaps |
|
2022-12 | Fast Stable Diffusion | Another tactic to accelerate inference |
||
CoreML Stable Diffusion | Apple’s optimizations for CoreML |
|||
Reference | 2024-01 | comflowy | a set of reference workflows and documentation for ComfyUI |
|
Tools | 2024-03 | comflowyspace | a ComfyUI desktop wrapper |
|
2023-10 | ComfyUI-AnimateDiff-Evolved | An AnimateDiff integration for ComfyUI |
||
ComfyUI-Manager | A component manager for ComfyUI |
|||
2023-08 | stable-diffusion.cpp | stable diffusion inference on the CPU, in pure C++ |
||
Opendream | A layer-oriented, non-destructive editor |
|||
2023-03 | ComfyUI | pretty impressive node-based UI |
||
InvokeAI | A polished UI |
|||
2022-11 | imaginAIry | Works well on Apple Silicon, pure CLI interface to all SD models. Does not reuse .ckpt files, however, so requires separate disk cache. |
||
2022-08 | Stable Diffusion WebUI | Nearly always the best, bleeding edge WebUI for SD |
Woke up in a country where the right-wing party increased their representation four-fold, wherein by “right-wing” I actually mean “those who do not know history are doomed to repeat it” or far, far worse. I have full faith in incompetence to assert itself over time, but it’s going to be a rough ride.
And yes, there’s a metaphor in the way Internet Explorer crashes the whole thing.
Pretty impactful corporate reorg dropped–at about the same time as my building water main ruptured.
As Douglas Adams famously quipped, I definitely can’t get the hang of Tuesdays.
Before that happened:
snapdrop
fork to GitHub. Needs a few more tweaks and excision of odd bits of code, but has held up to regular use over the past few weeks.SKADIS
pegboard at lunchtime, which of course meant 3D printing some hooks and adapters.Nothing much happened after that that I can mention. I was too busy dealing with the fallout from the water main and the reorg, and that went on for a while.
It leverages the DDC
protocl and is written in Swift.
Not sure if genius, madness, or both, but generating near real time video of performance stats and viewing it in picture in picture mode is not exactly the first approach that comes to mind for designing an operating system monitor…
This page is a stub.
RAM
LCD
and potato webcamSSD
(I upgraded to 128GB)USB-A
portsSD
card slot (which does not work in all OSes)HDMI
outFinally, it is powered by a small barrel jack (plug is 3mm wide, 7.5mm deep, ~1mm bore). That takes 19V/3.42A, ~65W, so can be powered by a $2 USB-PD
adapter in theory, although it will have to be an external one.
The case is plastic, and yet the thing seems pretty much indestructible. The battery still claims to last 6 hours on occasion (more like three, really, but it’s still useful), and I tend to use it as a travel laptop when on vacation.
Once unlocked, you can use SeaBIOS
to install a normal Linux system. Mine started out with Lubuntu 14.04 and is (in 2024) running Fedora 39.
Edit /etc/default/grub
and add tpm_tis.force=1
to the default boot options to work around a delay in booting.
This script was required to compile a set of suitable kernel modules to support the trackpad. It took a fair amount of time to come up with sensible sensitivity settings that allowed for two-finger scrolling the “right” way.
Those were added as an LXDE startup script, since it is easier to tweak than X11 configs:
#!/bin/sh
echo "Areas"
synclient AreaRightEdge=850 AreaLeftEdge=50
echo "Pressure"
synclient FingerLow=10 FingerHigh=16
echo "Buttons"
synclient TapButton1=1 TapButton2=3 TapButton3=2
echo "Scroll"
synclient VertScrollDelta=-19 HorizScrollDelta=-19 HorizTwoFingerScroll=1
Bound these using obkey to Super+<key>
:
pactl set-sink-mute 0 toggle pactl set-sink-volume 0 -- +5% pactl set-sink-volume 0 -- -5% xbacklight -inc 5% xbacklight -dec 5%
…but using xbindkeys
seems to be a better option. Here’s a configuration file for it, taken from here.
As always under Linux that is a work in progress, which is a shame considering that Chrome OS works flawlessly.
The following steps gave me workable suspend/resume in Lubuntu at the expense of Bluetooth (they are not necessary for Fedora anymore, but I do get the occasional slowdown on resume, so I’m keeping the notes around)
/etc/pm/sleep.d
and set it executable with chmod +x
/etc/rc.local
GRUB_CMDLINE_LINUX_DEFAULT
in /etc/default/grub
to contain these options
sudo update-grub
and rebootAll that remains then is to set the LXDE
power manager to suspend on lid close, etc.
To get secure swap to work properly, you need to patch the ecryptfs-setup-swap
script to include an offset=8
option in /etc/crypttab
. This appears to be an Ubuntu bug,which, unaccountably, hasn’t been caught during testing or fixed yet.
alias pbcopy="xclip -selection c" alias pbpaste="xclip -o"
Woke up at 4AM, which kind of set the mood for the day.
Had to make a trip to the office again, which is becoming far more usual this year than I expected, so my free time was shot.
PCB
s and where I could fasten both an endoscope camera and a large (20cm across) Fresnel lens I have someplace. And yes, I should get a soldering microscope, but all the nice HDMI
ones are outrageously expensive.PETG
holders to fasten them to the SK1.I have only vague recollections of the day, which was so productive work-wise that it risked spilling over and nuking my quality time.
iGPU
side. I suspect that 30fps with some aliasing tweaks are entirely possible, but am going to move on to other workloads ASAP because I need to get back to my AI stuff.Woke up at 4AM again with a splitting headache (either travel doesn’t agree with me or late night meetings, and I suspect both).
XFCE
remote desktop to start a Basilisk build in the wee hours of the morning. I have plans for something portable, but am not sure it will get done this month. I would love to join the Global AppleTalk Network people are setting up, because it is so wonderfully nostalgic…Miserably rainy day. Woke up exhausted.
btop
, which despite looking either like a “l33t” tool or like pants on a standard terminal is a great all-in-one solution for monitoring CPU, GPU, I/O, disk usage and network traffic and saves me the trouble of constantly installing iotop
and htop
.from os import environ, listdir, makedirs
from os.path import join, exists, getmtime, isdir
from shutil import rmtree
from json import loads
from asyncio import run, create_task, sleep, create_subprocess_shell
from asyncio.subprocess import PIPE, STDOUT
from aiohttp import ClientSession
from logging import basicConfig, INFO, DEBUG, WARNING, getLogger
basicConfig(level=INFO, format='%(asctime)s %(levelname)s %(funcName)s:%(lineno)s %(message)s')
log = getLogger(__name__)
PROJECTS = environ.get('PROJECTS', 'Ryujinx/release-channel-master').split(',')
ARCHIVE_PATH = environ.get('ARCHIVE_PATH', 'releases')
RELEASE_COUNT = int(environ.get('RELEASE_COUNT', 5))
async def fetch(path: str, url: str) -> None:
proc = await create_subprocess_shell(f"wget -P {path} -N {url} -qnv", stdout=PIPE, stderr=PIPE)
log.info(f"fetching {url} to {path}")
stdout, stderr = await proc.communicate()
log.debug(stdout)
log.debug(stderr)
async def main() -> None:
async with ClientSession() as session:
for project in PROJECTS:
log.debug(f'Fetching releases for {project}')
async with session.get(f'https://api.github.com/repos/{project}/releases') as response:
data = await response.json()
filtered_data = [element for element in data if ((element["draft"] != True) and (element["prerelease"] != True))][:RELEASE_COUNT]
for release in filtered_data:
folder = join(ARCHIVE_PATH, project, release['tag_name'])
if not exists(folder):
makedirs(folder)
for asset in release['assets']:
if not exists(join(folder, asset['name'])):
create_task(fetch(folder, asset['browser_download_url']))
await sleep(0.1)
folders = [f for f in listdir(join(ARCHIVE_PATH, project)) if isdir(join(ARCHIVE_PATH, project, f))]
log.info(f"checking for old releases in {project}")
if len(folders) > RELEASE_COUNT:
folders.sort(reverse=True)
folders = folders[RELEASE_COUNT:]
for folder in folders:
log.warning(f"removing {project} release {folder}")
rmtree(join(ARCHIVE_PATH, project, folder))
if __name__ == '__main__':
run(main())
Decided this was going to be a procrastination-friendly weekend, so after reading the news I went full on random geekery mode:
moonlight-embedded
on a Raspberry Pi Zero 2W and actually played stuff on it:This may turn out to be addictive, but not yet. I don’t really fancy accumulating pretty dust collectors and am happy with sticking to functional parts…
Election day, which I had completely forgotten about. I mean, it’s not as if Portugal has been under particularly effective government for a few years now.
IKEA
for a bit of strategic storage implement acquisition (I always knew there would be a pegboard in my life sometime).VINDSTYRKA
air quality sensor (that uses Sensirion hardware and Thread) to try out, because my homegrown solution is tying up a Zero W I have other uses for and the poor Enviro+ board design generates inaccurate temperature readings since the cursor is too close to the Pi CPU. I do lose the ability to do my own metrics, but the VINDSTYRKA
“just worked”–I paired it with my zigbee2mqtt
network by tapping the pair button four times (took me a while to figure that out, as it isn’t documented in the booklet), and it immediately popped up in HomeKit and I can get centralized metrics from it, so… Net win, I guess. And yes, I’ll be checking the actual metrics in detail as soon as I have some time (I’ve got a vague “revise home IoT telemetry” entry in my TODOs since last year).ollama
on my test machines and resumed fiddling with LLM
s–this time I did some RAG
over my notes, which might not have been the best of ideas:Decided to call it a day and do non-computer stuff afterwards.
Update: I went to check on my desktop Mac (a Mac Mini M2 Pro) and it had spontaneously rebooted barely 15 minutes before I got to it. I started digging into the logs (
log show --last 45m
is your friend) and saw nothing obvious except this:
... 2024-03-10 18:43:55.246304+0000 0x1743 Default 0x0 0 0 kernel: (AppleThunderboltNHI) AppleThunderboltGenericHAL::lateSleep - complete - took 0 milliseconds 2024-03-10 18:43:55.246312+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformSleepAction -> AppleThunderboltHALType5 2024-03-10 18:43:55.246326+0000 0x1743 Default 0x0 0 0 kernel: (AppleThunderboltNHI) AppleThunderboltGenericHAL::lateSleep - complete - took 0 milliseconds 2024-03-10 18:43:55.246332+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformSleepAction -> AppleThunderboltHALType5 2024-03-10 18:43:55.246346+0000 0x1743 Default 0x0 0 0 kernel: (AppleThunderboltNHI) AppleThunderboltGenericHAL::lateSleep - complete - took 0 milliseconds 2024-03-10 18:43:55.246355+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformSleepAction -> AppleThunderboltHALType5 2024-03-10 18:43:55.246369+0000 0x1743 Default 0x0 0 0 kernel: (AppleThunderboltNHI) AppleThunderboltGenericHAL::lateSleep - complete - took 0 milliseconds 2024-03-10 18:43:55.246378+0000 0x1743 Default 0x0 0 0 kernel: PMRD: trace point 0x18 2024-03-10 18:43:55.246641+0000 0x1743 Default 0x0 0 0 kernel: PE_cpu_power_disable>turning off power to cluster 1 2024-03-10 18:43:55.246810+0000 0x1743 Default 0x0 0 0 kernel: PE_cpu_power_disable>turning off power to cluster 2 # Last line before crash 2024-03-10 18:43:55.246836+0000 0x1743 Default 0x0 0 0 kernel: PMRD: trace point 0x19 2024-03-10 18:52:57.788824+0000 0x1743 Default 0x0 0 0 kernel: PMRD: trace point 0x23 # ^^^ First line after crash #...lots of IOPlatformQuiesceAction -> AppleT8101GPIOIC and similar stuff elided 2024-03-10 18:52:57.788995+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 1 2024-03-10 18:52:57.789010+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 2 2024-03-10 18:52:57.789017+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 3 2024-03-10 18:52:57.789026+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 4 2024-03-10 18:52:57.789039+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 5 2024-03-10 18:52:57.789041+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592453]: arm_cpu_init(): cpu 1 online 2024-03-10 18:52:57.789054+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 6 2024-03-10 18:52:57.789055+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592462]: arm_cpu_init(): cpu 2 online 2024-03-10 18:52:57.789057+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592458]: cpu_start() cpu: 5 2024-03-10 18:52:57.789068+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 7 2024-03-10 18:52:57.789080+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 8 2024-03-10 18:52:57.789086+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592498]: arm_cpu_init(): cpu 4 online 2024-03-10 18:52:57.789098+0000 0x1743 Default 0x0 0 0 kernel: cpu_start() cpu: 9 2024-03-10 18:52:57.789100+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592508]: arm_cpu_init(): cpu 5 online 2024-03-10 18:52:57.789111+0000 0x1743 Default 0x0 0 0 kernel: PMRD: trace point 0x22 2024-03-10 18:52:57.789113+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592522]: arm_cpu_init(): cpu 6 online 2024-03-10 18:52:57.789121+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformWakeAction -> AppleThunderboltHALType5 2024-03-10 18:52:57.789134+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformWakeAction -> AppleThunderboltHALType5 2024-03-10 18:52:57.789145+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformWakeAction -> AppleThunderboltHALType5 2024-03-10 18:52:57.789150+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592555]: arm_cpu_init(): cpu 8 online 2024-03-10 18:52:57.789152+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592564]: arm_cpu_init(): cpu 9 online 2024-03-10 18:52:57.789165+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformWakeAction -> AppleThunderboltHALType5 2024-03-10 18:52:57.789167+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592564]: arm_cpu_init(): cpu 9 online 2024-03-10 18:52:57.789169+0000 0x1743 Default 0x0 0 0 kernel: [ 7257.592564]: IOPlatformWakeAction -> AppleThunderboltHALType5 2024-03-10 18:52:57.789181+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformWakeAction -> AppleMCA2Switch 2024-03-10 18:52:57.789373+0000 0x1743 Default 0x0 0 0 kernel: IOPlatformWakeAction -> IODTNVRAMPlatformNotifier ...
…so I went and filed Feedback FB13682232
, in hope that Apple can make some sense of it. Smells like a kernel bug to me.
Update 2: I managed to get the panic log by logging in as an admin user, and the first lines are:
panic(cpu 0 caller 0xfffffe002fc97ce8): Wake transition timed out after 35 seconds while calling power state change callbacks. Suspected bundle: com.apple.driver.AppleThunderboltNHI. Thread 0x1bff1f.
Debugger message: panic
And guess what, this particular kind of issue with com.apple.driver.AppleThunderboltNHID
has been reported since the M1 days.
I’m going to update Feedback FB13682232
, but I’m not holding my breath given how long this issue has been around.
RK3588
, but on the AllWinner H618
SoC, which is a lower end quad-core ARM Cortex-A53 running at 1.5GHz:
Disclaimer: Orange Pi sent me a review unit (for which I thank them), and this article follows my Review Policy.
The Zero 3 is a bit of an odd duck, but with a few interesting features:
LPDDR4
RAM
USB-C
for powerI quite like to see Ethernet ports in smaller SBC
s, since it makes them more useful as thin clients, and the generous RAM
allocation is also a plus for a board this size. The rest of the specs are a mix of the usual and the unusual:
H618
SoC
with 4xCortex-A53 cores running at 1.5GHz and a Mali G31 MP2 GPU
.20U5622
Wi-Fi/Bluetooth module that supports 802.11ac at 5GHz and Bluetooth 5.0 (a pigtail antenna is supplied)HDMI
port (which is a bit of an annoyance, but I have a few cables for that)SD
card slot (which is all you get for storage, since there is no EMMC
on this board)GPIO
header (which is also a bit of an oddity, but is documented on their wiki)USB-A
ports (it has one on the main board)Given the mixing and matching that is going on in the BOM
, I suspect this board (or its ancestors) was originally designed for use in a set-top box and re-purposed for the maker market by replacing an EMMC
with a card slot, but that’s just a hunch.
As usual, getting stable, maintainable software was a bit of a challenge. While fiddling with the board I realized that it booted into a mini-userland saved to SPI
flash when no card was present (which has interesting implications for field service and is something I’d like to see more often), but booting a full OS has to be done from an SD
card.
As to Linux distributions, it took me a while to actually get around to testing it, for two reasons:
On the Android front, things are just… strange. To flash the official image to an SD
card, you need to use an extraordinarily specific Windows tool (you read that right, it does something to the partitioning scheme that apparently can’t be done with your usual dd
or Mac/Linux imaging tools), and there is no real way to customize or build your own image–so after a few weeks of poking around I gave up on that–part out of principle (it’s an unmaintainable solution) and part out of frustration.
Then I went and spent a fair chunk of time searching for a way to get a Linux image I could easily maintain or upgrade, and things were better, but still far from perfect.
There are unofficial Armbian images available, but even though the wiki had quite a bit of documentation, it took me a while to realize I had to use specific system images for the 4GB RAM
version of the board.
And, you guessed it, there were no prebuilt ones. This is apparently due to the need of having specific DTB
files for uboot
depending on board version, and instructions for patching the images were a bit hard to find (they are in Chinese, which I personally don’t really mind, but by that time I was already out of time).
So, in short, the software situation is a bit… complicated. And for folk like me, who are used to embedded systems and can boot their own kernels, Orange Pi does have build instructions for building a Linux 6.1 kernel on GitHub.
But since at the time I was already trying to backport an RK3588
kernel to Armbian, I just didn’t have the time to deal with another SoC
and its quirks.
I eventually flashed the official Debian desktop image onto a 32GB SD
card, and even though the system booted to a US English locale, I still had to do a few changes:
huaweicom
repository from apt
sources, because, well… I’d rather update from other places, or use geo-distributed mirrors.xfce-terminal
, because (as usual in Chinese distributions) the default terminal is picked due to its ability to display Hanzi.firefox-esr
as a browser since it was lighter than Chromium.avahi-daemon
and nss-mdns
to be able to ssh
into it using hostname.local
and discover my other machines on the network.I was also pleasantly surprised by orangepi-config
, which is pretty feature-packed:
Running Debian, I measured the bare board at the USB-C
port, and saw it taking in a maximum of 2.2W while booting without anything connected, and idling at 0.8W in the same situation.
Plugging in a keyboard and mouse bumped these by almost 1W, and adding Ethernet another 0.3W.
With a monitor, keyboard and mouse plugged in, it was taking in a little above 2W idle, which is in line with expectations for a board with this kind of feature set.
With my original idea of flashing Android on it and test Moonlight alongside the Logitech G CLoud out the window, I plugged the Zero 3 into an LCD
panel I have on my electronics bench and used it to look up documentation and well as a thin client to connect to my desktops.
And it worked–pretty well, really. With 4GB of RAM
and a quad-core CPU
, it was snappy enough to open PDF
s and browse the web (as long as you don’t expect to watch a lot of video–anything over 720p was a bit sluggish):
I used it without the expansion board, since the keyboard I was using has a built-in USB
hub (and didn’t need audio), and it was almost invisible thanks to its small size.
So as a thin client, yes, it does work perfectly–I had zero issues with performance over VNC
or RDP
on the 1080p display I was using. And I did eventually try out Moonlight as well, although clearly the Linux image I was using was not optimized for making the best out of the Mali G31 GPU
:
The Orange Pi Zero 3 is a strange SBC
. Like many, it is let down by its software support, but the only real flaw I can point to hardware-wise (within comparable boards) is the lack of an EMMC
.
I would have loved to have a good, easy way to run Android on it (where the GPU
would shine), but as a Linux board I see it as being more useful for thin clients and running Klipper/Octoprint alongside a 3D printer than, say, digital signage (since the video decoding is lacking), but it’s a very capable one.
It is a bit of a shame that it doesn’t ship with EMMC
storage. But overall it is a capable board that can be used for a variety of purposes.
My plans for it are to (eventually) build it into a monitor (the panel on my electronics desk is just bare, literally hanging by the driver board, and I have been slowly designing a suitable enclosure). That way I can use it as a thin client, and, eventually, plug in my oscilloscope via USB.
But given its small size (it’s almost exactly the size of the now useless LCD on my KP3S Pro), I’ve also considered using it to run Klipper (although with 4GB of RAM
it could probably handle two or three printers), and I suspect a lot of people will find the lower-specced boards pretty handy for that.
Another use (given its Ethernet port and low consumption) is as a home router “sidekick”–you can confidently power it off a USB
port on your router and use it to run Pi-hole
for ad blocking or OpenWRT
for a personal VPN–which would be a nice and compact way to add those features to a home network.
It is a CoreXY machine with a 256×256×256mm print volume, direct drive extrusion and shipping with Klipper firmware.
Category | Date | Link | Notes |
---|---|---|---|
Models | 2024 | Two Trees SK1 Base Plate STL | A base plate STL to include in SK1 print profiles |
Mods | Bowden tube guides | A set of guides for placing the Bowden tube differently |
|
Fan Shroud with LED mountings | Allows you to mount Voron-style LEDs near the nozzle and makes it easier to remove for maintenance |
||
120mm fan adapter for the mainboard | A mount for a 120mm fan to cool the mainboard |
||
Aux fan holder | A mount for an auxiliary 12032 part fan |
||
Anti-vibration feet | These take third-party rubber feet from the Bambu P1P |
||
Webcam mount | A mount for the Creality K1 Webcam |
Reading through this makes me realize there has been no real progress on app distribution or improvements in Apple’s App Store ecosystem regarding openness over the part decade, and that besides these changes flying in the face of EU requirements, real, live, actual sideloading is still a pipe dream–there is absolutely no way it’s become feasible for the individual user, and new app stores and browser engines are still hampered by various restrictions.
(As an aside, I am particularly amused at the availability of game streaming apps, and would like to take this opportunity to thank Apple for forcing me to buy an NVIDIA Shield to use them for the past four years, because it has turned out to be a much better piece of hardware than the Apple TV, which they continue to blunder and neglect as a product–but I digress.)
Most of the “additions” like payment features and NFC access are things that should have been there from the start, and it is clear to anyone with a modicum of technical knowledge (let alone folk like me who worked literally decades in the mobile industry) that Apple has done the absolute minimum to “comply” to a degree that should be transparent to even the dimmest bureaucrats in Brussels.
Your move, EU. And try to make sure fining Apple for hindering music streaming wasn’t a one-off heavily driven by industry lobbyists, OK? Because multi-year investigations just don’t cut it anymore.
Ouch. Of course the source code is still out there, but the more important question is whether this will have a chilling effect on other emulator projects. US$2.4M is a significant sum of money and a clear signal that Nintendo is willing to go after the people behind these projects.
I expect a great deal of discussion about the legality of emulation to ensue, but the fact remains that not actually going to trial also means there is no legal precedent set either way…
But yes, again, this is why we can’t have nice things, like playing Breath of the Wild at 4K with immersive rendering. Or play the games from a previous console generation without paying twice for them. Or, you know, have a backwards-compatible console.
Oh, wait, there is one.
Update: and now Citra, the 3DS emulator, is gone too. Considering the platform is dead and Nintendo closed the e-shop last year, this is a bit sadder.
I’ve been following this discussion for a week now due to my Two Trees SK1 testing and it’s just been merged into OrcaSlicer.
In short, this allows you to almost completely hide the seams in most 3D prints, and you can test it now if you run a nightly build (which I will be doing ASAP).
Another rough night. Spent the morning nursing a mild headache and clogged sinuses, and tried getting up to speed by pumping up the bass:
defaults write com.microsoft.rdc.macos AvcSupportLevel avc444
in order to try to resolve my RDP
woes with older xrdp
responsiveness on the Mac. Felt more like voodoo than anything else.RDP
servers with sane encodings and at least as fast rendering as FreeRDP
, without any hassle. The only downside is that it is your stereotypical Swiss Army knife IT administration tool, packed with extraneous features and dialogs and panes – but you can dial back the clutter, and I’m quite enjoying it that way.FreeRDP
build tree, which was sorely mangled. There are more interesting yaks to shave now.An utterly chaotic, stressful day. I really, really can’t get the hang of Tuesdays sometimes.
Almost made up for Tuesday. Had a great lunch (which was more than I bargained for exercise-wise), the high point of a blissfully meeting-free day (albeit with a lot of e-mailing and slide tweaking).
ffmpeg
script to generate compact, bandwidth-efficient slideshows for sets of images in a moderately sane way. I had forgotten xfade
and drawtext
could be that flexible, perchance because mixing them is a rather traumatic process.STL
viewer to the site, now that ThreeJS and WebGL
are common enough for it to be useful across the board (yeah, I know I’m late to the party)Narrator: that was not a good idea.
Woke up at 7:30 realizing that the water mains was going to be shut down at 8:30. Breakfasted and showered in the nick of time, then nested in the couch for half the morning poking at e-mail and nursing a sleep deprivation headache.
MIDI
connectors I had been waiting for for one project and (annoyingly) a few integrated circuits that my sleep-deprived brain could not remember what I wanted for. This is one of the pitfalls of doing some twenty things at once over long periods of time…CUDA
stuff I want to test.ffmpeg
script, this time to re-encode short videos, capture a poster image and spit out a ready-to-paste HTML
template for adding them to blog posts:#!/usr/bin/env python3
from os import system
from os.path import splitext
from argparse import ArgumentParser
def remux_file(input, output="remux.mp4", crf=20, bandwidth=3000, bitrate="96k", height=720):
cmd = ["ffmpeg"]
cmd.append(f"-i {input}")
cmd.append("-filter_complex")
filter_spec = []
filter_spec.append(f"[0]scale=-2:{height}[out]")
cmd.append('"' + "; \\\n".join(filter_spec) + '"')
cmd.append(f'-map "[out]" -map 0:a -b:a {bitrate} -c:a aac -b:v {bandwidth} -pix_fmt yuv420p -c:v libx264 -r 25 -crf {crf}')
cmd.append(output)
res = system(" \\\n".join(cmd))
res = system(f"ffmpeg -i {output} -vf 'select=eq(n\,0)' -q:v 5 {splitext(output)[0]}.jpg")
if not res:
print(f"""
---[HTML TEMPLATE]---
<figure>
<video controls muted style="width: 100%" poster="{splitext(output)[0]}.jpg">
<source src="{output}" type="video/mp4">
</video>
<figcaption>
A {height}p video at {bandwidth}bps
</figcaption>
</figure>
""")
def main():
parser = ArgumentParser(description="Convert a video to a standardized .MP4 envelope")
parser.add_argument("input", metavar="I", type=str, help="input file")
parser.add_argument("--height", type=int, default=720, help="vertical resolution of the output video")
parser.add_argument("--crf", type=float, default=25, help="quality of the output video (lower is better. 23 is the ffmpeg default, 0 is lossless, 51 is the worst possible quality)")
parser.add_argument("--bandwidth", type=float, default=1500, help="bandwidth of the output video (higher is better)")
parser.add_argument("--bitrate", type=str, default="96k", choices=["96k", "128k", "160k", "320k"], help="bitrate for the audio (one of 96k, 128k, 160k, 320k)")
parser.add_argument("--output", type=str, default="remux.mp4", help="The output file")
args = parser.parse_args()
remux_file(args.input, args.output, args.crf, args.bandwidth, args.bitrate, args.height)
if __name__ == "__main__":
main()
Writing and publishing day.
cSpell
and its own dictionary settings.Had a properly productive morning and then proceeded to turn the rest of my free time into a relaxing yak shaving day.
git
is a fickle mistress.In short, the Two Trees SK1 is a CoreXY 3D printer with a 256×256×256mm print volume, direct drive extrusion (atop an all-metal hot end rated for 300oC), a 32-bit MCU
and the ability (thanks to Klipper firmware and solid hardware) to print at ludicrous speeds.
I will unpack the above paragraph throughout the rest of the post for folk not into the lingo, but for those who are, the bottom line is that it is a workhorse printer that is certain to appeal to people setting up print farms, and, for various reasons I will also get into, it is especially attractive anyone using (or considering) Bambu Lab printers like the P1P.
Disclaimer: Two Trees supplied me with a review unit free of charge, and, as usual, this piece follows my review policy.
To understand why I like this machine, it important to take a little detour and list the five critical aspects I take into account when evaluating a 3D printer:
This is because even though I quite enjoy the process of building and tweaking printers, I use them as tools.
My main use of 3D printers is to create functional parts and electronics casings of various sorts, and as such I have a strong preference for printers that are easy to use, reliable and maintainable, with very few frills–with the caveat that I am willing to put in a little time to tweak and maintain them, just as I would with any other tool.
3D printers tend to be sturdy machines, but there has been a tendency towards using custom parts and non-standard components in the past few years, which makes them harder to maintain and upgrade. Since my first printer is still working and I can replace parts myself, I have a strong preference for printers that buck that trend.
As it happens, a great deal of the sophistication (and performance) of modern 3D printers is tied to their on-board firmware. In an age where most electronics is either locked down or has a short lifespan, I have a strong preference for open source firmware and software that can really control what the printer is doing as well as allowing for feature upgrades over time, and I have been using Klipper because of that.
If you’ve never paid attention to this space, Klipper firmware is a sophisticated combination of C and Python that has, over the course of the past couple of years, added a surplus of raw speed, printing quality, ease of use and ease of updates to the equation, and pretty much upended the entire industry of FDM printing in the process.
Instead of low-end 8-bit MCU
s sedately nudging 12V stepper motors along in a traditional bed slinger as they parse G-code, we now have entire Linux environments running Python-based software to process, optimize, and schedule motion paths that are then carried out by more modern MCU
s and high torque steppers in various configurations, in a way that is both faster and more accurate than anything that came before.
And the Two Trees SK1 is pretty much a product of its time–it is a very fast and precise CoreXY machine with a comfortable print volume, direct drive extrusion (i.e., the extruder sits on the print head atop an all-metal hot end that should be able to handle materials well beyond the usual PLA
and PETG
), and an on-board install of Klipper right out of the box.
I’m going to save you the trouble of looking through photos of a large, quite well protected metal frame inside inch-thick packing foam and reinforced cardboard, because the only real issue I had with unpacking it was finding a roomy enough place to do so.
Given the size of the frame, all the extras (a small PLA
spool, cables, spare parts, booklets and the usual tools etc.) fit with room to spare in a box shipped snugly inside the printer, and the entire thing came encased in very thick foam (pro tip: save it because it is great for doing maintenance or dampening vibrations).
Mind that this is not a beginner’s printer, and that I am not reviewing it as such. The docs are sparse and there are no glossy booklets or tutorials. You get a USB
drive in the box with a few slicer profiles and a few STL
files for testing, but like many Chinese-brand printers, there is an unwritten assumption here that if you get this, you know what you are doing.
All I had to do to get it running was to assemble the screen (two screws for the clip, then cable and slot it in) and remove a few plastic brackets that held the gantry in place for shipping. After that I noticed the belts were a little loose (which is a reasonable thing to do for shipping), tensioned them and powered on the machine.
I then realized I had to re-organize my office a bit, since it is a fair bit bigger than the other printers I have–thank goodness for wide angle lenses, because 3D printers can take up a lot of volume:
A nice thing about the SK1 is that it is exactly the size to fit atop an IKEA KALLAX
, which is what I use as low-cost, low-profile storage in my office. A few centimeters more and it would hang off the front or back.
All modern printers come with a screen and a set of basic controls, and the SK1 is no exception. The screen is a 4.3” capacitive touch panel that feels a bit laggy, but suffices for basic tasks like loading filament, calibration and stopping prints.
After a few seconds of animated logo, it guided me through the initial calibration stages.
Since the printer has three independent Z axis steppers (like the RatRig V-Core 3.1 and the Voron Trident Kit I have been thinking of building for a while now), it will level the bed using a three-point measurement and then do a full a 6x6 mesh.
With that done, it will take a few minutes to exercise the steppers at various frequencies so it can perform resonance compensation measurements for improving print quality–all of which are hallmark features of Klipper machines.
Note: besides an accelerometer, The print head has a dedicated
PCB
that includes an inductive probe, so be sure to keep yourPEI
coated steel sheet in there at all times, lest it crash into the bed)
From then on you’ve only to pick a Wi-Fi network (2.4GHz only, alas) or plug it in via Ethernet (which I didn’t yet–I’m waiting for a dedicated switch for this side of the office–but which I think ought to be a standard feature in all printers).
I have a feeling Two Trees was just a couple of centimeters short of being able to make this a 300×300mm machine–it would have been a bit tight with the triple Z axis and the relatively large print head (plus the gantry), but there is quite a bit of clearance around the print bed, which is good news since it means there is certainly room for an auxiliary part cooling fan.
The supplied PEI
-coated steel sheet has a couple of alignment notches that line up with mounting screws to keep it straight on the magnetic bed, which is a nice touch. But en even nicer touch is that the printer includes an LED strip that lights up the print bed–which is a feature I have had to improvise on my other printers and is a very welcome addition.
No camera is included, and there are no obvious mounting points for one inside the frame, but it seems possible to add one (I certainly have small cameras that would fit in the upper corners of the frame next to the LED strip).
The SK1 is, in two words, unapologetically metal. Yes, I know I overuse that reference, but it’s warranted here.
Every component your eye rests upon looks and feels solid. Everything but the print head cover is metal, and a lot of it is familiar parts: There are custom brackets and spacers in a few places, but the linear guides, pulleys, Z-screws and pretty much every kinematics component is something you can theoretically replace, and it feels very well put together.
And yes, comparisons with the Bambu Lab P1P are unavoidable, given that they share the same bare metal open framework look, general kinematics and build volume.
However, there are several differences between the SK1 and the P1P that are worth noting at this point:
Having upgraded my KP3S Pro with linear rails and bought the exact same Z screws and some brass lead nuts to upgrade my Prusa clone, I really appreciate that the SK1’s rails, lead screw nuts and print bed assembly seem to be standard parts.
As far as physical maintainability, the only two drawbacks I could see were the wide variety of screws used (from Philips M1 to hex head M3 and M4s, something that anyone who’s built kits will invariably find too diverse), and the print head assembly, which is a custom injection moulded part that includes the hot end, extruder and the inductive probe, with the cover held in place by a few Philips screws and the extruder tensioner.
However, the overall assemblies are easy to access, so doing things like replacing a belt should be straightforward:
There are no visible end stops, limit switches, etc. It all seems to be handled by the steppers and the inductive probe.
As to the kinematics themselves, the X/Y steppers are Usongshine US-17HS6001S-26B
motors, which are pretty beefy–they’re 480g in weight each, and rated for 1.7A current and a torque of 70Ncm, which is perhaps 50% above what you’d see in steppers for large(ish) printer beds. Comparatively, the 3 steppers that handle the separate Z-axis are, I think, rated for around 40Ncm (I have since lost track of the data sheet for those).
One of the first things I did after unpacking and testing the printer was to take a look at the internals. The bottom panel is held in place by a few screws and the electronics are all easy to access:
Note the placement of the cooling fans, especially the pair blowing across the drivers. These are a tad noisy (more on that later), but quite effective at keeping the board cool, and aligned with cutouts in the bottom panel to let the air flow through.
Looking more closely at the board, there are a lot of familiar components:
The board is a combined MCU
and Linux
board, with the main CPU having 1GB RAM and a direct connection to the STM32F402
MCU
. The Wi-Fi chip is an AP6212
variant that appears to only have 2.4GHz support (at least based on what I’ve seen it do so far), and the Ethernet interface is 100Mbps–either of which are more than enough for a 3D printer (and the Ethernet port is a welcome sight).
Besides the two USB
ports there is also an RJ11
port that seems to be for “screen expansion”, so I assume it’s another serial port.
I especially liked to see the extra fan connectors on the top left of the board, which means there is room for expansion and having an enclosure fan (Two Trees confirmed an enclosure kit is planned, but I have no details).
Even though that single GB of RAM worries me a bit (it may not be enough for handling extremely complex models down the line, which is something I’ve come up against in the past on 512MB Raspberry Pis) we have a lot of processing power here compared to older generations of 3D printers, and a set of well-known, recent components that are likely to be supported for a long time to come.
I don’t print any exotic materials (my open frame bed slingers can’t handle them, although I’ve been wanting to print ASA
and carbon fiber materials for a few small, tough parts), so I can’t say much about the 300oC rating for the hotend just yet.
But I did take a good look at the print head assembly–I have stopped short of disassembling it entirely to avoid any issues during tuning and testing, but I did take the covers off (all you need is a Philips screwdriver, which is great if you need to do it in a pinch to unclog the extruder1) and looked at the controller board and hotend assembly:
As you can see the entire assembly contains three fans, and it is those three that make the most noise (by far) while printing.
But much to my surprise, the hotend is identical to a 3rd party Bambu Lab replacement part–it has the same cooling fins, the same kind of fan, heat break, clip assembly, heater layout and silicone sock.
Comparing the SK1 to a P1P comes to mind again, and I think there’s a notable improvement here in terms of maintainability–instead of an integrated nozzle, you have removable ones. And this is amazingly great, because that means there are already dozens of replacement parts out there right now, and a sure supply in the future.
Also, the control board has free connectors, one of which is marked LED
– so I hope this will make it possible to have Voron-style LED
s illuminating the nozzle.
You get two 0.4mm hardened steel nozzles with the SK1 (one in the hotend and a spare), but neither is high flow, so I’ve since ordered (but not installed) replacement CHT
clones. As far as I can tell they are all V6-threaded, which, again, is another nod to standardized parts.
A sticking point here is that while the hotend fans appear to be easy to source, the part cooling fan seems to be a rather rare part:
LANG JIE TECHNOLOGY CO LTD
DC BRUSHLESS FAN
MODEL: LD245015B
DC 24V 0.20A
I’ve looked everywhere and I can’t find a direct replacement for it, so I hope it lasts a long time.
My first round of prints was actually just a “cold test” to see how the printer would handle a few different types of prints. I am a bit weary of the 3D Benchy that is all over YouTube videos (I printed my fair share of those, and they just take up space), so my first print was a Voron test cube, which provides you a good overview of cooling, small overhangs, etc.:
So yes, this is a pretty fast printer. And it would actually get faster as I started dialing it in.
Two Trees provides Cura and PrusaSlicer on a USB
drive, but I prefer to use either SuperSlicer or OrcaSlicer these days, so I created my own profile by reading through printer.cfg
and taking the values from the extruder and kinematics
sections in their Klipper configuration:
I also went and got this nice STL file for the print bed, and I was good to go.
And, of course, this being 2024 (and my having used things like OctoPrint for years), I didn’t use the USB
or TF
slots at all–I just connected the printer into my network and printed directly from the slicer, which is a huge improvement over the “I don’t trust any networks” workflow. And, again, unlike the P1P, this is done solely via the LAN. There are no cloud features here (which is a good thing, as far as I’m concerned).
OrcaSlicer also has the advantage that I get an embedded view of all my printer web UIs, which makes for a tidier workspace:
As you can see above, the SK1 comes with Fluidd as a web interface, which is nearly indistinguishable from Mainsail from a functional perspective–everything you’re used to is there, just in a different place, so anyone used to Klipper will feel right at home.
I have no real favorites here–I have used Mainsail on all my custom installs because it makes it easier to manage software updates by default, but I have no qualms about using Fluidd either, and managing firmware releases here will require some extra care anyway.
I have standardized my start G-code across all my printers by having each run their own calibration routines when I issue START_PRINT
, so I took the start G-code from the PrusaSlicer configuration files and edited printer.cfg
:
[gcode_macro START_PRINT]
gcode:
RESPOND MSG="Running START_PRINT"
G28 ;home
M107 ; Turn off the fan
{% set BED_TEMP = params.BED_TEMP|default(60)|float %}; Start bed heating
M140 S{BED_TEMP}
{% set EXTRUDER_TEMP = params.EXTRUDER_TEMP|default(190)|float %}
G21 ; set units to millimeters
G90 ; use absolute coordinates
M83 ; use relative distances for extrusion
G0 X0 Y0 F12000 ; Move the head to someplace it can drip
M109 S{EXTRUDER_TEMP} ; wait for extruder temp
M190 S60 ; wait for bed temp
G1 E-1 F2100 ; retract
;G32 ;Load bed mesh
;BED_MESH_CALIBRATE
ADAPTIVE_BED_MESH_CALIBRATE ; this is something I added later
G0 Z2.0 F600;
G0 X50 Y10 F12000;
G92 E0.0 ; reset extruder distance position;
G0 Z0.4 F600;
G1 X100.0 E10 F3000.0 ; intro line
G92 E0.0 ; reset extruder distance position;
G1 X200.0 E15 F3000.0 ; intro line
G92 E0.0 ; reset extruder distance position;
G0 Z0.8 F600;
G1 X100.0 E15 F3000.0 ; intro line
G1 Z0.4 F600 ;Wipe
G0 Y12 F6000 ;Wipe
G1 X100 F6000 ;Wipe
G0 Y8 F12000 ;Wipe
G1 X200 F6000 ;Wipe
G1 X190 Y12 F6000 ;Wipe
G1 X180 Y8 F6000 ;Wipe
G1 X170 Y12 F6000 ;Wipe
G1 X160 Y8 F6000 ;Wipe
G1 X150 Y12 F6000 ;Wipe
;G0 Z2.0 F600;
G92 E0.0 ; reset extruder distance position;
SET_PIN PIN=caselight VALUE=1 ; this is how you turn on the light strip
RESPOND MSG="Starting print"
I did, however, have to “fix” (read: change) a few things in the stock macros for it to work the way I wanted to, since Two Trees tried to simplify things for new users and the order in which some macros were called was different from what I expected (after my initial changes the printer would home twice on every print, etc).
If you are not the tweaking kind, this won’t affect you at all–I’m just pointing this out because people who are accustomed to building their Klipper configurations from scratch tend to be opinionated, and will do well to read through printer.cfg
a couple of times and understand how it is set up.
I plan on making my printer profile and config files available in a few months, when I’m positive I’ve dialed things in.
Over the past month the bed tramming and default 6x6 point mesh bed leveling worked really well, and I have not had to do any manual tinkering at all.
The PEI
sheet is the usual two-side textured/smooth kind (I’ve mostly stuck to the textured print surface, since I prefer that finish), and there is enough clearance even in the home position to remove the print surface.
Thanks to the alignment notches, flexing it in place to remove prints has become my preferred approach, and I’ve since seen there are third-party PEI
/PEY
flex plates out there already (or at least advertised for sale) with the same alignment notches. I intend to order one ASAP since PEI
beds, despite their hardiness, are long-term consumables and I like to have spares.
As to the heater, it is rated for 100oC, which is a tad too low for ASA
but more than enough for PLA
and PETG
–this feels a little low given that the hotend is rated for 300oC, though.
It is, in a word, impressive. Even without any real tuning and only the most bare bones slicer profile, I got some of the nicest Gridfinity boxes I ever printed.
Even with eight-year-old filament that by all accounts shouldn’t even be around anymore, it printed workable functional parts, and besides some extrusion irregularities (on that filament alone, due to some bubbling) the only thing that was noticeable were some rounded corners and seams, which is typical for PLA
without correct pressure advance settings (especially when printed at high speeds).
But for functional parts where I’m more concerned with overall dimensional accuracy2 rather than fine cosmetics, I would say print quality out of the box was great:
Over the next few weeks, as I started using the SK1 more as an actual printer rather than a test subject, results were uniformly good with either PLA
or PETG
(I used to have TPU
but ran out recently, so that will be something to test in the future).
Of course with the printer being open (and my only having open-frame printers in my office) I have not (yet) tested ABS
or ASA
, but I am looking forward to trying as soon as I can enclose the printer.
The SK1 comes with a filament holder that you can mount to the side of the machine (thankfully not in the back), and a length of PTFE
tube to guide the filament into the extruder routed through the cable chain. Given my particular layout I couldn’t use neither the holder (it is still too close to the back of the printer, and I have a wall there) nor the cable chain, and it was easy to unscrew the PTFE
guide and fasten it on the other side (where I could also use my somewhat temperamental Sovol filament dryer).
The filament runout sensor is mounted at the PTFE
insert in the print head, and is a plain, non-flow-aware switch. That meant it cannot detect pinched/stuck filament, so I had one print that failed due to that–there was filament in the extruder inlet, but it was tangled in the spool. So it was ground away and the print failed due to under-extrusion, but only stopped because I was watching it.
But while testing with brittle PLA
that broke several times, the printer did detect the breaks and prompted me to reload the filament, doing a good job of reloading it. The only issue I had was that the bed cooled down enough to loosen the print during one of the reloads (this seems to have been a one-off, since it didn’t happen in later PETG
prints where it would have been more noticeable).
I have not yet tested power loss recovery, but I have found a state file in the Klipper install, so I assume it is working.
Since I have been printing case prototypes for various projects, it wasn’t hard to find excuses to see how the printer would handle different materials and speeds:
PLA
and printed a few functional parts (an ESP32 case, a few brackets, the entire initial assembly for a 6DOF 3D mouse, etc.) This was to see how the printer would handle a material that is known to be brittle and prone to breaking during prints, and as written above it handled those fairly well.PETG
I have been avoiding using (it’s Sunlu Cherry Red, a color that for some reason is about as hygroscopic as a sponge), and that also went fairly well, although I did have to tweak the retraction settings to get rid of excessive stringing and blobs. I used this specific filament instead of TPU
(which I ran out of a few months back) to see if I would need to open the extruder to clean the gears (which has been a typical outcome of my using that filament on other printers).PLA
and Amazon Basics PETG
) to see how the printer would handle the sudden changes in direction and speed, and to assess wall finish and seams. The initial results were good considering I did zero tuning, but it was obvious I would need to tweak the pressure advance settings to get rid of overly rounded corners and bad seams.I then actually started to tune the printer to each filament using the OrcaSlicer built-in calibration prints, and the results were uniformly good when printing at speed (and excellent at more sedate paces).
The only really challenging part of this (which will be familiar to anyone who takes it seriously) is the time required to tweak pressure advance settings for the various kinds of PLA
and PETG
I have.
Finally, after I had a good feel for the printer with my usual materials, I switched to Two Trees‘ High Speed PLA
and began cranking up the speed to see how the printer would handle it, and yes, it certainly can reach the advertised 700mm/s speeds, but most of the time you’re going to be looking at this kind of speed, and it’s only really going to go beyond that for infills:
In general, across all the prints I’ve made so far, I would say printing infill at 300mm/s and outer walls at 2/3 of that would be a good lower third of what I’ve seen–and that is pretty amazing, because I was able to print parts, test their fit and finish, and then redesign and print them again (maybe even with a different material or settings) in a fraction of the time it would have taken me on my other printers.
Quick changes can take less than 5 minutes if (like me) you export and print just the redesigned sections off your CAD software (segmenting joinery, for example) and then do test fits.
Sometimes (when I use STEP
files) I can even and print them directly from the slicer, and that is a huge improvement over the usual 20-30 minutes it takes to print a small fitting.
For quick iteration, this machine is awesome, and that was the main thing I was looking for.
This is something that has been on my mind a lot of late, so the printer has been running plugged in to a Zigbee monitoring socket and I have been keeping an eye on its power consumption.
In short, it peaks at 290W heating up the bed, and will run at 196W while printing and keeping the bed warm (at least for PLA
and PETG
temperatures). There are a few small variations, but they are not significant.
However, this is not a quiet machine. Even at idle, the electronics fans (being high-RPM 40mm ones) tend to generate more noise than I would like in an office, but when printing the three high-powered tiny fans in the print head assembly can be quite loud to the point of drowning out everything else. Across various print runs, I measured 69dB
to 75dB
by holding my Apple Watch around 1m away from it inside my rather small office (which has some sound dampening hexagons in a couple of walls):
Compared to the 57dB
of my KP3S Pro (which I already find too loud) and the 40dB
of my Prusa clone, this is quite a lot. It is understandable because cooling is a perquisite for printing at these speeds, but it is something to be aware of if you’re planning to put this in a shared space. An enclosure might help (although, to be fair, it is quite likely to come with more fans).
In my office that kind of noise is a serious issue when I’m on a call (which also explains why it took me so long to test longer prints) and I have to close the door to the office to keep the noise from being too distracting when I’m in my living room.
So if you’re as averse to fan noise as I am, do consider placing the printer in a closet or garage if at all possible (I’m investigating the former, and looking at ambient noise reduction hacks in the meantime).
Amidst all this, the stepper motors are actually fairly quiet (except when printing at full speed). During bed leveling and first layers they are audible, but perfectly tolerable.
The capacitive touch screen is a key weak spot as far as I’m concerned. It works, but sometimes it lags or becomes unresponsive, displays incorrect information and has crashed on me at least twice. And it is not KlipperScreen, which is a bit of a letdown.
Build-wise it seems solid enough, but it is a bit of a letdown in terms of responsiveness and reliability. I only use screens on printers for loading/unloading filament and the most basic of things, so the most used function on the SK1 screen for me was turning the light strip on and off until I automated it.
But I can see this being an issue for regular users, since some quality of life features like preview thumbnails are not currently supported.
During more sedate moments, I investigated the software internals of the printer with some relish, since given my hardware background I always like to see how these products are built.
Internally, the SK1 comes with what appears to be a pretty vanilla Klipper install with a set of custom macros and, of course, all the right settings and tweaks for the steppers used. Two Trees chose Fluidd for its web interface, and that runs alongside the Moonraker API server and the core Klipper daemon.
Those all live on the ARM CPU
, and that, in turn, talks to three devices:
STM32F402
MCU
that handles the kinematics.RP2040
sitting on the print head that handles the extruder, filament runout sensor and the inductive probe.Nextion
-like device that has its own MCU
as well.Which means this is a great moment to look at maintaining and upgrading this printer from a firmware perspective. If you paid attention to the shots of the internals, you probably noticed there was a 4GB EMMC
chip labeled SK1 2.0.0.21 1221
. That’s where the Armbian Linux part of the firmware lives.
The MCU
part, though, goes into its own flash storage, and to update it you need to use the TF
card slot near the bottom right–and, finally, there is a third TF
card slot inside the screen.
The upgrade process for all these is well documented in a Two Trees video (and PDF
), but it does require you to open the printer, take out the EMMC
card, plug it into a supplied adapter, and then plug that into a computer to flash the firmware–and then do essentially the same with a TF
card to upgrade the MCU
s on the stepper side of the board and the screen.
This is a bit of a hassle compared to my custom Klipper installs (where I can do 90% of them over ssh
), but it is a once-in-a-while thing that, fortunately, I haven’t needed to do yet (as of the time of writing, the printer is still running the firmware it came with, and that was the latest revision).
Regardless, I should point out that a huge step up from the usual state of affairs in the 3D printing world is that it is conceivably possible to do all of these yourself and entirely offline, rather than be the mercy of the manufacturer to provide updates.
And yes, cloud updates are very, very convenient for consumers. But if you’re running a print farm, you probably want to be able to control when and how you update your printers, and the SK1 is a step in the right direction in that regard even if the process is physically convoluted.
I unpacked the firmware image and had a look at the rootfs
and boot
partitions, and it is a pretty standard Armbian
install with a few custom scripts and custom services. Most of the filesystem is ext4
, and the boot
partition is a VFAT
containing initrd
, ARM DTB
s and the usual stuff you’d expect to see in Rockchip-based device.
By this time I had already set up the printer on my network and was finding it a little odd that the clock wasn’t set correctly, so I downloaded the latest firmware image, figured out to login, and went to town:
_ _
_ __ ___ | | _____ _ __ (_)
| '_ ` _ \| |/ / __| '_ \| |
| | | | | | <\__ \ |_) | |
|_| |_| |_|_|\_\___/ .__/|_|
|_|
Welcome to Armbian 22.05.0-trunk with bleeding edge Linux 5.16.20-rockchip64
No end-user support: built from trunk
System load: 2% Up time: 13 min
Memory usage: 17% of 976M IP: 192.168.1.115
CPU temp: 40°C Usage of /: 69% of 6.6G
I’m not sharing the details because I don’t want people to break their printers on my account (and also because I hope Two Trees will not remove the functionality and even make this official in some way), but it’s all good news future-wise, since having a flavor of Armbian on board is a solid guarantee of some kind of future upgrades for both the base OS and for Klipper.
Once I was in, I did some minimal changes for sanity:
8.8.8.8
default resolver and set my LAN’s (I did’t want to mess with NetworkManager
, so I just edited /etc/resolv.conf
).twotrees-sk1
and installed avahi-daemon
and libnss-mdns
to be able to find the printer on the LAN (if you’re not familiar with this, it makes it show up on my LAN as twotrees-sk1.local
on Mac and Linux). armbian-config
to set the timezone, and refrained from touching anything else system-wise.Although I’m pretty sure I could update standard system packages without breaking anything, given the convoluted firmware upgrade process I want to have a long, hard look at the Klipper install before I risk breaking anything serious.
# Make sure I can see this from a Mac
apt install avahi-daemon libnss-mdns
# I also edited the hostname
cat /etc/resolv.conf
# Set my local LAN resolver and the systemd resolver so that this can resolve .local addresses as well
nameserver 192.168.1.1
nameserver 127.0.0.53
I did install a simple Klipper add-on – the simplest and least intrusive Adaptive Bed Mesh plugin I could find, and it has been working flawlessly so far.
But I have decided to treat this printer as an appliance rather than a computer, so I will likely not be doing any more changes to the base system (even if buster
is a little old). After a couple more official firmware upgrades, we’ll see how it goes.
I did a little digging and the display seems to be a Nextion/TaoJingChi variant, although I can’t really pinpoint the exact model. I spent a good while in the fascinating world of the Unofficial Nextion User Forum, and, in short, the screen itself is a customizable product that can be programmed using its own toolchain and a set of somewhat predefined components you can build upon.
It has its own MCU
that talks to the Klipper main board via serial on /dev/ttyS1
and a daemon process built with the Makerbase SDK (yes, I ran the binary through Ghidra, as anyone working in embedded systems would), and no, it’s not KlipperScreen.
But it’s somewhat likely that enterprising souls will be able to do something with it. And the screen was the only thing that I actually e-mailed Two Trees about–even though I will stick to reviewing what came in the box, I reported the issues I had with it and was told that there would be a new software revision “soon”.
I “replaced” it with a “Cheap Yellow Display” running CYD Klipper to see how it would fare, and even though I prefer the web interface, this has been working well enough on my desk:
I do have a crazy idea, which is to take over the connection to the existing display and set up SLIP
and a VNC
client on an ESP32
to run normal KlipperScreen. It’s been done before (just not over serial), and there are libraries available, so… Maybe someday.
Instead of plugging in a normal USB
webcam I mounted a Xiaomi 1080p HomeKit camera on the corner of the frame using its magnetic base and powered it from the printer’s USB
port, which worked great:
I prefer this setup because this camera also captures in infrared, the videos all go into iCloud storage directly and I can have a picture-in-picture view of the printer on my Mac or AppleTV, although of course I can’t do time lapses with it.
I am very happy with the SK1. It’s pretty obvious that it is first and foremost a workhorse printer targeted at people that are knowledgeable with the mechanics of 3D printing and are looking at setting up print farms–where its sturdy build, speed and remote management via Klipper are certain to outweigh the noise and lack of creature comforts like an enclosure (or even a polished screen UI). The only real question they should ask is how often they will need to upgrade the firmware, and how much of a hassle that will be.
As to me, I see this as an asset that you invest in and plan to maintain and tinker with over the course of quite a few years, so I suppose occasionally upending it, unscrewing the bottom and plugging in the EMMC
adapter in is OK (incidentally, I put mine in the neatly labeled bag it came in and stored it with double-sided tape inside the printer, where it definitely won’t get lost).
For consumers, it depends. Geeky buyers who can’t (or don’t want) to build a Voron kit or get a P1P will have a blast with it, and I think it is a great printer for people who are looking to get into the nitty-gritty of 3D printing and want to have a printer that can grow with them but understand that there is no overly polished software or hand-holding here. It is a bit of a hassle to upgrade the firmware, but there is more than enough of a standard Linux install in there to make it a very attractive proposition for people who like to tinker.
And, of course, from a purely engineering perspective the way the software works (without any cloud connectivity) and standard components throughout is a huge plus for people who are concerned about privacy and security.
For me right now, the biggest game changer has been its speed and print quality, because it’s been a big boost to my prototyping workflow. I have limited time to do some things, and with the SK1 I have been able to print and test parts in a fraction of the time it would have taken me on my other printers.
The results have been uniformly good, and there’s been a profound change on how I use the printer–I have timidly started making more use of the print volume, because I have more trust in the SK1‘s ability to print a trayful of parts in a reasonable amount of time:
Without going into price comparisons, I see the SK1 as being especially attractive to experienced 3D printer enthusiasts currently looking at the Bambu P1P or the Creality K1 and who understand the internals of Klipper. And there are quite a few nice things here–you’re essentially having to choose between curated ecosystems with proprietary applications, firmware and parts (although Creality does allow you to access the firmware) and something that might (with luck, granted), require less hassle to maintain and replace parts in the long run.
Of course the fact that the SK1 can use Bambu clone hotends fuzzes the lines a bit, but it does seem like a very clever move given the size of the market for Bambu replacement parts–and a good guarantee they will exist for a long time.
But, again, for folk like me who favor relatively standardized parts and the ability to deeply customize their printer settings, the SK1 is remarkably satisfying. It’s not a Voron, but it is a very sturdy framework that almost removes the itch to buy a kit and build one from scratch.
As usual with all the stuff I review, I will be updating this post (or linking to it in the footer), so I guess future us will know.
One thing I did find annoying is that you need to remove the extruder tensioning screw to get the cover off. There is a printables modded fan shroud that has a little notch to avoid this and adds LED
s near the nozzle, which is something I might try out. ↩︎
I’ve since printed a Califlower and dimensional error out of the box was 0.4%, which is pretty good for a printer that hasn’t been tuned yet and prints at speed. ↩︎
This is great news for my own Rockchip chipset exploration, which still has a ways to go–there now seems to be working Mali GPU
acceleration for LLM
s, and having more people doing this kind of testing on ARM
is both informative and a sign there’s interest in the small model, edge AI scenarios I’ve been toying with.
Serendipitously, I did look at llm-rk3588
when I got my Orange Pi 5+ (it was actually developed on one) but discarded it because the NPU
can’t really be used for LLM
s and the required firmware blob didn’t load under my Armbian build (I assume the repo owner was using the Orange Pi linux distro).
I would prefer that be baked into ollama
to have a baseline that is comparable with Apple Silicon and Intel chips–i.e., exact same model weights, at least–but its great to see something can be made to work with the Mali GPU (although I’m not really clear on what model layers will benefit, how it deals with quantization, etc.).
But I will have a look at reproducing (and, preferably, building locally and tweaking) what was used here and try to give both CPU
and GPU
inference a go on a similar (but more compact) 32GB RAM board that I have sitting on my in tray.
So watch this space (I’ve been busy with a lot of work and more physical testing)…
I have a first-generation model that is easily, hands down, the best value for money I ever paid for an MP3 player of any kind, and that has been repeatedly pressed back into service.
Category | Date | Link | Notes |
---|---|---|---|
2024 | squeezelite-esp32 | a modern port of most of the stack to the ESP32 |
|
2009 | Client Protocol | A copy of the client protocol specs taken from the Slim Devices Wiki. |
|
Remote Configuration | Sony Remote manual |
||
User Guide | A copy of the user guide. |
||
Slimserver Lite | C |
||
pyslimp3 | a Python daemon that acts as an iTunes remote. |
||
SoftSqueeze | a Java client that clones the SliMP3 and Squeezebox UI |
||
slimfx | a Flash-based theme for the front-end. |
||
Videobox | a remote control relay that lets you use the SliMP3 to control video displayed on your PC. |
||
Plugins | includes a great |
||
Pat Farrell's Tools | a set of Java tools for cleaning up large music libraries |
||
Another Cover Art Tool | this time in Perl |
RDP
, VNC
and ssh
(among others) client for Windows, Linux (including ARM
!), macOS, Android and iOS that provides a unified interface for managing multiple connections:
An interesting thing for me is that besides being available as a free version for personal use, short of FreeRDP, it is the fastest and most compatible RDP client I have ever used on macOS, even beating the official Microsoft client when connecting to legacy RDP
servers (with or without RFX
and GFX
protocols).
The only thing I really don’t like is that hiding the scrollbar in terminal windows seems to be impossible, but otherwise it is a very polished piece of software.
Devolutions also maintains a Rust-based RDP implementation called IronRDP, which likely explains all of the above.