Perimeter wire ru
- 1 Abstract
- 2 Perimeter v2 (used in latest robot code, recommended)
- 2.1 Signal
- 2.2 Filter
- 2.3 Sender
- 2.4 Receiver
- 2.5 Measurements
- 3 Tracking of perimeter
- 4 Sensor fusion
- 5 Further links
- 6 Perimeter v1 (for old v0.9.3 code, not recommended)
A perimeter wire (or buried wire fence, BWF) is like a 'virtual fence': it stopps the robot when it reaches its boundaries. A perimeter is not always necessary for all surroundings (a lawn sensor might be an alternative).
Principle idea: You will install a perimeter loop (a wire) in your garden through which a signal is sent and this signal is detected by the robot. So, you'll need: a sender (to transmit the on the wire) and a receiver (to detect the signal in the robot).
How is the signal detected? The signal is detected by one (or two) receiver coils. The closer the distance between coil and perimeter loop, the higher the signal strength. Also, something interesting happens when the robot crosses the perimeter loop: the signal changes its polarity, that means positive and negative voltages reverse each other. So, there are two basic principles to detect the perimeter loop. We have implemented both methods (perimeter v1 and v2) which are described below.
Perimeter v2 (used in latest robot code, recommended)
This is the new version of the perimeter sender and receiver (that can be purchased via the shop ).
While crossing the perimeter loop, something interesting happens: the signal changes its polarity, that means negative and positive voltages reverse each other. By using this principle, crossing the perimeter wire as well as the current state (robot is inside/outside) can be detected. As with perimeter v1, we will again use a motor driver to amplify the signal and an operational amplifier to amplify the received signal. The perimeter sender outputs a digital code sequence (aka 'pseudo-noise' code), and the receiver will detect that code using a software-based digital matched filter. Depending on wheter the match result peak is positive or negative, the robot is inside or outside of the perimeter wire.
- Generate output signal by Arduino Nano
- Amplify output signal by motor driver (MC33926), motor driver output connected to the perimeter wire (instead of a motor)
- Receive input signal with perimeter coil
- Amplify input signal with an operational amplifier (aka opamp - LM386)
- ADC sampling using Arduino Mega
- Signal filterung and signal detection using a digital filter (software-based matched filter algorithmn)
- Evaluation of matched filter output (for perimeter inside/ouside detection, tracking etc.)
The images below explain why the polarity of the received coil signal changes between inside and outside of the perimeter wire. The image shows the direction of the electric flux lines sent out from the perimeter wire and how they hit the coil for both inside and outside position.
To receive the perimeter signal everywhere on the lawn, the key is to maximize signal-to-noise ratio (SNR=signal/noise). There are two approaches to maximize SNR:
- increase signal strength (power) or
- increase the signal length
We use a combination of both. The sender sends a repeating sequence of a digital code ('pseudonoise4_pw') at 9615 Hz :
'1' means signal a positive pulse, '-1' a negative pulse. Because the shortest signal change generated is '-1,1', the highest generated 'tone' (if you would make this hearable) is 4808 Hz. The longest signal change generated is '1,1,-1,-1', and so the lowest generated 'tone' is 2404 Hz.
The coil only sees 'changes' of the sender signal - so (without using a capacitor in series with the coil) the received signal would be:
1,0,-1, 0,1,-1,1,-1, 0,1,-1,1,0,-1, 0,1,-1, 0,1,-1, 0,1,0,-1
However, using a capacitor in series with the coil, the received signal looks like the sender signal again.
The Arduino ADC samples the receiving signal at 9615 Hz.
The signal chosen has specific characteristic: it does not correlate in parts with itself - only as a whole sequence (because it looks 'random'). Because of this characteristic, the starts of the signal can be detected by a matched filter (aka 'correlation' with the search signal) and they generate a high peak in the matched filter result, even when high noise was added (due to motors etc.). The polarity of the peak (positive or negative) determines if the coil is inside or outside of the perimeter wire.
You can see how it works: For a better understanding of the perimeter signal and the filter, the matched filter is simulated here: Matched filter simulation
- Choose the perimeter signal at the right side (Set slider 'example signals': pseudonoise4_pw).
- Increase the noise a little bit (Set slider 'noise' to 2).
- At the left bottom plot ('Matched filter') you can see that the repeated signal was detected 3 times.
- Now simulate moving the coil outside of the perimeter wire. Click on 'Invert' to set amplifcation to '-1'. The matched filter results a negative match.
See also: Video about the matched filter
We use a motor driver as output amplifier and an Arduino Nano to generate the signal. The motor driver is driven by 3.2 Khz (two pulse widths 4808 Hz and 2404 Hz). With large enough perimeter wires, the circuit typically draws 10W (6.5V, 1.7A). We use a motor driver with integrated current limiting and thermal switch-off (e.g. MC33926). The perimeter wire length should be in the range 20m - 450m and must be at least 5 Ohm.
motor driver M1OUT1 o---------- perimeter loop (20-450 meters, > 5 Ohm) --+ | motor driver M1OUT2 o---------- perimeter loop ---------------------------+ motor driver Vin o-- 6.5V motor driver M1IN1 o-- Arduino Nano pinIN1 motor driver M1IN2 o-- Arduino Nano pinIN2 motor driver M1PWM_nD2 o-- Arduino Nano pinPWM motor driver M1nSF o-- Arduino Nano pinFault motor driver M1FB o-- Arduino Nano pinFeedback motor driver EN o-- Arduino Nano pinEnable motor driver VDD o-- Arduino +5V motor driver M1D1 o-- GND (via Jumper) motor driver SLEW o-- VDD (via Jumper) |---------o-- GND Potentiometer 100k -----o-- Arduino Nano pinPot |---------o-- Arduino +5V ACS712-05 OUT ------o-- Arduino Nano pinChargeCurrent ACS712-05 A ------o-- charging pin (+) ACS712-05 B ------o-- battery charger +24V battery charger GND-o-- charging pin (-)
Sender perimeter lawn size
At an operating voltage of 6.5V, the perimeter wire length should not exceed 450m. For 'kitchen test' a 100 Ohm resistor in series with 5m wire could make the job!
Assuming an ideal lawn shape (circle shape), we get a lawn radius:
radius = length / (2*PI) = 450m / (2*PI) = 70 meter
Assuming there is no maximum perimeter radius for good signal quality, the maximum lawn area size (ideal circle shape) would be:
area = PI * (r*r) = PI * (70m * 70m) = 15000 m2
However, assuming there is a maximum perimeter radius for good signal quality of 18m, the maximum lawn area size (ideal circle shape) would be:
area = PI * (r*r) = PI * (18m * 18m) = 1000 m2
Sender current control
To change the power (current/voltage) of the sender, you have several options:
- DC/DC Voltage: The motor driver supply voltage can be changed (6.5-12V via the potentiometer on the DC converter). That's one way to do it and it's the recommended way. NOTE: The minimum voltage (Vin) for the MC33926 motor driver is 5v. If the voltage is lower, the motor driver shuts down sporadically (undervoltage detection-Arduino LED starts to flash).
- Normal amplitude: Instead of switching the perimter wire between +Vin and -Vin (double amplitude/default), the motor driver can switch it between +Vin and GND (normal amplitude). This will reduce current. To use normal amplitude, comment out the corresponding code line in 'sender.ino':
// #define USE_DOUBLE_AMPLTIUDE 1
- Power resistor: If your perimeter wire resistance (R) is below 5 Ohms, you will not be able to further reduce voltage below 6.5v (otherwise the Arduino will not work properly). Then you have to increase the perimeter wire resistance (R) by using a power resistor (example: 5 ohm, 10W) in series with your perimeter wire.
@6 volts (Vin): 5 ohm power resistor => I=U/R=6v/5ohm=1.2A (P=U*I=6v*1.2A=7.2W)
So, your power resistor should be a 10W type or better. Activate 'normal-amplitude' in sender code (do not use double amplitude).
Sender current control (in development)
Idea: Replace poti VR1 by a digital poti (MCP4151-5K) and control LM2596 module output voltage (and so current) via Arduino:
Vout = 1.23V*(1+VR1/R1)
Using VR1=5K... Vstart (on reset): Vout=1.23V*(1+2.5K/0.33K)=10v Vmax: Vout=1.23V*(1+5K/0.33K)=19v
Sender automatic standby
The sender can be switched off during the time the robot is in the charging station. To detect the robot, a current sensor (ACS712) is connected between the charger and the charging pins.
NOTE: If you have never worked with Arduino before, read our 'Arduino first steps' introduction.
In the sender.ino you have this option:
- Define if you have connected a charging current sensor for automatic sender standby: #define USE_CHG_CURRENT 1 (or 0)
The perimeter sender status is indicated by the sender LED (Arduino Nano LED):
- ON: perimeter wire loop is closed and working
- OFF: perimeter wire loop is opened and not working
- blinking: robot is charging and perimeter will be switched OFF (energy saving)
Test sender with your PC's sound card
You can use your sound card to try out the sender with just a coil:
- Connect a coil (100 mH) to your sound card microphone/line input (max 1V)
- Launch the web oscilloscope, and choose Filter 'Matched', Frequency '9615' Hz, Visualization Math 'MinMax'
- The output signal should reflect the distance to your perimeter loop - the polarity (negative/positive) should indicate the side of the loop (inside/outside)
Try to move the coil as close as possible to the perimeter loop (for both inside/outside case) (Keep in mind that this is without pre-amplifier, so the signal will be only valid close to the loop - the microphone input cannot be higher than 1V, so we cannot use the pre-amplifier here).
For receiving the signal, we use a coil (100 mH or 150 mH) in upright position (centered at front in robot), connected through a capacitor 4.7nF (only older software versions) to an LM386 operational amplifier (to amplify the received signal). When using the LM386 module, capacitor C3 on the LM386 module should be bypassed (which is needed so that the LM386 generates a signal between 0..5V and not the default range -5V..+5V). The LM386 output pin should be connected to an analog Arduino pin ('pinPerimeterLeft').
LM386 IN o------- capacitor 4.7nF ----------- coil 100 mH (or 150 mH) Arduino pinPerimeterLeft o------o LM386 OUT LM386 GND o----------------------------------- coil
NOTE: It's recommended to directly mount the coil on the amplifier module. This ensures the 'small signal' of the coil is not distorted by other components (motors, DC/DC converters etc.).
Differential signal: Leave out capacitor 4.7nF in latest software versions (using differential signal).
Non-differential signal: If you use the capacitor 4.7nF to reconstruct the sender signal again (see section signal), the receiver circuit is an oscillation circuit (C and L, and perimeter wire acting as antenna) and everything (C,L,wire length) has to match. Because this makes it difficult to tune, the non-differential signal is not recommended.
Ensure all minimum distances to the following components:
* Coil to gear motor: > 15cm * Coil to mower motor: > 10cm * Coil to DC/DC converter: > 10cm
The sender / coil / LM386 amplifier outputs should look like this: (for more details about the signal, see section signal above)
Coil and noise measurements
Some coil measurements without amplifier but with noise (motors, DC/DC etc.):
Receiver ADC calibration
- The perimeter sender and robot motors must be switched off during calibration!
- If you cannot avoid that another sender is disturbing during calibration, remove the coil during calibration (connect LM386 input line to GND)
- Run the ADC calibration once ("pfodApp->ADC Calibration")
When calibrated correctly, the signal in the pfodApp plot ('sig') should be around zero (0) when the perimeter sender is switched off. When the perimeter sender is switched on, the plotted signal ('sig') should have the same maximum amplitude for both positive and negative axis (is 'symmetric around zero').
The receiver signal, filter result and signal quality can be monitored via Android phone (pfodApp->Plot->Perimeter):
Plot signal description:
sig: coil signal (raw pulse sequence after ADC) - it's a short snapshot (32 samples), and it's taken every 20 seconds (so you need to wait 20 seconds for the next snapshot) mag: filter result: inside (negative) or outside (positive), magnitude: distance to perimeter wire/magnetic signal strength (RSSI) - this is used for perimeter tracking smag: filter result, low-pass filtered, without sign (smooth mag) - this is used for 'sender-off' detection The threshold can bet set via pfodApp (Settings->Perimeter->Timed-out if below smag) in: binary result, low-pass filtered: inside (1) oder outside (0) - this is used for perimeter boundary detection If the robot is not inisde for a certain time, it will go into error. The threshold can bet set via pfodApp (Settings->Perimeter->Timeout (s) if not inside) cnt: number of "inside-outside" transitions (counter) on: perimeter sender active (1) or inactive (0), evaluation based on smag result qty: signal quality (how distinguisable inside and outside were in filter result computes ratio: match score with template signal / match score with inverse template signal 1.0 means poor quality, you should get 1.5 or higher)
The 'mag' plot should be clear (without spikes): Inside the perimeter loop, the signal should be a clear negative curve, outside it should be a clear positive curve. If your 'mag' curve is not clear (and has spikes), try to troubleshoot/optimize:
- Always test using long, correctly rolled-off perimeter wire (20m or longer) - Never use unrolled or too short perimeter wire. For 'kitchen test' a 100 Ohm resistor in series with 5m wire @ 5V could make the job
- Verify, your coil is connected correctly at 'pinPerimeterLeft' (you still may get a poor signal when connected at a wrong Arduino pin!)
- Reverse coil if the in/out is inverted or reverse the perimeter wire
- Minimize cable length between coil and LM386-pre-amplifier (directly mount coil onto pre-amplifier)
- Increase distance between coil and mower motor/DC converter (move away coil 30cm or more from any motors or DC converters)
- Add some magnetic shield (e.g. your battery) between coil and motors/DC converter
- Adjust voltage of sender: increase voltage (sender DC converter potentiometer) for for longer perimeter (>80m), decrease (sender potentiometer) for shorter perimeter (>25m)
- While motors are running, try to tilt coil slightly to one side so that 'qty' curve increases
For your reference, here are some outdoor measurements of different sender/receiver/perimeter loop combinations:
1) 120m (0.7mm^2), R=4 Ohm, 6.5V, coil Vpp 20mV
Noise (max): smag=192 Signal (min): smag=254 SNR=Signal/Noise=254/192=1.3
2) 30m (0.7mm^2), R=1.0 Ohm (+4 Ohm series R), 6.5V, coil Vpp 120 mV
Noise (max): smag=192 Signal (min): smag=896 SNR=Signal/Noise=896/192=4.6
- Perimeter2 demo
- 120m perimeter wire test
- Perimeter wire and matched filter theory (German)
- Sender PCB
Tracking of perimeter
The tracking of the perimeter wire is performed using a (software) digital PID controller. The controller's parameters (P,I,D) can be configured via the phone (pfodApp).
You can find more information about PID controllers here: Forum.
The perimeter magnetic field could be used as input for a robot position estimation.
- Another idea for navigation are infrared landmarks
- More details about the matched filter
- Sound card oscilloscope including matched filter
Perimeter v1 (for old v0.9.3 code, not recommended)
This was the first version of our perimeter sender and receiver. It has some drawbacks (orientation issues, no sender-off detection, no inside/outside state detection), so it's not recommended to build it anymore. Use the second version (v2) of our perimeter sender and receiver further below.
You can use the sender of a commercial lawn robot (the sender shown here is compatible with Tianchen or Rotenbach robot mowers), or you build one yourself.
So, here's the sender:
An Arduino (e.g. Nano) generates a square signal that is used to switch the direction of a motor driver (L298N) at 7.8 Khz. Thereby, the motor driver will switch the output between VCC and GND. A resonator circuit amplifies the signal spikes as it's dimensioned so that its resonation frequency is the same as the switching frequency (7.8 Khz). That way, the motor drive only needs to be operated at 5V (instead of 12V). The power supply should be able to supply 2W (400mA at 5V). One part of the signal is captured by the Arduino (ADC) through a diode and a voltage divider. This allows to detect if the perimeter loop is connected or not. A 150 mA current will flow through in the perimeter wire (wire cross section 2-3 mm^2) - the wire should not be longer than 500m.
Because it's sometimes difficult to find a specific coil, here are possible combinations (coil / capacitor) you can use (all will have a resonation frequency of 7.8 Khz):
- Combination 1: Coil: 160µH, Capacitor: 3,3µF/50V (tested)
- Combination 2: Coil 33mH, Capacitor: 12nF (not tested)
It is recommended to use a voltage step-down converter (e.g. module using LM2596) to generate the 5V voltage. Before connecting, set the voltage of the converter to 5V.
Warning : never connect more than 5V on the Arduino 5V pins, or you will damage the Arduino. Therefore, always measure the 5V voltage before connecting it to the Arduino 5V pin!
1. After uploading the code and connecting the perimeter wire, the Arduino LED should be ON. Now remove the perimeter wire - the Arduino LED should go OFF. 2. If that doesn't work: Using a voltmeter, measure once at Arduino pin D9 and once at motor driver output pin (OUT_1) against ground - both should have a DC voltage of 2.5 Volt. 3. If you have an oscilloscope, replace the perimeter wire by the oscilloscope. The measured signal look like below:
The output signal shows a higher amplitude (high spikes) as the input signal:
For a simple receiver test, you can simply connect the receiver coil to an oscilloscope. The measured oscilloscope signal should look like below:
This signal can be detected easily with a coil:
The receiver uses 2 coils mounted left and right in the robot. The signal strenght of left and right coils is evaluated to be able to compare them.
- Amplification of alternating signal using OPAMP
- Optional: Bandpass-filtering to filter-out noise caused by motors etc.
- Evaluation of signal strength of left and right coil
Advantage of this version: analog controlling works great. Disadvantage: You cannot detect, where you are (inside/outside) if your missed the perimter crossing. Also, you cannot detect if you drive clockwise or anti-clockwise on the perimeter wire.
A coil receives the sender's signal. A resonator circuit (LC) amplifies the received signal at resonation frequency (7.8 kHz). Then the signal is amplified using an LM386 (here: Arduino sound sensor using coil instead of microphone). A bandpass-filter (digital filter, FFT) on the Arduino filters the desired frequency (7.8 Khz) and outputs a PWM signal (pulse width is proportional to signal strength). A lowpass-filter converts it to a DC voltage. Note: Wiring between Nano and Mega has been simplified - see schematics for exact wiring.
We have tested the following combinations of amplifier und coils:
'Arduino sound sensor'
Important: When using this amplifier, capacitor C3 should be bypassed (will give a VCC/2 offset required for Arduino) and the coil will be connected to "IN" and "GND".
NOTE: It's recommended to directly mount the coil on the amplifier module. This ensures the 'small signal' of the coil is not distorted by other components (motors etc.)
- Make sure that the sender works correctly (see further above).
- Increase the Arduino Sound Sensor potentiometer to maximum (rotate counter-clock-wise).
- After uploading the code, move one coil towards the perimeter wire. The Arduino LED should start to blink. Now, hold both coils at same distance over the perimeter wire. The Arduino LED should be always ON now.
- If that doesn't work, open the serial console (19200 baud), and verify the signal values.
Choice for coil
Induction math, only approximation:
L = 1nH x n² x ((D² / mm² ) / (l / mm)) l = coil length D = coil diameter
Example: An inductance of 85 mH, and diamter of 10 mm, and length of 40 mm require about 5830 windings.
This inductance of 85 mH and a capacity of 4.7 nF results in a resonation frequency of 7963 Hz.
f0 = 1 / (2 * PI * sqrt(L * C)) = 1 / (2 * PI * sqrt(0.085 H * 0.0000000047 F)) = 7963 Hz
Because it's sometimes difficult to find a specific coil, here are possible combinations (coil / capacitor) you can use (all will have a resonation frequency of 7.8 Khz):
Combination 1: Coil: 85mH, Capacitor: 4.7nF (tested) Combination 2: Coil 104mH, Capacitor: 4nF (tested)
Arrangement of coils
The coils are arranged at the bottom of the robot, about 90 degress to each other, both turned 45 degress.
Measurements of signal strength
To compare measurements, the signal strength has been determined at several distances. The signal strength (i.e. the calculated ADC value) is shown in the Android pfodApp. The distance (cm) is the length calculated from the perimeter loop until the coil (coil built-in the robot).
Layout of the wire
It's important that the wire layout is round and does not have corners! Let's assume that the wire has a corner, and the robots drives exactly over the corner, it will not be able to detect the wire as both wire and coils are aligned.