Saturday, 29 December 2012

Keyer on RPi

This Christmas, along with other fine gifts, Santa gave me a Raspberry Pi.


In this brief lull in hostilities between Christmas and New year I've stolen a couple of hours to play with my new toy. I have to say I'm impressed!

It has been a pretty steep learning curve, because I didn't really know much about the whole Linux universe when I started. I've used a MAC at work for the past couple of years - but MAC encourages such a superficial engagement with the computer that you don't need to know anything about the nuts and bolts!

I was greatly helped by another present from Santa - the Raspberry Pi User Guide by Upton and Halfacree. That has been a good little book, which gave me a useful kick start. However, I didn't want just to light an LED or detect a button push as my baptism on the GPIO - so I decided to make a keyer...


I approached the project with a little trepidation, because Eben says in the User's Guide referenced above ...

"If true real-time operation is required for your project, the Pi may be a bad choice. Instead, consider using a microcontroller platform such as the popular open-source Arduino..."

That bothered me, because it was exactly the availability of the GPIO interface that attracted me to the Pi in the first place, promising a convergence between real computing and the PIC-based fun-and-games I've been describing on these pages. I hoped that the "real-time" warning (repeated on the Project Home Page for the GPIO module I used) wasn't going to threaten that promised convergence. Yes - I know that a morse keyer isn't exactly pushing the boundaries of real-time operation - but I also know from experience that a surprisingly small latency (of only 80 milliseconds) in a keyer is enough to make operation difficult.

Here's the circuit I hooked up...


You can see that three GPIO lines are used for interface; one for each of the paddle's switches and one to key the transmitter (through the open collector). I started development with some little momentary action push-button switches which I left on the breadboard in parallel with the interface to the twin paddle, as you see in this picture...


Talking of interfacing to the RPi GPIO lines, I really like this solution - I shall have to buy one or make a copy!

Before we go on to describe the code, a warning. Remember that I started this knowing NOTHING about programming in Python, so what follows is an account of how something can be done, rather than how something should be done.

My code uses a Python module to access the GPIO port and I chose to use the module recommended in the User's Guide.

The code is seen in the windows below - I have been connecting to the Pi through SSH using the PuTTY SSH Client . The windows below show the Keyer program listed in the Nano editor. You don't have to work in this rather spartan way - I chose to do so in order to learn more about console/terminal interaction with Linux.

The first window shows some configuration stuff and some initial functions...


The second window shows the main operating "loop" of the code...


I don't know just how bad a piece of Python the above code is. All I know is that I learned a bunch from writing it and that the resulting keyer works perfectly. Having said that, it is utterly pointless as I already have my own Keyer solution and its more Rhythmically sophisticated derivative!

 ...-.- de m0xpd

Update:

Perhaps this wasn't just a Raspberry Pi learning exercise - it could be a tool for wireless telegraphy. To prove it (to myself, at least), I just used the keyer and my Funster Plus rig (which ironically already has a keyer built into it!) to have a quick QSO with Wally, operating the GB0YAM station on 40m at the Yorkshire Air Museum. Reminded me just how sloppy my CW has become!

Update 2 (September 2015)

Some kind reader just pointed out that there is a problem runing the code in the images above - I tried it and agree s/he is right. The code was working back in 2012, but isn't working today (that's to say I was doing something different back then).

In order to make the code work correctly, we need to make sure the variable "last" is defined before entering the main "while" loop of the program - here's a complete listing of the code, with the required addition...

#!/usr/local/bin/python

import RPi.GPIO as GPIO, time
# setup GPIO options...
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
# setup IO bits...
GPIO.setup(11, GPIO.OUT)
GPIO.setup(12, GPIO.IN)
GPIO.setup(16, GPIO.IN)
# check initial state...
GPIO.output(11, False)

def SendDit(DitLength):
""" Sends a Dit..."""
KeyLength=DitLength
KeyDown(KeyLength)
Last_Element="dit"
return Last_Element

def SendDah(DahLength):
""" Sends a Dah..."""
KeyDown(DahLength)
Last_Element="dah"
return Last_Element

def SendSpace(DitLength):
""" Wait for inter-element space..."""
time.sleep(DitLength)
return

def KeyDown(KeyLength):
""" Keys the TX """
# set the output to Key Down...
GPIO.output(11, True)
time.sleep(KeyLength)
# clear the output ...
GPIO.output(11, False)
return

DitLength=0.075
DahLength=3*DitLength
# here's the additional line (23/9/2015)...
last="none"

# Main Operating Loop...
while True:
paddle_left=GPIO.input(12)
paddle_right=GPIO.input(16)
if (paddle_left == False) and (paddle_right == True):
while (paddle_left == False) and (paddle_right == True):
last=SendDit(DitLength)
SendSpace(DitLength)
paddle_left = GPIO.input(12)
paddle_right = GPIO.input(16)
elif (paddle_right == False) and (paddle_left == True):
while (paddle_right == False) and (paddle_left == True):
last=SendDah(DahLength)
SendSpace(DitLength)
paddle_right = GPIO.input(16)
paddle_left = GPIO.input(12)

elif (paddle_left == False)and(paddle_right == False):
while (paddle_left == False) and (paddle_right == False):
       if last == "dit":
last=SendDah(DahLength)
SendSpace(DitLength)
elif last == "dah":
last=SendDit(DitLength)
SendSpace(DitLength)
else:
last=SendDah(DahLength)
SendSpace(DitLength)
paddle_right = GPIO.input(16)
paddle_left = GPIO.input(12)

else:
last="none"

I have just tested the operation of the code and confirmed that it runs FB on my original Pi - here's the hardware I just lashed together for the verification (the battery isn't part of the system!)...


Thanks to our "Unknown" commenter (below) and apologies for any inconvenience to others - I still can't understand the origin of this issue, as the Keyer was working perfectly well before - well enough for me to use it in a QSO, as described!

4 comments:

  1. I tried using your code and schematic to make my own keyer, but I keep getting an error saying
    File "keyer.py", line 57, in
    if last == "dit":
    NameError: name 'last' is not defined

    Is this the entire code? Is there a copy and paste version available if this is the entire code to ensure I'm not typing anything wrong?

    ReplyDelete
  2. Well - this is a blast from the past!

    I had to get out the old R Pi to find the code and yes, you are right - there is a compile error as you describe. But I cannot understand what was going on before, because the code published above was exactly what I was using and it was working!

    You need to add a definition of last before entering the main loop - something like:

    last = "none"

    Then (as I have just confirmed) it will work fine.

    What I still cannot understand is how it was working before - it is as if there was somehow a declaration of "last" floating around in the compiler (/ interpreter).

    Thanks for pointing out this problem - I'll post the working code in an update.

    ReplyDelete
    Replies
    1. ... and the plot gets thicker and thicker by the minute...

      I've come back an hour later to find that the original code will now work once again WITHOUT the extra line. This is after a shutdown / logout and after a power-down.

      I have no idea what has changed - I just got things running again (as described in the comment above and in the update) with the definition of "last", after which everything is fine.

      Safest to keep that extra line in place - making sure the system is in a known state. But this is a pretty story if ever there was one!

      Delete
  3. Just a suggestion, if you could copy the features of K3NG keyer to this , it would be just too good. I guess, RPi-0 is the hardware for a standalone full rich keyer project. With keyboard and LCD attached

    ReplyDelete