The construction and software files contain the complete information for building the project.
Ground Penetrating Radar using Arduino
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
The construction and software files contain the complete information for building the project.
Operation_Instructions.txtOperation instructionsplain - 2.86 kB - 09/26/2026 at 19:04 |
|
|
Software_stacked_version.zipArduino and PC (in LabVIEW 2013) software source code (performs decimation and stacking on scan samples)x-zip-compressed - 920.25 kB - 10/07/2026 at 16:17 |
|
|
Antennas_v2.zipAntennas - New version of antennas, must be printed on double-sided PCB FR4 laminate size A4 (210 x 297 mm). PDF for Toner Transfer construction (Top layer mirrored) and GERBER filesx-zip-compressed - 70.87 kB - 05/15/2024 at 11:54 |
|
|
PCB_Construction_Toner-Transfer_Method.zipPCB images in PDF for Toner Transfer PCB construction (Top layer mirrored), and schematicsx-zip-compressed - 1.93 MB - 08/27/2025 at 09:16 |
|
|
LF(GPR_LF).zipOrCAD 9.2 design files and Gerber for Low Frequency boardx-zip-compressed - 159.42 kB - 06/07/2025 at 18:40 |
|

System tested on a bridge. This is the GPR image obtained for the bridge in the photo:
System tested and works fine.
Antenna coupling is quite high. Would be nice placing the antennas at a bigger distance from each other, or using more directive antennas in order to reduce unwanted coupling.
This is how the electronic boards are stacked.
Create an account to leave a comment. Already have an account? Log In.
Just as a thought, the scan seems to show the roof of your driveway, when you reach your truck (metal) there should be a huge amount of reflections that’s maybe the reason why you saw this anomaly in this shape. I guess the same case might show if you scan while a human passes under you (huge amount of water inside the body).
This is my simple analysis it might be wrong.
@Mirel Paun this is my first real test, anntenas are bowtie with no shield above them, distance between them around 55cm and they are 2cm above the ground with wheel type (i did make wood slider with 4 wheels and a trigger on one wheel), concrete mode with depth 2.5m, the test is on large bridge under me there where three concrete holders for the bridge, even with 7000 it didn't show as white pixles and I did feel that the holders didn't show as what they supposed to be, I did got this kindly can you help me in reading it to decide if I have faults
https://myimgs.org/image/HWXBX8kX
https://myimgs.org/image/hpIcAxic
I think you should repeat the test with the 30dB attenuator and see what it shows. The reflections are quite week, maybe there's some faulty connection to the antennas.
This is a test with 30db attenuator connected using 3m cable and the debug version, I guess it is perfect, what you think my issue might be, the anntenas are cooper and I did test them on tinySa they are getting signals like I connect one anntena to the tinySa and the other to GPRino tx and I did got the signal on the screen idel (just plug Arduino with power) around 660Mhz
https://myimgs.org/image/ZrShkuFq
@Mirel Paun mabye my issue related to my soldering of the SMA connector since my attenuator test is ok, what do you think,
https://myimgs.org/image/OUA7b72B
In all cases I am now working to make the distance between the anntenas edge's 1m and I will but 45*45cm steal plate 15cm above the anntenas, but kindly I need your recommendations.
After do this test and make 1m between the anntenas with steal on top the signal reduced to about 2000 not more while for 7000 it is working only without steal and the distance no more 30cm what is your opinion
Sometime even a green pixles shows on the lcd screen that's up normal
This is the latest images after removing the battery sampling from the code. I didn't realize that it was now using every once of speed the arduino can muster...
https://myimgs.org/storage/images/57490/StackedSample.jpg
https://myimgs.org/storage/images/57491/StackedImage.jpg
The reference value is set to 7000 in the arduino and the .vi which seems good.
The scan is a simple back and forth over the same spot in my office and the settings are:
Concrete
depth = one meter
distance = 3 meters
Is there a better place to communicate about this GPR project? This seems clunky here and we can't share images and code easily.
I have not had any luck at all with the latest code, all I get are bands of dark - light - dark - light. I'm going to work on mine a little more today.
And the old code runs OK? It's strange, because I tested it on my hardware and it worked fine. Maybe something broke in the hardware?
I noticed that you removed the battery level meter code. I kept it in mine, could that be the issue?
Yes, absolutely if you kept the battery level meter it interferes with the new faster sampling strategy I implemented. Use the new code exactly as it is. The battery meter was useless anyway because powerbanks always give 5V at their outputs, so you have to check their integrated level meter.
This is what I get now, I have taken several readings:
https://myimgs.org/storage/images/57082/StackedLCD1.jpg
https://myimgs.org/storage/images/57087/StackedImage.jpg
@Dan I am with you in finding a better way to commuincate since me and you I guess the only persons that reach to full model of the GPRino device. During my test I did face issue like yours (the one in the images) it was due to lossey connection between the RF and LF. @Mirel Paun I did make another design like you did in your handheld version what you think is better the one with wheel or this one since I guess the annetans will not be at fix distance from the ground all of the time due to the movement. One last question how to define that 7000 value is the best since new 64 sample start to give white reflections on this value but also 3000 give also but larger amount ?
@Control_Eng Use the new code exactly as I uploaded it, without Battery meter, otherwise will not work. The wheel version is better than handheld, but the handheld one is more handy in certain scenarios, and can be made also easier to carry disassembled. The default reference value I obtained from experiments is 12000.
Yes I did use it as is. if 12000 gave you the correct behave then in my case why at 7000 I did start to see the old 256 sample behave is because my testing senario (room floor) or I have issues in my signals, when I did test it with 30db antteuator it gave me a good shape of sine waves?
this is my .vi after test with 12000
https://myimgs.org/image/h1jA3DG0
and this is my .gpr
https://storage.to/21unwXp9R
The sine waves were OK. Probably the difference is from the antennas, because I use now bow-tie antennas with back reflector, so the echo signal is higher for me, so 7000 for you gives the results I have at 12000.
Dear @Mirel Paun I did test it with the 64 sample, it starts to give LCD white pixles at 7000, above that mostly it shows light black and gray scale only.
Hello @Mirel Paun after enhance some of connections, I got these debug image with the 30db antteuator, what do you think (I guess now my GPRINO should work perfectly),
https://myimgs.org/image/cW0tRU7X
I have three questions on it:
1. Why the sine wave is almost disapear starting from 150 sample index,
2. The previous image is without the powerbank connected since after connect it and test I feel that the sine waves become larger,
https://myimgs.org/image/7Ri3GIXD
3. Finally, I did got multiple since waves because we are taking 256 sample per each scan right ?
Yes, looks perfect now.
1. The sine wave diminishes after 150 samples because the power generated by the JTOS oscillator decreases with increasing frequency. It is an imperfection of the oscillator described in its datasheet.
2. The signal increases after using the powerbank because the powerbanc gives a bit higher voltage than the USB (4.8V USB vs. 5V powerbank).
3. Each measuring position (a scan) is 256 samples. It produces a vertical column in the image after FFT processing. When moving the device takes scan after scan to create the image (column after column).
I uploaded here and on GitHub a new version of the programs (Arduino and PC) which performs decimation of the scan samples to 64 samples, then mediates over consecutive 4 scans (procedure called stacking) and then processes by FFT the resulting 64 samples decimated and stacked signal. It also samples 1.5 faster. This procedure decreases the maximum displayed depth by 1/4 to aprox. 7m in air, but theoretically improves SNR and sensitivity. You can give it a try and compare the results.
Thanks @Mirel Paun, this
https://myimgs.org/image/S20sFY9I
is after the 64 sample edit, and I did notice that the amount of white pixles on on the arduino mega screen become almost not there, only black pixles above the usual at 0 depth,
It should behave more stable and be more sensitive in this version with decimaton and stacking. At least this is what theory says.
Hello @Mirel Paun good evening, I did test for the same area as I did for the old code before the 64 sample edits,
Here is the resutls for images (vi+RGPR)
https://myimgs.org/image/IYi0tQlT
https://myimgs.org/image/OLLu6m1Q
And this is the .gpr file,
https://storage.to/ljnNYR3Jn
I noticed something unusual in the VI graph. It still shows some white areas, but they are much smaller than in my previous test (in the 256 sample). Since I was testing over a concrete floor, I expected the white region to be larger because the concrete should produce a relatively strong reflection (it almost was showing that in the old one as near continious line of white pixles).
What is even more unusual is that, during the test, the Arduino screen did not show any white pixels at all. It displayed only black and gray areas. Similar to this image
https://myimgs.org/image/mFkUBHuA
I had similar results on the gpr screen. I have not installed the new vi program, so I’m anxious to see what that looks like for me.
I also am scanning through a layer of concrete foundation.
For the LCD problem, try increasing the reference maximum value by pressing the UP button when the device is standing still. The default value is 12000. Try increasing it so that the image becomes OK on the LCD. And please tell me at what value the image is OK.
Regarding the concrete floor, I don't know why it looks different now, in theory it should be better now. Maybe there is an inhomogeneity in the middle section of the concrete slab (some insertion) and now it became visible.
@Dan hello Dan, yes this new thing I am testing after Mirel change the sample rate to be 64 vs 256 old one, this reduce the depth but should enhance the results.
how do I install the new .vi file. The only way I've done it in the past is with the installer program.
@Dan as far I know (how I did it) .vi will not work without labView installed in your computer, I did install it and activate using student license, then you can run the .vi
When I load the data from the GPR to the GPRino tool, the depth scale seems to be wrong. My setting on the GPR was only for a depth of just over 2 meters, but when it;s imported, the depth goes all the way to 13 meters.
Is there something I am doing wrong?
There is no problem. It always stores all depth data no matter what the visualisation setting was on the LCD, which is 13 meters in air. You can modify the scales in the PC program at wish.
I uploaded here and on GitHub a new version of the programs (Arduino and PC) which performs decimation of the scan samples to 64 samples, then mediates over consecutive 4 scans (procedure called stacking) and then processes by FFT the resulting 64 samples decimated and stacked signal. It also samples 1.5 faster. This procedure decreases the maximum displayed depth by 1/4 to aprox. 7m in air, but theoretically improves SNR and sensitivity. You can give it a try and compare the results.
Hello @Mirel Paun good day, after test it with 30db 3w anntteuator and 3m cable I did got this graph in the debug mode, is this ok ?
https://myimgs.org/image/pW2q2tUm
Looks relatively well. Ideally it should be more like a constant amplitude / frequency sine wave. Your signal has some distorsions, but it it pretty good.
After ensuring on some connections I got this with 30db anettuator,
https://myimgs.org/image/YDZbEYmJ
Then after doing test on my room floor with another room under me I got this wwith concret mode,
https://myimgs.org/image/1Y1nX7HC
And this is the .vi software
https://myimgs.org/image/UKRcf2YB
And the RGPR R lib
https://myimgs.org/image/4JDi2g2k
What your analysis for the new debug image ? and what do you think, do it worth to start real test ?
There is some distortion in the debug signal, I don't know where it comes from, maybe a faulty connector. But overall it looks OK.
In RGPR try this:
library(RGPR)
x <- readGPR(dsn = "D:/test.txt")
#set velocity
vel(x) <- 0.12
#limit to first 500 depth samples
x1 <- x[1:500, ]
#dewow filter
x2 <- dewow(x1, type = "Gaussian", w = 20)
#depth attenuation compensation
x3 <- gain(x2, type ="exp", alpha = 0.01347, t0 = 0, te = 110)
#filter clutter
data_matrix <- values(x3)
mean_profile <- rowMeans(data_matrix)
clean_matrix <- data_matrix - mean_profile
x_clean_alt <- x3
values(x_clean_alt) <- clean_matrix
#plot
plot(x_clean_alt, col = palGPR("grey2"))
I did make longer test (I guess the .gpr is consist of the old one and the new one you can see the dif from the graph). Here are the images:
vi
https://myimgs.org/image/ozRCKPx6
PGPR
https://myimgs.org/image/XEyf9QyP
So I just tried for the first time to load the file to the GPRino_v2.vi program and am getting nothing but a black screen.
When I click the 'Load from GPR' button and name the file, it resets the unit and after a little bit the screen says "Done". It changes the resolution from 0 to 0.278293 and sets the Amplitude to 120, but the screen remains black.
I never get a screen that asks if I want to delete the file on the SD card, the lcd just goes back to the Waiting to connect screen.
I have verified the com port and it is communicating, hence the reset, but no data is ever displayed on the PC.
What am I doing wrong?
I was able to successfully open it by putting the SD card in the PC and opening the Data.gpr file. So I am assuming a communication error??? Transfer speed maybe?
After digging in a little, I believe it's because I am using the Keyestudio Mega2560 USB-C version which has a CP2102 USB to serial IC.
That IC resets the Arduino via a DTR command every time the serial port is opened. If the GPRino code included a command to hold the DTR inactive, it would solve the issue I think.
UPDATE: Yep, I removed the cap that links the CP1202 DTR reset line from the rest of the curcuits reset system and Viola, I can now download directly from the GPR to the GPRino program.
So the problem was the reset circuit. I'm glad you solved it.
Yes, I had to rewire a capacitor on the Keyestudio (Arduino) board that connected the CP2102 DTR line to the reset circuit of the ATMEGA ic. I ended up using a switch to connect or disconnect that line depending on whether I wanted to download program updates, or upload GPR data. Just In case anyone else runs into this problem.
@Mirel Paun I am happy to share all my PCB gerber files, schematics (in PDF form), and the converted Arduino code that allows for a different LCD screen. Let me know if you want me to send them to you.
Curious what this section of code is doing, looks like it's setting the amplitude of the signal from the antenna, but I want to be sure:
// ------------------------------------------------------------------------------
// Reference Level Function
// ------------------------------------------------------------------------------
void check_reference_level()
{
if (!digitalRead(button_down))
{
if (max_amplitude > inf_lim_max_amplitude)
max_amplitude -= 1000;
else
max_amplitude = inf_lim_max_amplitude;
delay(500);
}
else if (!digitalRead(button_up))
{
if (max_amplitude < sup_lim_max_amplitude)
max_amplitude += 1000;
else
max_amplitude = sup_lim_max_amplitude;
delay(500);
}
}
The section you pointed out lets you set de reference (maximum) level used for plotting the GPR image (using the up down buttons). The lower this level is, the whiter the image becomes. It's the same as playing with the 120 limit in the LabVIEW .vi (the scale on the right of the graph).
BTW, I am willing to sell a set of these antennas for $100 US, but it would be a couple of weeks to have them made since I only have one extra (not a set) right now. I can also provide the Altium files with gerbers for free if you want to get your own made.
I noticed though that you are not wanting Vivaldi style antennas.
I figured I'd post a few more images in case it helps:
https://myimgs.org/storage/images/32676/IMG_1767.jpg
https://myimgs.org/storage/images/32677/IMG_1770.jpg
https://myimgs.org/storage/images/32678/IMG_1771.jpg
https://myimgs.org/storage/images/32679/IMG_1773.jpg
I took some samples across this bridge:
https://myimgs.org/storage/images/32680/IMG_1776.jpg
Sorry for the terrible images, it was hot and sunny out and really hard to get any good pictures:
https://myimgs.org/storage/images/32698/IMG_1780.jpg
https://myimgs.org/storage/images/32700/IMG_1781.jpg
https://myimgs.org/storage/images/32701/IMG_1779.jpg
https://myimgs.org/storage/images/32702/IMG_1777.jpg
You can definitely see the outline of the walls of the wash. I only tried this with concrete and asphalt velocities, but it would be interesting to get scans using every medium.
The device looks very well. The GPR images are nice. Would be interesting to know what a professional GPR operator thinks about our images, because I am not a professional in this field and I never used a GPR other than my own prototypes, so I don't have a comparison term.
You can try this RGPR data processing. Has interesting results:
library(RGPR)
x <- readGPR(dsn = "D:/test.txt")
#set velocity
vel(x) <- 0.12
#limit to first 500 depth samples
x1 <- x[1:500, ]
#dewow filter
x2 <- dewow(x1, type = "Gaussian", w = 20)
#depth attenuation compensation
x3 <- gain(x2, type ="exp", alpha = 0.01347, t0 = 0, te = 110)
#filter clutter
data_matrix <- values(x3)
mean_profile <- rowMeans(data_matrix)
clean_matrix <- data_matrix - mean_profile
x_clean_alt <- x3
values(x_clean_alt) <- clean_matrix
#plot
plot(x_clean_alt, col = palGPR("grey2"))
https://myimgs.org/storage/images/41594/testone.png
I did a quick scan in my house and loaded it to RGPR, this is the result.
Do you think it would be better to load the converted .gpr file?
My goal is to do a grid scan and reconstruct the grid in a 3D plotting program. I think RGPR could be made to do that. I'd love to hear your thoughts and pointers.
This processing reduces clutter by reducing the constant features that appear in horizontal lines. So it eliminates antenna-soil reflection and other horizontal constant reflections.
The image looks clearer than without this processing, so localised object are more visible.
Yes, I think it is better to use this processed image and RGPR has the feature for creating 3D.
For the stacked code the processing in RGPR is:
library(RGPR)
x <- readGPR(dsn = "D:/test.txt")
#set velocity
vel(x) <- 0.12
#limit to first 250 depth samples
x1 <- x[1:250, ]
#dewow filter
x2 <- dewow(x1, type = "Gaussian", w = 20)
#depth attenuation compensation
x3 <- gain(x2, type ="exp", alpha = 0.01347, t0 = 0, te = 110)
#filter clutter
data_matrix <- values(x3)
mean_profile <- rowMeans(data_matrix)
clean_matrix <- data_matrix - mean_profile
x_clean_alt <- x3
values(x_clean_alt) <- clean_matrix
#plot
plot(x_clean_alt, col = palGPR("grey2"))
Hello @Mirel Paun good day,
When I look at modern GPR systems such as the LMX,
https://onesurveying.com/upload/img/UtilityScan-Pro_Data1.jpg
https://telonix.ca/product/lmx200-ground-penetrating-radar-gpr-utility-locating-equipment/
The hyperbola responses are very clear and have a well-defined shape. In our Python debug viewer, I can also see some responses that resemble hyperbolas, but they are much less clear and are often hidden by background response, ringing, or noise.
At this stage, I am not even fully confident that these responses represent real targets. Their color, intensity, and shape are not consistent between repeated test runs, and they are usually quite small and difficult to distinguish. Because of that, it is hard to know whether they are genuine reflections from buried objects or simply artifacts/noise that happen to look like hyperbolas.
Do you think that by applying the right processing filters such as background removal, gain/normalization, band-pass filtering, and possibly migration or hyperbola enhancement we could achieve a display closer to modern commercial GPR systems while still preserving the real target response?
Also, I tried generating a .gpr file from the Arduino debug version. When I open it in the .vi viewer, the radargram appears extremely dark. I can see some blue features, but the overall intensity is so low/dark that it is difficult to distinguish targets or structure. I suspect the amplitude scaling, normalization, or dynamic range used when writing the .gpr file may not match what the viewer expects.
If it might help I can be part of any idea that can do filtering and provide modern look, just lead me and I will be ready to provide help, I did make android application also from the debug one we can work on it if you love.
Hello! I know the images don't look as good as in modern commercial GPRs. I can't figure out the exact source of this difference. I think the problem may be the reduced resolution of the onboard ADC, only 10 bits, while modern systems use something like 16 to 24 bits combined with oversampling or signal stacking. This can only be achieved in our case by redesigning the whole GPR around a more powerful microcontroller board like Arduino GIGA.
I don't know which filtering can improve image quality.
The Arduino debug PC Python version generates .txt files which are not compatible with the .vi viewer, but are compatible with RGPR. They are not depth compensated, so you can play with the depth compensation in RGPR.
Aha, so for my case now I am running the debug mode on Arduino Nano that cause issues?.
No, the .gpr I have make it in the arduino code and store it in the card, then run the .vi and import it,
Nano, Mega, both have 10 bit ADCs so the performance is the same. Only GIGA can offer 16 bit ADCs, but GIGA works at 3.3V and is damaged by 5V signals, so the whole circuit has to be redesigned for it.
If your code stores the data samples exactly like the LCD version, the image should look the same in the LabVIEW .vi.
this is the image from the .vi test mode concret, step size 0.083
https://myimgs.org/storage/images/30191/Screenshot2026-08-24165508.png
and this is the image after convert it using convert and show it in R
https://myimgs.org/storage/images/30193/Screenshot2026-08-24165941.png
and this is the used code,
https://limewire.com/d/zfbMn#WJ1eTEGlZ3
I guess I have a critical issue right ?
The code looks fine. But the image doesn't. There is definitely a problem. Can you send me the .gpr file to look at it?
This is the .gpr file,
https://limewire.com/d/X3R3f#M7M5wuR6WW
I analysed the .gpr file. The acquired signal's amplitude of your GPR is close to 0. Something is wrong I guess in the hardware. Maybe an RF amplifier is fried or something else.
I re-analysed the file I get ADC mean 508.9, average RMS 15.5 ADC counts, average peak-to-peak 113.8 counts, consecutive trace correlation 0.937, and repeatable fraction 0.838. The waveform appears highly repeatable rather than random noise. Can you tell me how I can point where my issue might be, I have a sepctrum analyzer and when run the gpr I did has somthing as the sweeping frequncies between around 350-850 Mhz.
This image from another test (I did connect the 5v to powerbank in first it was to arduino 5v)
https://myimgs.org/storage/images/30367/Screenshot2026-08-25005127.png
And the .gpr file
https://limewire.com/d/XdWmM#AIrHtYXgHe
and this analysis is using chatgpt
File: test_1.gpr
File size: 113154 bytes
Velocity index: 0
Number of scans: 221
Samples per scan: 256
===== RAW ADC =====
Minimum ADC: 0
Maximum ADC: 712
Mean ADC: 507.1676682692308
Std deviation: 37.45566277391703
Overall peak-to-peak: 712
===== SIGNAL AMPLITUDE =====
Average peak-to-peak: 146.07692307692307
Minimum peak-to-peak: 76.0
Maximum peak-to-peak: 352.0
Average RMS: 17.460869681903173
Minimum RMS: 12.211624135965122
Maximum RMS: 33.97335646628047
Average max absolute amplitude: 84.30348557692308
===== TRACE REPEATABILITY =====
Average consecutive correlation: 0.9184330585555502
Minimum correlation: 0.22616165271518174
Maximum correlation: 0.9975520187927019
===== AVERAGE TRACE =====
Average individual scan RMS: 17.460869681903173
Average trace RMS: 12.339465733380525
Average trace peak-to-peak: 95.80090497737557
Repeatable fraction: 0.7066925049082416
===== ADC SATURATION =====
Samples near 0: 150
Samples near 1023: 0
===================================
SIMPLE DIAGNOSIS
===================================
ADC DC bias looks reasonable.
WARNING: Some ADC samples appear saturated.
There is measurable signal variation at the ADC.
Traces are highly repeatable.
This strongly suggests a real repeatable waveform is present.
A large fraction of the waveform survives averaging.
IMPORTANT:
This script can identify weak/noisy/saturated data,
but it cannot prove that an RF amplifier is damaged.
A known-good GPR file or oscilloscope measurement is needed
to confirm a hardware fault.
===== EXTREME TRACES =====
Weakest scan: 23
RMS: 12.211624135965122
Peak-to-peak: 88.0
Strongest scan: 155
RMS: 33.97335646628047
Peak-to-peak: 352.0
The signal is way too weak. Something is wrong. From my experience the RF amplifiers are very sensitive, I fried mine while building my first prototype. The one in the receiving part of the RF board may be the problem. Or other things like faulty wires can be the problem. But I bet on the RF amplifier.
During tracing I did broke one bias tee, I will order a replacement, in addition I will order amplifiers PSA replacements. Do you think that my antennas (I made them from home use thin aluminum foil) might cause this, if so, do you have an online link to buy them (bowtie and antipodal). During trace I found that without antennas attached for ADP-2-4-+ pin 4 and GND has resistance very close to short (my short is 0.6-0.5 ohm this gives about 0.7ohm).
I found a small problem in your code. You don't save the velocity index at the beginning of the .gpr file. This creates an incompatibility with the .vi program.
Structure of the .gpr PC file: Identical to the storage format on the card file, binary, the first number (on 2 bytes, unsigned int16 format, big endian) contains the propagation velocity index, followed by the time samples (each sample on 2 bytes, unsigned int16 format, big endian).
You need to save the velocity index (can be 0 for air) at the beginning of the file to preserve the compatibility with the .vi program.
It is done by these lines in my code:
if (card)
{
//Verify file existance, if missing, create it and write velocity index
if (!file_existance) {
file = SD.open("Data.gpr", FILE_WRITE);
file.write(highByte(i));
file.write(lowByte(i));
file.close();
}
}
where i is the index, 0 for air.
I don't know where to buy antennas, I made them myself on PCB laminate. You should take care to have good electrical connection between the coaxial cable terminals and the aluminium foil. Aluminium is notoriously difficult to solder as is oxidizes instantly at high temperatures in air.
The short circuit in the ADP is normal because of its internal structure.
you are correct I did fix the code, and did check the connection between the cable and the anntenas but still the color is light not showing as your test.
Here is a test for about 13m on my flat room floor stepsize 0.083 and I did draw it using R and here is the results
https://myimgs.org/storage/images/30655/Screenshot2026-08-25225815.png
from look it seems that the GPR is working but I don't know why in the .gpr the amptiude is low, when multiply it with 8 it seems to be ok and show the white and blue, I did make sure everything is correct and no damage (last time I did damage my amplifier it was giving resistance between pin 1 and 3. I did test everything and the voltage it is working and the connection to the annetnas are working also, do you recommend something to do it ?
If you have a 30dB coaxial attenuator you can connect it on a 3m coaxial cable between the Tx and Rx and look at the signal in debugging mode on the debug python program to see how it looks. It should resemble a sine wave with a peak-to-peak amplitude of about 500.
Another small set of questions if you don't mind:
1- I am assuming that the first segment of the graph is acting as the blanking area, negative depth value to the 0.0 value which should be interpreted as the surface, is that correct?
2- If so, then am I also safe to assume that the following line of code is determining that depth:
</> C++
resolution = c / (2.0 * bandwidth); //depth resolution [m]
min_depth = -1.0 * float(cable_offset) * resolution; //offset cables + antennas
3- Is there any other portions that need blanking, like the air gap between the bottom of the antenna and ground? or since mine uses a 1m ribbon cable from the LF board to the RF board, should I also calculate for that?
Thank you for your help in this.
Yes, you are right. The negative depth values represent the cables and antennas plus the air gap between the antennas and the soil. The so called cable_offset accounts for all these (cable, antennas, air gap), so that 0 depth should correspond to soil surface. If you use longer / shorter or different velocity antenna cables or different antenna distance to soil you should modify the offset in this line:
const word cable_offset = 7; //offset cables + antennas in no. of resolution cells.
It represents the multiple of resolution cells, because the value in meters varies with the propagation velocity selected and is computed in the code section you indicated above, so only the number of resolution cells stays constant.
Only the antenna cables (coaxial cables between the RF board and the antennas) matter, the cables between the LF board and the RF board don't matter.
So in my converted code that uses a different LCD, the first level of the graph (between negative value and 0.0) I am seeing varying levels for the 0.0 line depending on the medium being scanned, etc. I thought that was a glitch in my reworked code, does yours draw the graph that way as well? I only have the one image of your LCD screen and was unable to confirm whether is remained at the same spacing or changed.
I've been chasing this "Glitch" since I started on this...
BTW, I really like the M_EXPONENT fix, the results look a lot more like what I imagined. I am able to see the disturbed layers of packed earth under my driveway now.
You mean that the 0 position moves on the vertical axis depending on your medium setting? If this is the case, it's OK, this is how it is supposed to work because resolution changes with medium.
The min_depth, the value on the top of the graph (the negative value in meters) changes when changing the medium setting, because the resolution changes with the wave velocity "c" in that medium but the number of resolution cells stays the same, so that the min_depth gets computed by:
resolution = c / (2.0 * bandwidth); //depth resolution [m]
min_depth = -1.0 * float(cable_offset) * resolution; //offset cables + antennas
Also the number of resolution cells in, let's say, 1 m changes when changing the medium because the resolution changes, that's why the vertical axis is changed to adapt to the medium settings.
@Mirel Paun If you want me to send you my PCBs I'd be happy to give you a set. (however, I only have one extra antenna pcb right now.)
Send me a private message with your address and I will get them in the mail.
@Mirel Paun , I actually just realized that you might not be able to PM me here. Just let me know and I will find another way.
Really good to see more action here on this project, it IS very worthwhile. I have a few questions that I haven't really seen answered yet.
1 - How far off the ground should the bottom of each antenna be?
2 - What is the best distance between pings? Mine is currently set to ping every 6cm (2.36"), should it be farther apart or closer together?
3 - Is the white area indicating an object or the dark area?
4 - Should I expect the image to be returned when the object is closer to the send antenna or the return antenna and which antenna should lead and which should follow?
Hello! I'll try to answer the questions above:
1 - The antennas in the case of GPRs should be placed as close as possible to the ground in order to improve the RF energy coupling with the ground, so a couple of cm above the ground is recommended;
2 - The closer the pings, the better. 5.5 cm is reasonable;
3 - It depends on the object properties. Dielectric vs. conductive objects produce different effects, so the object can be either dark or white in the image;
4 - It doesn't matter which antenna leads / follows, should work the same.
Great info, thank you for the quick response!
To follow up,
1 - I remember reading some feedback about the blanking area for the near field, is that related to the antenna distance from the ground?
2 - If the pings are at 6cm (I corrected the above) should this line of code be changed to match, from 0.12 to 0.06:
const double GPR_horizontal_step = 0.12; //GPR horizontal step [m]
3 - That explains a lot, I had been assuming that all reflective objects were white in the screen and all voids were black. This should probably be documented somewhere... I guess now it is ;)
4 - The antennas are 1m apart, at what point between them would the object be when the it's seen on the screen? A lot can be in between the antennas and knowing what part of the ground I'm seeing could be helpful. I am slowly creating a buried object course to figure this out, but it's hot here in Texas right now.
Bonus question: As for shielding and directing the antenna ping, could you add a quick image reference to show what you mean by behind each antenna?
Would it be beneficial to enclose each antenna in a 5 sided shield with only the bottom open?
1- There is a correlation between the blanking area and the antenna distance from the ground, so I think the best distance must be determined experimentally.
2 - Yes, line 32 should be: const double GPR_horizontal_step = 0.06; //GPR horizontal step [m]
and line 47: const word distances[] = {3, 6, 12, 24};
3 - More exactly: Objects in Ground Penetrating Radar (GPR) images are neither strictly white nor strictly black; instead, they appear as a combination of both white and black bands. When a radar wave hits a buried object, the signal alternates between peaks and troughs, creating a bipolar reflection that shows up as alternating white and black streaks on a radargram. The ordering of those colors depends on the type of material you scan.
Positive Reflection (White-Black-White): This happens when the radar wave travels into an object with a higher dielectric permittivity (meaning the radar wave slows down). Metal objects (like rebar or steel pipes) or water-filled voids typically show a strong positive reflection where the leading edge of the pattern is bright white.
Negative Reflection (Black-White-Black): This happens when the radar wave enters an object with a lower dielectric permittivity (meaning the radar wave speeds up). Air-filled PVC pipes, empty conduits, or dry geological voids usually display a negative reflection, where the leading edge of the pattern is black.
Or at least this is the theory.
4. Depending on the reflectivity of the object, it can be visible even when the GPR is near its vertical position, so that it shows up as a wider hyperbola on the image. The most visible indication of the object in the image should be when the object is exactly in the middle between the antennas.
5. The shield should be a metal sheet / plate 45x45 cm at 15 cm behind each antenna, so each antenna has its own shield. The shielded antenna will look like a T, the vertical portion being the antenna and the horizontal one being the shield.
It’s an interesting project congratulations @Mirel Paun . I was just wondering: almost all GPR devices use hyperbola-shaped reflections to identify objects, whereas your system seems to detect changes in another method. If you could display the results as hyperbolas, I think the objects would be easier to identify and trace.
I improved the code by using interpolation for displaying the image. Now it shows hyperbolas. It was a problem of resolution.
thanx, which one do you update labview one, debug python one or the arduino gpr wheel one.
what about the installer in https://drive.google.com/file/d/1fTImNGTH--9QTrTLh3JD8akViHZg7n2P/view?usp=sharing
It installs the last version of the PC program, it's made from the source code (.vi) that I placed here.
@Mirel Paun Good day, I did test on my room floor (concrete under it there is another room which is the ground floor final one there is no payment) I got this, the blue marks are for the areas that the GPRINO was not moving since I am using no wheel mode. I did use python debug and use the extrcated txt in the R RGPR library. https://myimgs.org/storage/images/26249/rada_image.png
Try the last programs (Arduino code and PC).
Also, in order to improve the directivity of the antennas and also provide some shielding to ambiental interferences you can place a conductive plate 45x45 cm at 15 cm behind the antennas, at 90 degrees (perpendicular).
In this test I did already put the antennas each one in card box and cover it expect the bottom with aluminum foil (top from antennas around 12cm). I tried to use your debug python to start to behave unnormal after the first window finished, so I did one using AI (did take your last codes for arduino and python and explain the issue then I extrcated those in the link). here are the links for both. kindly lead me I guess I am kind of lost here,
https://limewire.com/d/QnwDd#qDqKwukhFA
Even for R with the orgianl debug python and arduino code you can't run this
library(RGPR)
x <- readGPR(dsn = "D:/test.txt")
x1 <- gain(x, type ="exp", alpha = 0.01347, t0 = 0, te = 110)
plot(x1, col = palGPR("grey2"))
it will throw errors such as
p1 <- RGPR::gain(p, type ="exp", alpha = 0.01347, t0 = 2, te = 110)
Error in if (caller %in% c("convertTimeToDepth")) { :
the condition has length > 1
The problem is in the python code, more exactly the very slow update speed of the image which makes the program lose data. The arduino codes are OK.
I corrected the python code by using a different plotting approach so that it updates only the image and not also the axis. Now it works OK, also with RGPR. Try it, it's in the GitHub repository, GPR.py.
I did test with wheel after you made the last edits on the GPR.py and I did draw the extracted file with RGPR and I got the image
https://myimgs.org/storage/images/26738/Screenshot2026-08-08162907.png
The test: I did scan my room floor. There is another floor under me, there is an attic, I guess it is about 2m, and it is right after my room's concrete floor. There is a bathroom under it then the floor of the floor under me, in this floor, after about 7 meters in my scan, where I got some of the white area. Can you help me to evalute this image and to determine if I have any issues in my GPRino.
Here are some images of my menus and graph. I am using a different screen than yours which dictated some coding changes. The last picture is from a quick sweep inside my house which has a concrete slab for the foundation. I do not know whats under there, so I cannot confirm whether or not the data is good.
https://myimgs.org/storage/images/22424/IMG_1635.jpeg
https://myimgs.org/storage/images/22443/Menu-2.jpeg
https://myimgs.org/storage/images/22444/Menu-3.jpeg
https://myimgs.org/storage/images/22445/Graph Blank.jpeg
https://myimgs.org/storage/images/22446/Graph full.jpeg
Yes, it would be useful to test it in a known, controlled scenario, like on top of a tunnel or over a pipe to see how the displayed image correlates to the underground.
https://myimgs.org/storage/images/22271/GPR_LF_Stackup-2.jpeg
https://myimgs.org/storage/images/22272/GPR_Set-02.jpeg
https://myimgs.org/storage/images/22273/GPR_RF_Inside-1.jpeg
https://myimgs.org/storage/images/22274/GPR_Antenna-1.jpeg
https://myimgs.org/storage/images/22275/GPR_LF_Connection-2.jpeg
https://myimgs.org/storage/images/22276/GPR_LF-RF_Connections.jpeg
Hello! Your boards look impressive. I would love to see some scan results. I'm very curious to see how the RF shielding improves scan quality. Did you use the Arduino code that compensates the VCO nonlinearity?
Thanks! I am still working out the antenna height and sample rate. I do believe the shielding has helped, but I don't have definitive evidence at this point.
As for the code, I had to do quite a bit of modifying to use a different LCD, mainly menu issues and graph layout. I believe I am using the latest code you've posted here for all the calculations. I will add a few more pictures to the above thread to show my screen after a sweep over concrete.
My weakness is coding, and I don't have a full grasp on everything you did, so i am reluctant to make too many changes. I would be very interested in supplying you with a set of boards in trade for some help working out the bugs. I have several extra LF & RF blank boards, but I currently only have one extra antenna. I can get more made, but the antenna's were the expensive part. I'll set you up with what I have for some help if you're interested. And I will try to keep all results posted here for others to enjoy as well.
Is this the section of code you are referring to?
//modulator signal ramp that compensates JTOS-850VW+ nonlinearity
const word modulator_sig[256] = {
I updated all the programs right now. The displayed image should now be improved by the interpolation I implemented.
https://myimgs.org/storage/images/21998/GPR SHIELD BLK.jpg
https://myimgs.org/storage/images/21999/GPR RF BLK.jpg
Become a member to follow this project and never miss any updates
About Us Contact Hackaday.io Give Feedback Terms of Use Privacy Policy Hackaday API Do not sell or share my personal information
Abid Jamal
CiferTech
Embedotronics
Jean Noel
library(RGPR)
x <- readGPR(dsn = "D:/test.txt")
#set velocity
vel(x) <- 0.12
#limit to first 500 depth samples
x1 <- x[1:500, ]
#dewow filter
x2 <- dewow(x1, type = "Gaussian", w = 20)
#depth attenuation compensation
x3 <- gain(x2, type ="exp", alpha = 0.01347, t0 = 0, te = 110)
#filter clutter
data_matrix <- values(x3)
mean_profile <- rowMeans(data_matrix)
clean_matrix <- data_matrix - mean_profile
x_clean_alt <- x3
values(x_clean_alt) <- clean_matrix
#plot
plot(x_clean_alt, col = palGPR("grey2"))
This doesn't work with the new stacked code. I'm not sure I understand it enough to make the necessary changes, any help here would be appreciated.