ArkButton: Keyboard Split Nirkabel yang Dicetak dan Disolder Sendiri
58 tombol, dua nRF52840, ZMK, dan satu posisi thumb yang sengaja dibiarkan kosong. Catatan membangun keyboard split nirkabel — termasuk bug clock yang bikin tangan kanan mati total dan plat tenting yang baru mau jadi setelah dicetak berdiri.
Keyboard yang saya pakai sekarang namanya ArkButton. Geometrinya Scylla/Charybdis dari Bastard Keyboards, dicetak di Elegoo Neptune 4 Pro, disolder langsung tanpa hotswap, jalan nirkabel dengan ZMK di dua HwThinker Pro Micro nRF52840.
Yang paling saya suka dari proyek ini bukan hardware-nya. Waktu saya buka file keymap ZMK-nya, baris pertama di komentarnya berbunyi:
ArkButton — keymap direplika dari Dactyl Manuform 4x6 milik Aris
Papan sebelumnya — Dactyl Manuform — sudah lama pensiun. Case-nya beda, mikrokontrolernya beda, firmware-nya pindah dari QMK ke ZMK, kabel TRRS-nya hilang diganti Bluetooth. Yang tidak berubah: susunan tombolnya. Layout-nya selamat, hardware-nya yang diganti. Jari saya tidak perlu belajar apa-apa lagi.
Spesifikasi
| Geometri | Bastard Keyboards Scylla / Charybdis |
| Jumlah tombol | 24 jari + 5 thumb per tangan = 58 |
| Kontroler | 2× HwThinker Pro Micro nRF52840 (kompatibel nice!nano v2) |
| Firmware | ZMK, repo terpisah: charybdis-wireless-zmk |
| Matrix | col2row, satu dioda 1N4148 per tombol, 29 per tangan |
| Sambungan | BLE — kiri jadi central, kanan jadi peripheral |
| Rakitan | solder langsung, tanpa hotswap |
| Printer | Elegoo Neptune 4 Pro |
| Dudukan | tenting stand berengsel, sumber OpenSCAD di tools/tent/ |
Tombol yang tidak ada
Baris thumb punya enam posisi di matrix, tapi cuma lima yang dipasang switch. Posisi paling dalam di tiap tangan dibiarkan kosong — bukan lupa, memang tidak dipasang. Ibu jari saya tidak sampai ke sana dengan nyaman, dan memaksakan satu tombol yang hanya akan tertekan tidak sengaja itu lebih buruk daripada tidak punya tombol sama sekali.
Posisinya tetap ada di keymap sebagai hantu:
// THUMB kiri: SHIFT MO1 GUI SPACE ALT (Del*) | THUMB kanan: (Bksp*) BSPC ENTER HOME MO2 SHIFT
// (* = kolom dalam, tanpa switch)
Binding-nya tetap ditulis supaya jumlah kolom tiap baris konsisten 12. Menghapusnya justru bikin semua orang yang mengedit file itu — termasuk saya enam bulan lagi — salah hitung kolom.
Kenapa Esc di kelingking dan Ctrl di bawahnya
Baris jari dari atas ke bawah: angka, Tab, Esc, LCtrl. Di keyboard biasa posisi ketiga itu Caps Lock dan keempat Shift. Di sini Esc duduk di home row kiri, satu kelingking dari A, dan Control tepat di bawahnya.
Alasannya nvim. Keluar dari insert mode itu gerakan yang saya lakukan ribuan kali sehari; kalau butuh menjulurkan kelingking ke pojok kiri atas, itu ribuan kali menjulur. Shift dipindah ke thumb, tempat yang jauh lebih pantas untuk tombol yang ditahan, bukan diketuk.
Prefix tmux ada di bawah ibu jari kanan
Ini bagian yang biasanya butuh dijelaskan dua kali. Di dotfiles/tmux/tmux.conf:
unbind C-b
set-option -g prefix Home
Dan di keymap ArkButton, Home adalah tombol keempat di cluster thumb kanan. Jadi setiap perintah tmux — pindah window, split pane, semuanya — dimulai dengan satu tekanan ibu jari. Tidak ada akrobat Ctrl sama sekali.
Home sebenarnya sudah ada di keymap Dactyl yang lama (KC_HOME, di baris paling bawah tangan kanan). Waktu cluster thumb tumbuh jadi lima tombol, dia tinggal geser ke ibu jari — dan justru di situ dia baru masuk akal.
Empat layer, satu di antaranya lahir karena nirkabel
- 0 — Base. QWERTY plus number row.
- 1 — Numpad. Ditahan dengan
MO1di thumb kiri. - 2 — Nav. Ditahan dengan
MO2di thumb kanan. - 3 — Adjust / Bluetooth. Muncul sendiri saat layer 1 dan 2 ditahan bersamaan.
Layer 1 dan 2 nyaris salinan persis dari keymap Dactyl-nya — numpad di posisi yang sama, panah di A S D F yang sama. Layer 3 tidak punya padanan sama sekali di papan lama, dan alasannya sepele: papan lama tersambung kabel. Begitu jadi nirkabel, harus ada tempat untuk BT_SEL 0–4, BT_CLR, dan sys_reset. Layer itu tidak dirancang, dia dipaksa muncul oleh keputusan hardware.
conditional_layers {
tri_adjust { if-layers = <1 2>; then-layer = <3>; };
};
Bug yang bikin tangan kanan mati
Ini bagian yang paling lama.
Setelah semuanya disolder dan di-flash, tangan kiri jalan sempurna sebagai central. Tangan kanan tidak. Bukan mati suri — dia bahkan sanggup jalan sendirian sebagai central kalau di-flash begitu. Yang gagal hanya sambungan split-nya, dan lognya berulang: Security failed err 9, lalu disconnect reason 0x08, terus begitu.
Saya sempat curiga ke pin, ke wiring, ke bonding. Tidak satu pun. Penyebabnya: klon HwThinker ini tidak punya kristal 32.768 kHz yang diasumsikan board profile nice_nano_v2. Tanpa kristal itu, clock frekuensi rendah untuk BLE melenceng, dan sambungan split yang timing-nya ketat kehabisan waktu di tengah proses security. Perbaikannya satu baris:
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n
Ada satu lagi yang mirip sifatnya. Central harus memegang satu peripheral (tangan kanan) plus lima profil Bluetooth untuk lima perangkat. Default-nya lima koneksi — kurang satu, dan yang tidak kebagian slot selalu tangan kanan:
CONFIG_BT_MAX_CONN=6
CONFIG_BT_MAX_PAIRED=6
Dan satu jebakan pin: P0.22 mati sebagai GPIO di board ini karena dipakai QSPI flash. Col1 dipindah ke P0.31.
Cermin itu urusan firmware, bukan solder
PCB kanan adalah cermin dari kiri, jadi kalau kedua tangan disolder dengan pin dan urutan yang sama, kolom tangan kanan keluar terbalik. Godaan pertama adalah membongkar dan menyolder ulang. Jangan. charybdis_handwired_right.overlay membalik urutan col-gpios dan menambahkan col-offset = <6>, persis seperti yang dilakukan corne_right.overlay di ZMK. Keymap tetap ditulis dalam urutan visual kiri→kanan seperti yang terlihat mata.
Kenapa disolder langsung
Prioritasnya awet. Socket hotswap Gateron sempat masuk keranjang belanja lalu dibatalkan sebelum dibayar: switch-nya Gateron G Pro dengan rating sekitar 50 juta klik, jadi kemungkinan saya mengganti switch di papan ini mendekati nol, sementara socket menambah satu titik kontak per tombol yang bisa kendor atau teroksidasi bertahun-tahun ke depan. Dioda dan kawat email yang disolder permanen jauh lebih sedikit hal yang bisa gagal.
Plat tenting harus dicetak berdiri
Bagian mekanik yang paling keras kepala adalah plat dudukan tenting. Sekitar sepuluh percobaan gagal dalam satu sesi, semuanya dicetak rebah — dan setiap kali, knuckle engselnya yang berbentuk tab tipis tinggi melengkung dan saling menempel di sekitar lapisan keempat atau kelima.
Yang lucu: orientasi berdiri sempat saya coba lebih dulu dan saya coret sendiri dengan catatan “rejected, tippy” — dinding setinggi 138 mm dengan tapak cuma 14 mm memang terlihat mustahil. Ternyata itu justru jawabannya, dan readme desainer aslinya memang sudah menulis “print them vertically” sejak awal. Berdiri, knuckle engselnya berubah fungsi jadi gusset yang menempel di dinding vertikal, bukan lagi tab menggantung. Bonusnya tak terduga: tapak yang tipis itu jatuh persis di tengah bed, jauh dari sudut-sudut yang melengkung.
Masalah kedua di sesi yang sama sama sekali bukan soal geometri: Z0 bergeser setiap kali printer di-home, kisaran ±0,15 mm dalam satu sesi yang sama. Semua offset yang saya suntikkan ke gcode jadi salah begitu printer re-home di awal cetak. Solusinya home sekali, verifikasi titik nolnya dengan kertas, lalu buang baris G28 dari gcode supaya cetakan memakai home yang sudah terverifikasi itu. Dan aturan yang saya tulis besar-besar untuk diri sendiri: habis mengelem bed, ulangi tes kertas. Ketebalan lem saja bisa menggeser Z0 sebesar 0,1 mm.
Satu jebakan terakhir, dari catatan tanggal 30 Juni: nama file di repo upstream tertukar kiri-kanan. File yang bernama ..._plate_right.stl sebenarnya plat kiri. Ini baru ketahuan setelah membandingkan render dan menghitung IoU outline-nya terhadap case. Semua baris di antrean cetak akhirnya ditulis ulang memakai tangan yang sebenarnya, bukan nama file.
Repo ini tidak menyimpan satu pun hasil
.stl, .3mf, .gcode, .uf2, dan seluruh PNG render tidak masuk git. Yang masuk cuma sumbernya: OpenSCAD, skrip, dan catatan. Semuanya bisa dibangun ulang:
tools/fetch-upstream.sh # klon upstream di commit yang dipin
node tools/cycle.mjs <target> # build → validate → capture → ringkasan
Ada tiga viewer three.js untuk melihat hasilnya tanpa membuka CAD — preview-keymap.html, preview-tenting.html, dan preview-wiring.html. Yang terakhir yang paling sering saya buka waktu menyolder.
Firmware juga tidak disimpan sebagai file. GitHub Actions di repo ZMK yang membangun .uf2-nya; artefaknya diunduh, di-unzip ke firmware/, lalu:
firmware/flash left # atau right, atau reset
firmware/kbstatus # status Bluetooth di macOS
flash reset itu jaring pengaman: dia menuliskan settings_reset ke kedua sisi untuk membersihkan bonding BLE yang basi. Setiap kali kedua tangan tiba-tiba tidak mau saling kenal lagi, itu langkah pertama.
Yang belum selesai
Papannya sudah dipakai mengetik setiap hari, termasuk tulisan ini. Yang masih di antrean cetak: plat tenting sisi kiri, dua bagian base, dan dua tenting arm — total sekitar tiga puluh jam printer. Holder baterai dan dudukan cradle ke case sengaja ditunda sampai semuanya benar-benar terpasang.