When is comes to ham radio operators that use Morse code keys each has their favorite and none have just one. Morse keys can differ in many ways, but the bug key is typically the most expensive and the most difficult to learn. Real bugs mechanically (not electronically) "automate" the DITs while the DAHs are still produced manually. It's a throwback to the times when effortless high speed code was sent without the use of fancy electronics.
-----
That was then and this is now because with fancy electronics we can simulate things. BTW, if you are a SKCC member this isn't a 100% manual key so would not qualify as a bug for a Triple Key Award, but it gives a real bug key feel at price well under a six pack. This allows more OPs the experiment or practice with a bug key before having to lay out real folding money for the experience.
-----
We cobbled this together in a few hours with "stuff in the drawer". A C3 uController was used but any Arduino based device could work.
----
Video of our first try (we could benefit from a little bug practice):
And.... we may (or may not) design and 3D Print a case for it.
-----
To create your own, wire it up like this and upload the code below to the uController via the Arduino IDE. Presto, instant bug! Note; safety first: We used a PC817 to completely isolate and protect the ham radio rig from having any external voltages sent into it.
We also designed in a potentiometer to adjust DIT WPM speed, but it can be eliminated if you just want to hardcode the WPM speed into the code.
-----
/*
* Bug Keyer Simulator with Smoothed WPM Control and Live Pot Adjustment
* Arduino IDE Board Settings: ESP32 Dev Module, 240MHz (WiFi/BT), 921600
* APRIL2026
* Project details at: whiskeytangohotel.com
*/
// Define C3 pins
const int ditPin = 2; // From key
const int dahPin = 3; // From key
const int keyOutPin = 8; // To rig
const int potPin = A0; // Bug Speed adjust
// Define some variables. Feel free to adjust minWPM and maxWPM to suit needs
int wpm;
int targetWpm;
int ditLength;
int minWPM = 10;
int maxWPM = 40;
float smoothedWpm = 20;
void setup() {
pinMode(ditPin, INPUT_PULLUP);
pinMode(dahPin, INPUT_PULLUP);
pinMode(keyOutPin, OUTPUT);
digitalWrite(keyOutPin, LOW);
ditLength = 1200 / wpm;
}
void loop() {
// --- Read pot and update WPM (live knob response) ---
updateWPM();
bool ditPressed = digitalRead(ditPin) == LOW;
bool dahPressed = digitalRead(dahPin) == LOW;
// --- DIT side (automatic repeating like bug) ---