Ямбічний ключ у USB за день: адаптер, корпус із логотипом і тренажер Морзе
Ямбічний ключ у мене є, а тренуватися з ним не було на чому: трансивер для цього вмикати не хочеться, а тренажери в браузері чекають натискань на клавіатурі. За один день із цього вийшло три речі: адаптер, який робить із ключа USB-клавіатуру, корпус до нього з моїм позивним і тренажер, що розуміє саме ключ.
Принцип простий: плата на RP2040 читає дві пелюстки ключа й надсилає комп'ютеру натискання
клавіш A і S. Комп'ютер бачить звичайну клавіатуру, драйвери не потрібні. До цього я
додав те, чого мені бракувало: корпус і власний тренажер.
Модель корпусу, прошивку й тренажер я робив у парі з ШІ-асистентом (Claude Code). Про це нижче буде окремий урок на два міліметри.
Залізо
| Деталь | Що взяв |
|---|---|
| Плата | YD-RP2040 (VCC-GND Studio), USB-C, 23,2 × 53,5 мм; посилання на AliExpress |
| Гніздо | стерео 3,5 мм під пайку в плату, з верхньої панелі старого корпусу ПК |
| Дроти | три, по 4–5 см |
Гніздо має п'ять виводів, потрібні три: загальний, кінчик і кільце. Два інші — контакти, що розмикаються, коли вставлено штекер. Шукати потрібні найпростіше мультиметром через кабель: штекер у гнізді, один щуп на контакті штекера з іншого кінця кабелю, другим проходимо по виводах.
Паяється так:
| Контакт штекера | Площадка плати | Клавіша | У тренажері |
|---|---|---|---|
| Загальний (основа) | GND між 13 і 14 | — | спільний |
| Кінчик | 14 | S | крапка |
| Кільце | 15 | A | тире |
Усі три площадки стоять поруч у кінці плати, протилежному до USB. Кольори дротів на схемі умовні: важливо лише, щоб кожен контакт штекера потрапив на свою площадку.
Прошивка
На платі CircuitPython 10.3.2. Зазвичай для клавіатури беруть бібліотеку adafruit_hid;
я обійшовся без неї, бо звіт клавіатури — це вісім байтів, які можна надіслати напряму.
import time
import board
import digitalio
import usb_hid
KEY_GP14 = 0x16 # HID-код клавіші S
KEY_GP15 = 0x04 # HID-код клавіші A
def make_input(pin):
p = digitalio.DigitalInOut(pin)
p.switch_to_input(pull=digitalio.Pull.UP)
return p
pins = ((make_input(board.GP14), KEY_GP14), (make_input(board.GP15), KEY_GP15))
kbd = next(d for d in usb_hid.devices if d.usage_page == 0x01 and d.usage == 0x06)
report = bytearray(8)
last = None
while True:
state = tuple(not p.value for p, _ in pins)
if state != last:
report[2] = pins[0][1] if state[0] else 0
report[3] = pins[1][1] if state[1] else 0
try:
kbd.send_report(report)
last = state
except OSError:
pass # хост ще не готовий, повторимо на наступному колі
time.sleep(0.002)
Другий файл, boot.py, ховає диск CIRCUITPY, щоб адаптер був лише клавіатурою. Якщо під
час підключення тримати пелюстку на 14 замкненою, диск з'являється знову, і код можна
правити.
import board
import digitalio
import storage
pin = digitalio.DigitalInOut(board.GP14)
pin.switch_to_input(pull=digitalio.Pull.UP)
if pin.value: # пелюстку не натиснуто
storage.disable_usb_drive()
pin.deinit()
Порядок такий: затиснути BOOT, підключити плату, скопіювати на диск RPI-RP2 файл
CircuitPython, потім на диск CIRCUITPY покласти code.py. Перевірити пінцетом, що
замикання 14 на GND дає літеру s, і лише тоді копіювати boot.py: якщо в коді
помилка, з відкритим диском її виправити простіше.
Одна пастка на Linux: якщо в системі працює USBGuard, плата за час прошивки тричі змінює «обличчя» (завантажувач, диск із клавіатурою, лише клавіатура), і кожне треба дозволяти окремо.
Корпус
Корпус описаний скриптом для FreeCAD, а не намальований мишею. Розміри плати, гнізда й зазори лежать на початку файлу як числа; після зміни скрипт сам будує основу, кришку й обидва STL. Це знадобилося раніше, ніж я думав.
Що є в корпусі:
- виріз під USB-C у торці й отвір під носик гнізда в протилежному;
- полички під краї плати, щоб під нею лишалося три міліметри для пайки;
- ложемент, у якому гніздо лежить виводами догори;
- кришка на защіпках з отвором до кнопки
BOOT; - логотип сайту й позивний, заглиблені на 0,6 мм під заливку фарбою.
Модель можна покрутити просто тут. Повзунок піднімає кришку, і видно, як усередині лежать плата й гніздо:
Файли для друку:
- case_base.stl — основа;
- case_lid.stl — кришка з логотипом і позивним UR3PKI, уже перевернута лицем до столу;
- case.py — скрипт FreeCAD, з якого зібрано обидві деталі. У ньому міняються
розміри плати й гнізда, напис і логотип; запуск:
freecadcmd case.py.
Обидві деталі друкуються без підтримок.
Логотип узято з SVG сайту: кожен контур стає окремою кишенькою, тому червона, синя й жовта фарба не змішуються. Перша версія логотипа мала 21 мм, і доріжки в ній виходили завширшки 0,75 мм. Для сопла 0,4 мм це на межі, тож я збільшив логотип до 28 мм, а корпус розширив під нього до 33 мм.
Друкував на FlyingBear Reborn 2, PLA, шар 0,2 мм, три периметри. Кришка лежить лицем до столу, тому для неї важливі два налаштування першого шару: ширина лінії 100 % замість заводських 130 % і компенсація «слонячої ноги» −0,12 мм. Без них тонкі канавки запливають.
Два міліметри
Розміри плати я дав асистентові фотографіями штангенциркуля. Він прочитав з них 21 × 51,5 мм. Насправді на шкалі було 23,2 × 53,5.
Помилку ніхто не помітив, доки основа не надрукувалась. П'ятдесят хвилин друку, і плата лягає зверху на напрямну, а не між стінкою й нею.
Першу основу я підігнав руками. У моделі розміри виправлено, і тепер вони звірені двома способами: зі шкали на збільшеному знімку і з сітки отворів плати, де двадцять отворів із кроком 2,54 мм дають відомі 48,26 мм.
Висновок простий і стосується не лише ШІ: число, зняте з фотографії, треба назвати вголос і звірити до того, як воно піде в модель. Параметричний скрипт тут виручив: виправити три числа й перебудувати корпус зайняло хвилину.
Тренажер
Тренажер живе за адресою cw.cyberdev.space. Це одна сторінка
без встановлення; прогрес зберігається в браузері. Працює і без адаптера: пелюстками
служать клавіші A і S або стрілки.
Тренажер не прив'язаний до мого адаптера. Якщо ви вже зібрали
адаптер ямбічного ключа за описом so1der на сайті UARO,
він підійде без змін: надсилає ті самі клавіші A і S. Якщо крапка й тире виявляться
навпаки, у налаштуваннях є перемикач «поміняти пелюстки».
Навчання побудоване на двох відомих методах. За методом Коха знаки одразу звучать на робочій швидкості, а новий знак додається лише тоді, коли попередні приймаються на 90 %. За Фарнсвортом самі знаки швидкі, а паузи між ними розтягнуті, щоб початківець встигав подумати. Типові налаштування: знаки на 20 слів за хвилину, ефективна швидкість 15.
Далі коротка інструкція. На кожному знімку ліворуч темна тема, праворуч світла; тема перемикається кнопкою в шапці.
1. Курс
Угорі поточний урок: новий знак, його код крапками й рисками, кнопки, щоб послухати кожен знак уроку, і графік останніх спроб із лінією порога. Нижче курс у вигляді друкованої плати на 40 уроків. Перший урок дає K і M, кожен наступний додає один знак.
Навколо уроку три кільця: синє показує прийом, червоне передачу, бірюзове радіограму. Коли всі три режими пройдено на 90 %, кільця зливаються в одне золоте й відкривається наступний урок. У шапці видно серію днів поспіль і скільки знаків зроблено сьогодні.
2. Прийом
Звучить знак, ви натискаєте відповідну клавішу. Тренажер читає фізичні клавіші, тому розкладка не має значення: клавіша K зарахується і з увімкненою українською. Пробіл повторює звук. Після помилки на екрані з'являється правильний знак із кодом.
Нові знаки й ті, у яких ви помиляєтесь, випадають частіше за засвоєні.
3. Радіограма
Класичне заняття за Кохом: суцільний текст групами по п'ять знаків на одну–п'ять хвилин. Ви записуєте на слух, пробіл розділяє групи, Enter перевіряє. Головна навичка тут — не зупинятися на пропущеному знаку, а писати далі.
Після перевірки видно передане з підсвіченими помилками і ваш запис. Результат рахується двома способами, по всьому тексту й по групах, і зараховується кращий, тож один пропущений знак не зсуває решту.
4. Ехо ключем
Режим, заради якого все починалося. Звучить знак, ви повторюєте його ключем, декодер перевіряє. Знак на екрані можна показувати або ховати. Якщо знаки розпадаються на частини, зменште «Швидкість ключа» в налаштуваннях: декодер закінчує знак після паузи у дві з половиною крапки.
Є ще «Вільний ефір»: передаєте що завгодно й бачите, що з цього розібрав декодер.
5. Слова й позивні
Наступний етап після абетки. Слово або позивний звучить цілком на стандартних паузах, ви набираєте його й тиснете Enter. Правильна відповідь додає одне слово за хвилину, помилка знімає. Слова складаються лише з уже вивчених знаків; позивні відкриваються, коли серед них з'являється перша цифра.
6. Налаштування й перенесення прогресу
У налаштуваннях швидкість знаків і ефективна швидкість, швидкість ключа, тон, поріг уроку, мета на день. Два перемикачі варто ввімкнути приблизно з п'ятого уроку: випадкова довжина груп і випадковий тон, щоб слух не звикав до одного звучання.
Нижче точність по кожному знаку, експорт та імпорт прогресу файлом і синхронізація між пристроями. Вона працює без облікового запису: сторінка створює випадковий ключ, і той, хто введе його на іншому пристрої, продовжить з того самого місця.
Що взято в LCWO
Перед тим як дописувати тренажер, я порівняв його з LCWO, найвідомішим сайтом для вивчення телеграфу. Його автор, Fabian Kurz, DJ5CW, публікує вихідний код під ліцензією AGPL 3, тож роботу курсу можна прочитати, а не вгадувати.
Звідти прийшли ідеї: порядок сорока уроків, радіограма як основний вид заняття, перевага нових знаків у тексті, випадкова довжина груп і тон. Код у тренажері свій. Таймінг я звірив окремо: у записі з LCWO на швидкостях 20/15 крапка триває 59 мс, пауза між знаками 339 мс, між групами 789 мс; мій розрахунок дає 60, 338 і 788.
Чого в LCWO немає і що було метою: передача ямбічним ключем із перевіркою.
Чого воно ще не вміє
- У тренажері немає відкритого тексту й типового зв'язку, лише знаки, групи, слова й позивні.
- Ключ працює в одному ямбічному режимі з пам'яттю, без вибору між A і B.
- Набір слів і позивних розрахований на клавіатуру, на телефоні зручні тільки прийом і ключ.
- Отвір до кнопки
BOOTу першій кришці зміщений приблизно на міліметр: скріпка дістає, але ближче до краю.
Джерела
- Learn CW Online і його вихідний код — курс Коха, з яким я звірявся.
- Дерево коду Морзе — звідки взято мотив друкованої плати для карти курсу.
- cw.cyberdev.space — сам тренажер.
