100 years since World War I: build a Morse code virtual radio

On this day 100 years ago, Austria-Hungary declared war on Serbia in response to the assassination of the heir to the Austro-Hungarian throne. As the dominos began to tumble Russia mobilised against Austria-Hungary, causing Germany to declare war on Russia. Germany then invaded Luxembourg and declared war on France; and on the 4th of August the United Kingdom declared war on Germany. So began one of the bloodiest conflicts in human history, that would draw in all of the great economic powers of the world, lasting until November the 11th 1918.

A century later the effect of this war is still with us. Every one of us has some kind of connection to it, whether it be an impact on our family history or on the place we live. This year events are taking place all over the world to commemorate and remember the millions of people who lost their lives. You can visit www.1914.org to find out more.

QST May 1942

The cover of QST magazine showing a call for women radio operators.

We expect lots of schools will be taking part in these events, and in the spirit of commemoration we have put together an educational resource called the Morse Code Virtual Radio. This allows you to simulate and experience the main form of radio communication that was used back then, using your Raspberry Pi. If you have an ancestor who was an ex-telegraph operator or world war serviceman, you may have an old Morse Code key in your attic which you could use.

antique key

An antique Morse Code key.

Invented by Samuel Morse in the year 1836, Morse Code is a method for sending and receiving text messages using short and long tones. It was adapted for early radio communication, before it was possible to send or receive voice, and was used extensively during both world wars.

Morse Code is also a really great skill to have. There is a very human element to it which is difficult to quantify and describe. Human skill is required to key in Morse Code correctly which takes only minutes to learn, but a lifetime to master. Skill is also required to listen to the tones and decode them. Our educational resource provides learning opportunities for both aspects.

Want to have a go? You’ll find everything you need here on our resources pages.

18 comments

Avatar

Nice resource, very comprehensive and great fun!

Avatar

Thanks Mike! We’re looking at making more cross-curricular resources like this available in the future, too, so keep an eye on the Resources pages for new content.

Avatar

Not forgetting the (decidedly non-RPi/low tech) use of telephones. WWI was the first conflict that used them. Static postions allowed for extensive telephone networks to built. But it had to be adaptable and fault tolerant for where shelling or trench capture forced reconfiguration.

Not as sexy as WT, but without phones the flyers wouldn’t have been able to do their stuff.

Avatar

Morse code – not as sexy as ‘texting’, but requiring a great deal more skill. Shame really – It would be wonderful to see kids roaming the streets, walking into lamp-posts and falling down open man-holes whilst busy sending Morse code to each other!!

And, remember, before there were SMS abbreviations such as ROTFLMAO and LOL and OMG and M8, etc. the users of Morse code had had to invent their own shortcuts, so . . .

73 es 88 de GM6GMZ

Avatar

72 de Jeff WD4ET (qrp) ;)

Avatar

First of all, I used a lot of morse code while I was in the navy from 1980 to 1988, then we had to announce RTTY (Radio TeleTYpe Messages) at the shore station in morse code and it was mandatory for the night shift to type the weather report which was sent via morse code.

Second, it is quite easy to improvise a morse key with a wooden clothes-peg and some wire.

I’ll join the project tomorrow! After all those years I need a refresher :)

Avatar

Hi Volker, yes you can easily make your own Morse key and use it for the project. You can even get away with just touching two wires together.

Avatar

The timing of this is perfect. Me and some friends had just been looking at a morse code server with the pi. A bit like internet radio :D

If I get it working, I’ll have to release the image. If its popular, I might even open the server to the world. It wont be running on port 80, so will be a bit more hidden like the old WW1 lines :)

Avatar

Navy use(ed) Aldis lamps. A modern spin would be 2 RPi-s flashing LEDs at each other, or a human. Fundamentally this all that goes on in an optic fibre.

Avatar

Surely this is crying out to be combined with the FM transmitter hack

Avatar

To extend the educational part of the project can I recommend
The Victorian Internet” book

Packed with anecdotes about how the use of WT mimiced current internet stuff.. Spam messages, Encryption for commercial transactions; Online dating between operators, Sub Sea cables etc etc..
A really good read..

Avatar

I was interested to see this resource. Recently I played around with generating morse code using SonicPi 2 (beta). Here is my program.
I am currently recording a range youtube tutorials for using SonicPi 2. This program is perhaps one of the more unusual uses.

Robin Newman
==========================

#sonic-pi 2 does morse! by Robin Newman 28th June 2014
#you can send a-zA-Z and 0-9 and ,.!? (other characters could be added)
msg = “SonicPi 2 sends morse. ” #the message to be sent
msg = msg + “The quick brown fox jumps over the lazy dog.”

sp = 0.08 #set the speed 0.08 is about 18 words/minute
dit = 1 * sp #timings for individual elements
dah = 3 * sp
gs = 1 * sp #gap between elements
cs = 3 * sp #gap between characters
ws = 7 * sp -cs # gap between words (cs already included by playarray so subtract it)
pt = :c5 #note pitch

note=[] #empty arrays for note and durations
dur=[]
#define alphabetic characters each is an array entry for notes and for durations
a = [[pt,pt],[dit,dah]]
b = [[pt,pt,pt,pt],[dah,dit,dit,dit]]
c = [[pt,pt,pt,pt],[dah,dit,dah,dit]]
d = [[pt,pt,pt],[dah,dit,dit]]
e = [[pt],[dit]]
f = [[pt,pt,pt,pt],[dit,dit,dah,dit]]
g = [[pt,pt,pt],[dah,dah,dit]]
h = [[pt,pt,pt,pt],[dit,dit,dit,dit]]
i = [[pt,pt],[dit,dit]]
j = [[pt,pt,pt,pt],[dit,dah,dah,dah]]
k = [[pt,pt,pt],[dah,dit,dah]]
l = [[pt,pt,pt,pt],[dit,dah,dit,dit]]
m = [[pt,pt],[dah,dah]]
n = [[pt,pt],[dah,dit]]
o = [[pt,pt,pt],[dah,dah,dah]]
p = [[pt,pt,pt,pt],[dit,dah,dah,dit]]
q = [[pt,pt,pt,pt],[dah,dah,dit,dah]]
r = [[pt,pt,pt],[dit,dah,dit]]
s = [[pt,pt,pt],[dit,dit,dit]]
t = [[pt],[dah]]
u = [[pt,pt,pt],[dit,dit,dah]]
v = [[pt,pt,pt,pt],[dit,dit,dit,dah]]
w = [[pt,pt,pt],[dit,dah,dah]]
x = [[pt,pt,pt,pt],[dah,dit,dit,dah]]
y = [[pt,pt,pt,pt],[dah,dit,dah,dah]]
z = [[pt,pt,pt,pt],[dah,dah,dit,dit]]
#put characters in a lookup array
lookup = [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]
#traverse the characters in the message converted to lowercase and to byte values
msg.downcase.each_byte do|ch|
case ch #deal with non-alphabetic characters
#nb a “rest” of appropriate duration is added after each
when 32 #space
note << :r
dur << ws #for word gap
when 33 # exclamation mark
note << [pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dit]<<cs
when 63 #question mark
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dah,dah,dit,dit]<<cs
when 46 # fullstop
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dit,dah,dit,dah,dit,dah]<<cs
when 44 #comma
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dit,dit,dah,dah]<<cs
when 45 # hyphen
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dah,dit,dit,dit,dit,dah]<<cs
when 48 #0
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dah,dah]<<cs
when 49 #1
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dah,dah,dah,dah]<<cs
when 50 #2
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dah,dah,dah]<<cs
when 51 #3
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dit,dah,dah]<<cs
when 52 #4
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dit,dit,dah]<<cs
when 53 #5
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dit,dit,dit]<<cs
when 54 #6
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dit,dit,dit,dit]<<cs
when 55 #7
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dit,dit,dit]<<cs
when 56 #8
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dit,dit]<<cs
when 57 #9
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dah,dit]<<cs
else #otherwise it is an alphabetic character
note << lookup[ch – 97][0].flatten << :r #look it up in the lookup array
#97 = a which is first char in array so subtract 97 to get index 0
dur << lookup[ch – 97][1].flatten << cs #flatten removes the []
end
end

define :playarray do |narray,darray,shift=0,vol=1,voice = :saw_s|
with_synth voice do
narray.zip(darray).each do |narray,darray|
if narray == :r #if a gap or rest wait the required time
sleep darray
else
with_transpose shift do #allows transposition (may be 0)
play narray,amp: vol,sustain: darray * 0.9,release: darray * 0.1 #play note
sleep darray + gs #gap till next note
end
end
end
end
end

playarray(note.flatten,dur.flatten,12) #remove remaining [] and send arrays to playarray, Third param is transpose shift

Avatar

Here is the program again inside a code block. The previous version had the quotes changed to smart quotes which caused an error


#sonic-pi 2 does morse! by Robin Newman 28th June 2014
#you can send a-zA-Z and 0-9 and ,.!? (other characters could be added)
msg = “SonicPi 2 sends morse. ” #the message to be sent
msg = msg + “The quick brown fox jumps over the lazy dog.”

sp = 0.08 #set the speed 0.08 is about 18 words/minute
dit = 1 * sp #timings for individual elements
dah = 3 * sp
gs = 1 * sp #gap between elements
cs = 3 * sp #gap between characters
ws = 7 * sp -cs # gap between words (cs already included by playarray so subtract it)
pt = :c5 #note pitch

note=[] #empty arrays for note and durations
dur=[]
#define alphabetic characters each is an array entry for notes and for durations
a = [[pt,pt],[dit,dah]]
b = [[pt,pt,pt,pt],[dah,dit,dit,dit]]
c = [[pt,pt,pt,pt],[dah,dit,dah,dit]]
d = [[pt,pt,pt],[dah,dit,dit]]
e = [[pt],[dit]]
f = [[pt,pt,pt,pt],[dit,dit,dah,dit]]
g = [[pt,pt,pt],[dah,dah,dit]]
h = [[pt,pt,pt,pt],[dit,dit,dit,dit]]
i = [[pt,pt],[dit,dit]]
j = [[pt,pt,pt,pt],[dit,dah,dah,dah]]
k = [[pt,pt,pt],[dah,dit,dah]]
l = [[pt,pt,pt,pt],[dit,dah,dit,dit]]
m = [[pt,pt],[dah,dah]]
n = [[pt,pt],[dah,dit]]
o = [[pt,pt,pt],[dah,dah,dah]]
p = [[pt,pt,pt,pt],[dit,dah,dah,dit]]
q = [[pt,pt,pt,pt],[dah,dah,dit,dah]]
r = [[pt,pt,pt],[dit,dah,dit]]
s = [[pt,pt,pt],[dit,dit,dit]]
t = [[pt],[dah]]
u = [[pt,pt,pt],[dit,dit,dah]]
v = [[pt,pt,pt,pt],[dit,dit,dit,dah]]
w = [[pt,pt,pt],[dit,dah,dah]]
x = [[pt,pt,pt,pt],[dah,dit,dit,dah]]
y = [[pt,pt,pt,pt],[dah,dit,dah,dah]]
z = [[pt,pt,pt,pt],[dah,dah,dit,dit]]
#put characters in a lookup array
lookup = [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]
#traverse the characters in the message converted to lowercase and to byte values
msg.downcase.each_byte do|ch|
case ch #deal with non-alphabetic characters
#nb a “rest” of appropriate duration is added after each
when 32 #space
note << :r
dur << ws #for word gap
when 33 # exclamation mark
note << [pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dit]<<cs
when 63 #question mark
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dah,dah,dit,dit]<<cs
when 46 # fullstop
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dit,dah,dit,dah,dit,dah]<<cs
when 44 #comma
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dit,dit,dah,dah]<<cs
when 45 # hyphen
note << [pt,pt,pt,pt,pt,pt]<<:r
dur << [dah,dit,dit,dit,dit,dah]<<cs
when 48 #0
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dah,dah]<<cs
when 49 #1
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dah,dah,dah,dah]<<cs
when 50 #2
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dah,dah,dah]<<cs
when 51 #3
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dit,dah,dah]<<cs
when 52 #4
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dit,dit,dah]<<cs
when 53 #5
note << [pt,pt,pt,pt,pt]<<:r
dur << [dit,dit,dit,dit,dit]<<cs
when 54 #6
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dit,dit,dit,dit]<<cs
when 55 #7
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dit,dit,dit]<<cs
when 56 #8
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dit,dit]<<cs
when 57 #9
note << [pt,pt,pt,pt,pt]<<:r
dur << [dah,dah,dah,dah,dit]<<cs
else #otherwise it is an alphabetic character
note << lookup[ch - 97][0].flatten << :r #look it up in the lookup array
#97 = a which is first char in array so subtract 97 to get index 0
dur << lookup[ch - 97][1].flatten << cs #flatten removes the []
end
end

define :playarray do |narray,darray,shift=0,vol=1,voice = :saw_s|
with_synth voice do
narray.zip(darray).each do |narray,darray|
if narray == :r #if a gap or rest wait the required time
sleep darray
else
with_transpose shift do #allows transposition (may be 0)
play narray,amp: vol,sustain: darray * 0.9,release: darray * 0.1 #play note
sleep darray + gs #gap till next note
end
end
end
end
end

playarray(note.flatten,dur.flatten,12) #remove remaining [] and send arrays to playarray, Third param is transpose shift

Avatar

S’funny.
I have an old Morse key, recovered from Oban Radio station, many many years ago.
As Marconi did many of his experiments from there, I wonder if he had ever used it…

Avatar

Great thinking!
I was considering this, you beat me to it.
I never got much beyond BASIC dialects, so I’m not much of a programmer, and after a stroke no longer have the mental agility, but still have ideas…
How about the server idea, with user database like the pi map, registration via program active on pi. Could even have same map display with indication of on-line/busy (when’conversing’ with another or just lurking).
An idea for JOTA?

73 de ZL2DEX

Avatar

Sigh… I *have* an actual telegraph key. Only dates to about WW2, though. My father mounted it on a board with a buzzer and a couple of strips of copper to act as a battery holder. My sisters and I played with it when we were kids…

Avatar

Oddly enough, Hal, I thought “Hal’s bound to have one” when I hit the publish button on this post. I am delighted to be proved right. :D

Avatar

I made my own Morse Code (CW)keyer from Lego follwing the instructions available here
http://www.scottwhittle.co.uk/amateur-radio

Leave a Comment

Comments are closed