Introduction: Arduino Cockpit Sensors Demo

In this Instructable I will show you how we normally write our Arduino Sketches and combine our sensors with a Windows application to produce a working demonstration of a cockpit computer. We use a single Arduino Uno, and four sensors sending five sensor readings to produce the telemetry necessary to fly an aircraft.

This Instructable is the beginning of a series which will bring us to the point of having a fully operational flight computer suitable for drones and RC models. Written by you to behave the way you want them to.

The quickest way to see what this is all about is to watch the video then proceed through this Instructable. At the end you will be able to download all the source code necessary.

On to the Hardware...

Step 1: The Hardware

The Four Sensors are the Ultrasonic Sensor which we use for a psuedo-collision detector, a photoresistor and two analog joysticks. The Photoresistor allows the system to automatically turn on and off lights as required. The two joysticks provide data on pitch, direction, and throttle.

I will not provide a wiring diagram for these devices as they are fairly straightforward and plenty of diagrams are already on the internet for these sensors.

Once you have got them wired up we can move on to the code which is the main part of this Instructable.

On to the code...

Step 2: The Arduino Code

void loop() {
// put your main code here, to run repeatedly:

DetectCollision();

DetectLight();

DetectDirection();

DetectPitch();

DetectThrottle();

}

Our main loop is a little different from the normal small code samples that you see. This time instead of us actually processing the sensor data we are just calling a series of functions. Each of these functions deal with a particular type of sensor data.

void DetectCollision()
{

unsigned int uS = sonar.ping();

Serial.println(String("CD") + String(uS / US_ROUNDTRIP_CM) + String("Z")); }

For instance the DetectCollision() function purely looks at the collision detection data. We send out the ping convert it to cm from microseconds and in-fix it between the strings "CD" and "Z". The CD is the command that is being sent and the Z indicates to the receiving application that the command has completed.

This allows us to verify that we have received a valid and complete command. I won't show the rest of the functions as they are pretty much the same.

Step 3: The Windows C# Code

I will only explain two functions within the code as there is some repetition and the ArduinoNet library was explained in my previous Instructable called which you can find here.

The main function within this application is where we extract the command and data from the string sent to us from the Arduino.

private double _currentPitch = 0;
private int _currentAirSpeed = 0;

private void _serial_ArduinoDataRecievedEvent(string dataRecievedMessage) { if (dataRecievedMessage.Length < 3) return; if (string.IsNullOrEmpty(dataRecievedMessage)) { Log("Empty Message Received"); return; // Ignore empty commands } if (dataRecievedMessage.Contains("Z")) { var zTerminatorPosition = dataRecievedMessage.LastIndexOf('Z'); dataRecievedMessage = dataRecievedMessage.Replace("\r", ""); dataRecievedMessage = dataRecievedMessage.Substring(0, zTerminatorPosition); } else { Log("Corrupt Message received"); return; // No Terminator found - corrupt message } try {

// Get the command - first two letters in our protocol

var command = dataRecievedMessage.ToCharArray()[0].ToString() + dataRecievedMessage.ToCharArray()[1].ToString(); var finalCommand = command.ToString().ToLowerInvariant(); // May not be needed now Log("Arduino Data: " + dataRecievedMessage);

switch (finalCommand) { // Collision Detection case "cd": // Pull UP! if low and flying // Terrain - Pull Up! if high break; // Detect Internal Lighting Conditions case "dl": var lightValue = Convert.ToInt16(dataRecievedMessage.Replace(command.ToString(), "")); // Low Light Darken form background BackColor = lightValue > 500 ? Color.Black : DefaultBackColor; SetRefresh(); break; // Detect Direction case "dd": SetLabel(lblHeading, dataRecievedMessage.Replace(command.ToString(), "")); // Set Left Right // Set pitch // Set Air Speed // Set Direction // Set Altimeter break; // Detect Pitch case "dp": // Set pitch SetLabel(lblAttitude, (Convert.ToDouble(dataRecievedMessage.Replace(command.ToString(), "")) - _pitchModifier).ToString(CultureInfo.CurrentCulture) ); _currentPitch = Convert.ToDouble(dataRecievedMessage.Replace(command.ToString(), "")); SetPitch(dataRecievedMessage.Replace(command.ToString(), "")); // Set Air Speed // Set Altimeter // Set Vertical Speed break; // Detect Throttle case "dt": SetLabel(lblAirSpeed, (Convert.ToInt16(dataRecievedMessage.Replace(command.ToString(), "")) - _airSpeedModifier).ToString()); _currentAirSpeed = Convert.ToInt16(dataRecievedMessage.Replace(command.ToString(), "")); SetAirSpeed(dataRecievedMessage.Replace(command.ToString(), "")); break; default: Log("Unknown Message " + dataRecievedMessage); break; } } catch (Exception ex) { Log("Error processing command: " + ex.Message + "\t" + dataRecievedMessage); } }

As you can see this is quite a large function. We would normally split it down into small sections but that is not necessary at this point.

We use a switch statement to see which command (the first two letter of the string sent to us by the Arduino) that we have received. We then extract the value and process it.

In case "dd" where we process the direction you will see that a number of remarks are present. These indicate parts of the logic that are missing. This Instructable is not about providing you a fully finished Flight System Computer, but to show you how to build your own fully functional FSC. With that in mind, the remarks show that one control often, can, affect many others. If we pitch the plane upwards the Air Speed will drop, the Vertical Speed will increase, Our Altitude will increase and our Attitude control will also change. So you need to have the sensors to detect the changes otherwise you may end up stalling without realising why.

We will look at the pitch modifier method next.

private double _pitchModifier = 0;
private void SetPitch(string value) { if (airSpeed.InvokeRequired) { airSpeed.Invoke(new ControlStringConsumer(SetPitch), new object[] { value }); // invoking itself } else { try { attitude.SetAttitudeIndicatorParameters((Convert.ToDouble(value)-_pitchModifier), 0.00f); } catch (Exception ex) { Log("Set Pitch: " + ex.Message); } } }

Even with out valid command check some errors still creep in - the try, catch section will weed those out. Because we are running a multi-threaded application it is very unwise to set the value of a control that is not in the same thread as you are. So the GUI thread needs to be invoked when setting the aviation controls this is done throught the InvokeRequired check. If it is not required we go directly to the control and set its value, otherwise we Invoke the control on the GUI thread and set its value that way.

Do you see the mistake in the code?

On to the mistake...

Step 4: The Deliberate Mistake...

Did you spot it?

Because we do a lot of writing code that is similar we often copy and paste code from one location to another. However, in doing this it is really important that you read through the pasted code to make sure you have changed everything you need to.

I left a mistake in that I made where in one part of the DetectPitch code I am setting the AirSpeed and later I change it to the Altitude. So anyone and everyone can make this mistake and often do. So try and be aware of it and you won't get caught out flying your plane into the side of a mountain. Because instead of warning you to "Pull Up" the computer put the lights on.

Well that's it for my second Instructable. Crack open the coders, pull out the sensors and Arduino and build something wonderful.

Source Code: https://github.com/7ASecond/ArduinoNet