Introduction: URadar
In this instructable we'll show you how to build a radar using an Arduino Leonardo compatible board. Have a look to the video and then to the tutorial .... Please download the full source code and play with it!!
Step 1: First at All Get the Parts
This instructable was part of a course from the University of Malaga called "Creative Electronic". Following these instructions you can build your own arduino based radar with very cheap parts, available everywhere, Let's do it!
Ingredients:
- Arduino Leonardo compatible board. (We've used this one)
- HC-SR04 Ultrasonic Sensor
- SG90 Servo
- Some hookup wires
- A protoboard to glue everything
- ... and a small box to put everything together, just to hide your new invent!
Step 2: Cook the Components on a Low Heat
Fritz schematic and some pictures about the electronic parts assembly
Step 3: Arduino Source Code Step by Step
First at all the setup part, where we're going to setup the digital ports, the Serial port and the Servo,
void setup() {
pinMode(trig, OUTPUT); // ultrasonic output trigger pinMode(echo, INPUT); // ultrasonic echo Serial.begin(9600); // Serial port motor.attach(13); // Servo asociated to pin 13 }
Then the loop part. There are two steps, first the servo rotate clockwise and then anticlockwise,
ClockWise rotation,
// Turn the servo 0 to 180 degrees
for(int i=0;i<=180;i++){ motor.write(i); // positioning servo delay(50); // some delay to let the servo mechanicaly stop dis = CalcularDistancia(); sprintf(temp, "%d/%d\n", i, dis); // Print degrees/distance\n Serial.print(temp); }
The iteration begins by placing the servo to the required degress. An small delay is introduced to avoid mechanical issues and to let the servo stop. Then an echo is sent by the ultrasonic sensor and the distance is calculated knowing the propagation speed of sound trought the air (340m/sec) and the time the sound takes to go and to go back.
int CalcularDistancia(){
digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); // Emit a pulse delayMicroseconds(10); digitalWrite(trig, LOW); resp = pulseIn(echo, HIGH); // Returns time in microseconds dis = resp * 0.034 / 2; // Set for calculate distance from resp variable return dis; }
Note we have to divide by 2 because we have the time the sound took to propagate and to get back.
... And then the second step, where the servo rotate anticlockwise following the same steps,
// Turn the servo 180 to 0 degrees
for(int i=180;i>0;i--){ motor.write(i); delay(50); dis = CalcularDistancia(); sprintf(temp, "%d/%d\n", i, dis); Serial.print(temp); }
Thats it!
Step 4: C# Source Code Step by Step
When the app first load, we define the origin, the bitmap, the structure of data, and the most important thing, we let the app discover the COM port for us,
private void Form1_Load(object sender, EventArgs e)
{ // Define origin and bitmap origin = new Point(size / 2 + margin, size / 2 + margin); bitmap = new Bitmap(size + margin + 50, size + margin + 50); lineas = new List ();// Initialize the full structure for (int i = 0; i <= 180; i++) { lineas.Add(new Linea() { alpha = 0, angle = i, color = Color.GreenYellow, distancia = 255 }); }
// Configure serial port to receive information from Arudino // Locate the first COM port ocurrence with Arudino name using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE Caption like '%(COM%'")) { var portnames = SerialPort.GetPortNames(); var ports = searcher?.Get().Cast().ToList().Select(p => p["Caption"].ToString()); var portList = portnames.Where(n => ports.FirstOrDefault(s => s.Contains(n)).Contains("Arduino"))?.FirstOrDefault(); if (portList != null) { serialPort1.PortName = portList; serialPort1.BaudRate = 9600; serialPort1.Parity = Parity.None; serialPort1.StopBits = StopBits.One; serialPort1.Handshake = Handshake.None; serialPort1.ReadTimeout = 1000; serialPort1.NewLine = "\n"; serialPort1.RtsEnable = true; serialPort1.ErrorReceived += serialPort1_ErrorReceived; serialPort1.DataReceived += serialPort1_DataReceived; serialPort1.Open(); } } }
We have some methods that allow us to draw text, lines and arcs.
Helper method to draw a text given an angle and a length,
private void drawTextAngle(Graphics g, Point origin, float angle, float length, String text = null) { Point point = new Point((int)(origin.X + Math.Cos(angle * Math.PI / 180) * length), (int)(origin.Y - Math.Sin(angle * Math.PI / 180) * length)); if (angle > 90) point.X -= 80; g.DrawString((text==null)?angle + "º":text, new Font("Tahoma", 20), Brushes.White, point.X, point.Y); }
Helper method to draw a line given an angle and a length,
private void drawLineAngle(Graphics g, System.Drawing.Pen pen, Point origin, double angle, float length) { Point p = new Point(origin.X, origin.Y); Point point2 = new Point((int)(p.X + Math.Cos(angle * Math.PI / 180) * length), (int)(p.Y - Math.Sin(angle * Math.PI / 180) * length)); g.DrawLine(pen, p, point2); }
Helper method to draw an arc given an origin and a size,
private void drawArcSize(Graphics g, System.Drawing.Pen pen, Point origin, float size) { float px = origin.X - (size / 2); float py = origin.Y - (size / 2); g.DrawArc(pen, px, py, size, size, -180, 180); }
We have also a method to define the scaffoldingon the graph,
private void drawBase(Graphics g) { // Draw the arcs drawArcSize(g, pen1, origin, size); drawArcSize(g, pen1, origin, size * 0.75f); drawArcSize(g, pen1, origin, size * 0.50f); drawArcSize(g, pen1, origin, size * 0.25f);
// Draw the scale lines drawLineAngle(g, pen1, origin, 0, 1.05f * (size/2)); drawLineAngle(g, pen1, origin, 30, 1.05f * (size / 2)); drawLineAngle(g, pen1, origin, 60, 1.05f * (size / 2)); drawLineAngle(g, pen1, origin, 90, 1.05f * (size / 2)); drawLineAngle(g, pen1, origin, 120, 1.05f * (size / 2)); drawLineAngle(g, pen1, origin, 150, 1.05f * (size / 2)); drawLineAngle(g, pen1, origin, 180, 1.05f * (size / 2));
// Draw the text with the information drawTextAngle(g, origin, 30, 1.05f * (size / 2)); drawTextAngle(g, origin, 60, 1.05f * (size / 2)); drawTextAngle(g, origin, 90, 1.05f * (size / 2)); drawTextAngle(g, origin, 120, 1.05f * (size / 2)); drawTextAngle(g, origin, 150, 1.05f * (size / 2)); drawTextAngle(g, origin, -1, 0.75f * (size / 2), "90cm"); drawTextAngle(g, origin, -1, 0.50f * (size / 2), "60cm"); drawTextAngle(g, origin, -1, 0.25f * (size / 2), "30cm"); }
The following method is where the magic happends, whenever a new set of data arrived the listener is triggered and we can process it. Every incoming data is composed by two parameters, an angle and a distance.
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{ string valores = serialPort1.ReadExisting(); string[] parejasDatos = valores.Split('\n'); foreach (var dato in parejasDatos ) { string[] angulo_distancia = dato.Split('/'); if (angulo_distancia.Count() == 2) { int angulo = 0; int distancia = 0;int.TryParse(angulo_distancia[0], out angulo); int.TryParse(angulo_distancia[1], out distancia);
this.Invoke(new Action(() => { procesarNuevodato(angulo, distancia); } )); } } }
... Then this couple of parameters are processed in the following method,
// Method to update the information of the graph
private void procesarNuevodato(int angle, int distancia) { Graphics g = Graphics.FromImage(bitmap); g.Clear(Color.Black);foreach (var linea in lineas) { if (linea.angle == angle) { linea.alpha = 255; // Draw the current line full bright linea.distancia = distancia > 120 ? 120 : distancia; if (distancia < 120) // Change color depending of the distance linea.color = Color.Red; else linea.color = Color.GreenYellow; }
// Decrement the bright of the rest of the lines linea.alpha -= 3; if (linea.alpha < 0) { linea.alpha = 0; } else { Pen penlinea = new Pen(Color.FromArgb(linea.alpha, linea.color.R, linea.color.G, linea.color.B), 5F); drawLineAngle(g, penlinea, origin, linea.angle, linea.distancia * 1.0f * (size / 2) / 120 ); penlinea.Dispose(); } } drawBase(g); g.Dispose(); pictureBox1.Image = bitmap; }
Briefly the whole structure is updated for every single data received. The incoming data angle is presented with a full bright. The color is binded to the measured distance, a threshold of 120 is established. The graph shows Green/Red lines based on the distance received.
Step 5: Full Source Code Download
You can download the full source code here.