Discman Powered Mower
June 26, 2010 19 Comments
A robotic lawn-mower
A few years ago my father bought one of Friendly Robotics‘s Robomows. The Robomow is a battery-powered robotic lawn-mower that will happily mow your lawn for you; all you have to do is charge up its battery and ask nicely. My father’s model is the RL550 and not only does it do an excellent job of cutting the grass but it emits a satisfyingly deep humming sound as it proceeds merrily about its work. Watching it work, one gets the feeling this is a mower that really enjoys its work.
The perimeter wire
Clever though the Robomow may be, it does need a bit of help figuring out exactly what it is that you would like mowed. To Robomow you are just as you are likely to want your prized Blue Bell Tunicates cut down to size as your are keen to have your grass cut.
Blue Bell Tunicate (not my picture)
In other words Robomow is absolutely snookered when it comes to finding the edge of your lawn unless you’re willing to lend it a hand. In fact (perhaps as a result of bad experiences in the past, I don’t know) Robomow will stubbornly refuse to cut a single blade of grass until you tell it where the boundary of what you would like cut is. As a result of this stubbornness, you have to lay a perimeter wire around your lawn at a safe distance from flowerbeds, pets and other garden features you think might not appreciate Robomow’s particular brand of attention. It takes a bit of time to lay the perimeter wire but it’s worth it and the good news is that once the perimeter wire is in place you need just one more thing: a perimeter switch.
The perimeter switch
The people at Friendly Robotics have thought of everything. When they send you your Robomow, not only do they generously include a length of perimeter wire but they also provide you with a small battery-powered perimeter switch. The perimeter switch helps Robomow find the edge of your lawn by sending a characteristic signal round the perimeter wire.
A broken perimeter switch
Robomow had been taking good care of my parents’ lawn for several years without any trouble at all and the lawn was in good shape:
However this Spring when my father was bringing Robomow out of its Winter hibernation, he was dismayed to discover that the perimeter switch appeared to be lifeless. Remembering that I liked to fiddle around with electronics, he asked me to take a look at the switch to see if there was anything I could do for it. Sadly, it was too late. We had to say our goodbyes to the old perimeter switch and order a new one. The new switch arrived in due course and Robomow was back in action. However my curiosity was now piqued: I wanted to know what signal the perimeter switch sends round the wire. I decided I’d try to analyse it a little and to build my own perimeter switch. I hope that a few people might be interested to read a little about what I learned in the course of my investigations.
The perimeter signal
First analog measurements
The perimeter wire is a single solid core copper wire with about 1mm diameter. The connector at the base of the perimeter switch has two terminals: one for each end of the perimeter wire. The perimeter switch creates the perimeter signal by placing a periodic potential difference across these two terminals. Robomow has a circuit which is designed to look for the magnetic field generated by the induced current round the perimeter wire. Also, the perimeter switch will not send a signal unless it detects a resistance of at most about 5 ohms between the two terminals (otherwise it reports a broken perimeter wire using one of its three status LEDs and its Piezo buzzer). I measured about 0.7 ohms of resistance around the perimeter wire in my parents’ garden. To measure the signal I thus placed a 1 ohm resistor across the two terminals of the perimeter switch and connected my oscilloscope (Link Instruments’ MSO-19) across the two terminals. As expected I found quite a simple signal. The perimeter signal (described in more detail later) is exactly 48.001ms (milliseconds) long and is divided into three chunks which are approximately:
- 16.001ms of silence (i.e. no potential difference) with a brief “blip” in the middle
- 16ms of 8KHZ sine
- 16ms of 8KHZ sine but almost exactly out of phase with the previous chunk
The amplitude of the sine waves varies depending on the resistance that is placed across the two terminals but for 1 ohm I measured about a 220mV swing from the minimum to the maximum of the sine waves. Here are some screen-shots from my oscilloscope’s software showing parts of the signal at various frequencies:
The apparent two levels of the sine waves in the above picture are just an aliasing effect caused by the low sample rate. Note the presence of a blip in the silence. We will see the genesis of this later when we examine the digital data.
At a higher sampling rate as in the above picture, the aliasing effect disappears.
At an even higher sampling rate we can see the waveform “charges up” (possibly literally) to its full amplitude over about 5 periods.
Shifting our attention to the transition period between the two 16ms sine wave chunks we can see the signal makes a slightly complex transition and again, the new phase-shifted sine wave seems to charge up over about 5 periods.
As well as examining the signal myself, I searched the web to see if anyone had written anything about the Robomow perimeter signal. The only reference I could find was on this page where on 17 Jun 2005, the user mackenziema wrote:
“I put my perimeter switch on my O’scope over the weekend. It’s a complex waveform that looks like 15ms of off time, followed by 32ms of 8KHz signal. The 8KHz burst is split into two levels. (don’t know why) The waveform of the burst looks like a sin
wave with pointy tops and rounded bottoms.”
Encouraged at the sensible looking signal and its similarity to what mackenziema had observed, I decided to press on with my investigations.
Perimeter switch circuit board
Perhaps the next most natural thing to do is to open up the perimeter switch and have a look at the circuit board and indeed this is what I did. Here are some photos of what I found:
Note that I took these photos after I had broken off the connector for the perimeter wire (so that I could use it for my own perimeter signal generator). Also the damage to the board near the empty white circle in the front picture is the result of my removing a corroded electrolytic capacitor in order to see if replacing it would fix the broken switch (which it did not).
The circuit on the board is pretty simple but unfortunately it is a little tricky to work out the exact connectivity because all of the solder globules appear to have a layer of insulation covering them. I think this is most likely to be some sort of conformal coating for weather protection. As a result of this I couldn’t use my multimeter to easily determine the connectivity of the various components and since it was pretty difficult to read the traces I decided I would make do without knowing the exact circuit. However it is a big help even just to identify the most important components on the board. These are:
- Microchip PIC16C54C (data-sheet)
- SDE 4.000MHz 12pf crystal oscillator
- LM393 comparitor (data-sheet)
- LM385 voltage reference diode (data-sheet)
- 74AC125 quad tri-state buffer (data-sheet)
- 74AC14 hex Schmidt inverter (data-sheet)
Not knowing the circuit topology, I can only guess at what these components are used for (e.g., as a friend suggested, perhaps the comparitor and reference diode are used to see whether the switch should report its low battery warning; alternatively it may be used for the broken wire warning). However it is clear that it is the PIC microprocessor that is in charge. The obvious thing to do then is to take a logic analyser and sniff the data on its pins. (Incidentally there was a sticker labelled PRG2007E on top of the PIC which I removed; I suspect this identifies the code which the manufacturers burned onto the chip.)
So I set about sniffing the data on the PIC pins using my USBee SX logic analyser (which in contrast to the digital lines on my MSO-19, has a nice big buffer size). I was only interested in PIC’s behaviour when it was in its mode of continuously sending the perimeter signal and so I set it up to do this across a 1 ohm resistor. I found that the only pins which carry data are RA3, RB3, RB7 (these pin names are taken from the PIC16C54C data-sheet). Here is a screen-shot from the USBee Suite (the logic analyser software) with some data from these pins which I sniffed at 8MHz:
The data on pin RB3 is used to flash one of the perimeter switch status LEDs (so the user knows the switch is working) and I suspect this is its only function.
Zooming in we can examine the data on the other pins in more detail:
and even more detail:
and elsewhere at the same zoom level:
Roughly speaking the digital data on RB7 appears to be periodic with period ~48ms. The signal which it sends is constant for ~16ms (with one state change from high to low in the middle) and has two ~16ms bursts of rectangular waves at 8KHZ with opposite duty cycles. All of this is in line with what we observed in the analog perimeter signal and it seems very likely that the other circuitry on the perimeter switch board passes this digital signal though a low-pass filter and amplifies it to produce the sine wave bursts that we saw above.
However I was keen to make sure I had understood the digital data completely (e.g., that it was truly periodic and there was not some modulated subtle signal contained in it). I wrote a simple script to read through a longish chunk of digital data (about 50 seconds worth, about twice as long as it usually takes Robomow to get started) and report a summary of what it found. Based on this I found that the data was as expected but with one mildly surprising (and probably irrelevant) quirk. To describe the digital data let’s introduce a tiny bit of notation. Let:
- L(l) denote l microseconds of low state
- H(h) denote h microseconds of high state
- LH(l, h) denote l microseconds of low state followed by h microsecond of high state (i.e., a rectangular wave that is low then high with h/(h+l) duty-cycle)
- HL(h, l) denote h microseconds of high state followed by l microseconds of low state (i.e., a rectangular wave that is high, then low with h/(h+l) duty-cycle)
- The notation xN indicate repeating N times, e.g., L(10)x5 is the same as L(50)
The exact behaviour of the digital data then is that the data is almost periodic with period 48.001ms but there are two very similar 48.001ms signals which alternate. Thus strictly speaking the data has period 96.002ms and the fundamental waveform is:
- H(8004.5), L(7996.5), HL(10, 115)x127, L(125), LH(11, 114)x127, H(125)
- H(8004.5), L(7996.5), HL(11, 114)x127, L(125), LH(10, 115)x127, H(125)
The above two 48.001ms signals are very similar except that the duty cycles of the rectangular wave bursts in the first are 8%, 91.2% respectively whereas they are 8.8%, 92% respectively in the second. I don’t know why Friendly Robotics have done this and I do not believe it matters but it is nice to have a truly accurate description of the data. Incidentally I sampled the data at 16MHz and also captured the 4MHz clock signal so that I could count cycles to be sure all measurements were absolutely correct. It might be helpful to include a schematic picture of the 96.002ms signal:
As I mentioned above, in view of what I measured with my oscilloscope for the analog perimeter signal, it seems very likely that the RB7 pin is being passed through a low-pass filter to generate the sine waves. I’m not terribly knowledgeable about filtering circuitry but I do know Fourier analysis quite well and thinking in terms of the filtering picking out one of the terms in the Fourier series for a rectangular wave, it would be the case that the complementary duty cycle of the second 16ms burst of rectangular waves in each 48.001ms digital signal would cause the observed half-period phase shift in the analog signal. It would also mean that the alternating 48.001ms digital signals with similar but different duty-cycles would result in an analog signal in which every second 48.001ms burst was very slightly phase shifted relative to the previous.
Further analog measurements
The measurements of the perimeter signal which I had made using my MSO-19 oscilloscope were useful but unfortunately the limited buffer size (1000 samples) meant that they were rather short. What would be ideal would be to have a 10Mhz, say, oscilloscope with a large buffer size so that I could capture and analyse a large portion of the perimeter signal. Unfortunately oscilloscopes aren’t too cheap and I couldn’t quite justify the expense (though I was tempted to buy Bitscope’s BS100) so I had to make do with the equipment to hand. However based on the measurements I could make with the MSO-19 and based on the digital data, it seemed very likely that the highest frequency signals I cared about were 8KHZ. I thus spent a little time taking high frequency (in the range 5-200MHz) snapshots of the small portions of the perimeter signal that I could using my MSO-19 to increase my confidence that there were indeed not higher frequencies present. After reasonably extensive searching, the only signals I could find were very tiny circuit “recoils” (as a friend put it) when the rectangular wave in the digital signal was changing state:
Fairly confident then that 8KHZ were the highest intended frequencies, I decided that sampling using my laptop’s sound card at 48KHZ (conveniently an integral multiple of the 8KHZ, thus mitigating aliasing effects) would be a fruitful way to capture a longer sample of the analog perimeter signal. I thus connected the perimeter switch up to the microphone of my laptop and recorded a minute of data and saved it as a wave file. I was able to examine the data easily using the python wave module as well as the pylab suite of tools especially matplotlib. Since my sound card is not limited by a small buffer size like the MSO-19, I was able to capture a long chunk of the signal at a sampling frequency which I had good reason to believe would give me a reasonably faithful representation of the signal. Saving a few plots from matplotlib:
Examining this data in pylab, I found everything as expected (aside from a few mild aliasing effects). It was quite satisfying how a simple laptop sound card could be turned into a usable low frequency oscilloscope with just a few lines of python! I found myself able to get the same data that I had previously relied on my oscilloscope to provide, using only my soundcard and it was easy to manipulate it thanks to the wonders of the python wave module and pylab. Also, I thought it might be worth making my recording of this signal available so here is a link to a gzipped wave file containing it.
Building a perimeter switch
A discman as a perimeter switch
Based on all of the above, I felt that I understood the perimeter signal sufficiently well to be able to build my own perimeter switch and so I set about doing this.
The convenience that the frequencies involved fell well within the audio range meant that I could use standard audio equipment that I had lying around to help. I decided to use an old discman to play back a signal which I would generate and burn to a CD. The only other thing I needed was a simple amplifier. After searching around a little I found a cheap amplifier chip on eBay, the LM386N-1 (data-sheet). I built a circuit straight from the data-sheet (using the closest resistor/capacitor values I had to hand):
I powered my circuit with a 9V battery, connected the input up to my discman’s headphone jack (through an appropriate resistor) and in place of the speaker shown in the above diagram, I connected up the perimeter cable together with an additional 5 ohms of resistance in series. Using the volume control on the discman as a signal strength controller was very convenient.
Generating a signal
With the above taken care of, all I needed to do was generate my own perimeter signal and burn it to a CD. I decided to write a simple python script to generate a 44.1KHZ-sampled wave file mimicking those aspects of the perimeter signal which I thought mattered.
Here is the python code which I used to generate my signal:
import wave, math, struct samp_freq = 44.1e3 #samp_freq = 48e3 #samp_freq = 96e3 sig_len = 5 * 60 blip_len = 1e-4 n_blip_samps = int(blip_len * samp_freq + 0.5) period = 48001.0 # Note extra microsecond (doubt matters). n_cycles = int(sig_len / period) freq = 8e3 on_tm = 16e-3 vol = 16384 data =  n_samps = int(on_tm * samp_freq) for i in range(n_cycles): for j in range(n_samps): data.append(vol * math.sin(2 * math.pi * freq * j / samp_freq)) for k in range(n_samps): data.append(-vol * math.sin(2 * math.pi * freq * (j + k) / samp_freq)) T = len(data) / samp_freq N = int(T / period) t = (N + 1) * period - T n = int(t * samp_freq) k = 0 for j in range((n-n_blip_samps)/2): data.append(0) k += 1 for j in range(n_blip_samps): data.append(vol * math.sin(math.pi * j / (n_blip_samps-1))) # Bit of a guess and probably not necessary. k += 1 while k < n: data.append(0) k += 1 f_data = wave.open('%d_perimeter_signal.wav' % samp_freq, 'w') f_data.setparams((1, 2, samp_freq, samp_freq, 'NONE', 'not compressed')) f_data.writeframes(struct.pack('%dh' % len(data), *data)) f_data.close()
Let me begin by telling the story of a successful attempt to get Robomow to obey my discman.
I gathered my amplifier circuit, discman, signal CD etc. and went round to my parents’ house. There I set up my equipment, pressed play on my discman and turned up the volume till my oscilloscope (which I had also connected up to the perimeter wire) indicated appropriate signal strength. I then turned on Robomow and asked it to mow. To my absolute delight it complied! It began mowing, reached the perimeter cable at the edge of the lawn, turned correctly and continued mowing. After another pass across the lawn, it reached another edge and turned for a second time. At this point I asked my brother who was present to press pause on the discman. Instantly Robomow stopped and complained that the signal had disappeared. This was all great news. My python script’s CD track was controlling the mower. Success!
A calibration problem?
Although I was able to get Robomow to obey my signal, unfortunately I was not able to get it to do so reliably, at all. For the vast majority of my attempts, Robomow indicated my signal was present on its signal strength indicator but when asked to mow would think about it for a long time before eventually refusing. Unfortunately without taking apart Robomow (which I don’t want to do) very little information is obtained on each attempt. Not having Robomow obey my perimeter signal reliably is a little disappointing and I dare say I could overcome this final hurdle but having already spent a lot more time than I ever wanted to on this project, I decided it was time to write up and stop. My partial success was still fairly satisfying!
I also hoped that by posting an article on my blog I might get some useful feedback as comments. I would still like to know why Robomow so seldom obeys my signal even though it is extremely similar to the signal generated by the official perimeter switch. I am aware of some very small differences (e.g. the circuit recoils, the slightly different joining between the two 16ms bursts of sine waves, the slight phase difference on every second pulse, the charge up times at the beginning of the bursts of sine waves, …) but I would be very, very surprised if any of these are intended features that Robomow looks for. Unfortunately it was only at the very end of this project that I read the section in the manual that talks about calibration more carefully. I discovered that when you buy Robomow new, you have to calibrate it with the perimeter switch turned on. You can read about this on pages 21, 22 of the manual which I found on the Friendly Robotics website. However I also consulted the printed manual that came with Robomow and it had a little more to say about calibration (it carries document number DOC0099A instead of DOC0012A):
“The Robomow uses a sophisticated navigation system that utilizes an on-board compass type device, which responds to the magnetic poles of the earth. Magnetic North can vary from one point on the earth to another based on geography. In order to accommodate this variance, it is necessary to calibrate the compass device to the area of the earth where Robomow is being used. This is a one-time process and need not be repeated unless Robomow is moved several hundred miles from its’ [sic] present location.”
The bit about the earth’s magnetic field is interesting but, I think, not relevant. However the above paragraph makes it clear that Robomow permanently (or at least till next calibration) stores data about the magnetic field of the signal it measured during calibration. It seems plausible to me that Robomow is not so keen on the signal I send because it is calibrated to Friendly Robotics’s perimeter switch signal which my father calibrated it to years ago. It may thus be expecting some of the (presumably unintended) artifacts (mentioned above) which I have not included in my cleaner signal. I would expect that if I was willing to recalibrate Robomow with my signal turned on then it would always reliably work with mine. However I don’t want to do this for fear of not being able to successfully recalibrate Robomow back to the perimeter switch afterwards. (I expect I would be able to but Robomow is expensive and I’d rather not take the risk since it’s working well now.) I’d be interested to hear any opinions from readers. One final thing to note here is that I did not succeed in getting Robomow to obey an amplified recording I made of the true perimeter switch signal played through my discman and sampled at 44.1KHZ. This suggests that if Robomow is calibrated to artifacts then it is sensitive to some with reasonably high frequency or that there are artifacts generated by my LM386N-1 amplifier which it doesn’t like (though I haven’t seen these on my oscilloscope).
A final thought
Shortly after posting the above I had one final thought on this. If we have a periodic signal of period T then we can take any interval of length T as a fundamental domain to represent the signal. However for some signals some choices may be more natural. In particular, thinking about the digital signal I may not have broken up the signal in the most natural place. I think that it would be more natural to break up the 96.002ms signal into two 48.001ms chunks with complementary duty-cycles for the 8KHz chunks. We can do this if we break down these chunks as:
- 16ms 8KHz oscillation
- 16.001ms silence (with blip)
- 16ms 8KHz oscillation
rather than putting the silence first as I have above. My schematic picture of the digital signal in this case is then:
Looking then at the analog signals I took with my soundcard it looks like there is a simple alternating amplitude modulation taking place between the 48.001ms chunks. I had noticed this before but not taken it very seriously till I saw everything at once when I wrote this post. Perhaps this is the extra detail which I should include to make my perimeter signal more reliable?