From the Depths Guide

Breadboard tutorial by example: programming an airplane for From The Depths

Breadboard tutorial by example: programming an airplane

Overview

This tutorial teaches how to make an airplane fly using a breadboard. The tutorial is intended as an introduction to breadboard design.

Introduction

This tutorial will introduce the (AI) breadboard block and explain how to use it by showing how to set up the AI for an airplane. The tutorial goes into detail to describe the operation of the airplane and how to program it. There should be enough information here to get you started on breadboards and even to allow you to explore the components that are not covered in this tutorial.

The airplane

This tutorial’s airplane is a simple thing, with both up/down and left/right mirror symmetry when viewed from the front. This makes it very stable. It is powered by a single Huge Jet engine and controlled using Universal Flight Surfaces. The airplane is unarmed.


Before the breadboard can be looked at, it is necessary to first set up the Universal Flight Surfaces. These are used as tailplanes and ailerons to control the airplane’s pitch, roll and yaw angles. The control surfaces used for pitching are all positioned at the back of the plane and can all be set to Pitch Up. The control surfaces for rolling are on different sides of the plane and need to be set to Roll Left on one wing and to Roll Right on the other. The same is true for the yaw controls, which are on the left- and right-hand sides of the tail and need to be set to Yaw Left and Yaw Right.


When you are setting up your own airplane, do not worry about what is left and what is right, or what is up and what is down, as this is easy to correct in the breadboard by flipping + and – signs. Just make sure that control surfaces on the opposite sides of the airplane are set up differently. This is important for pitch control as well if you have control surfaces for pitching in the front and the back of the aircraft.

The tools and the plan

Now that the airplane is built and set up correctly, it is time to connect an AI breadboard to the AI mainframe. The normal breadboard, which is in the Control tab and has fewer capabilities, will not be used.


Before we do any programming, let us look at the way the breadboard UI is built up. On the left, there is a panel in which components can be placed. This can be navigated by zooming out and in with the scroll wheel, while keeping the cursor on something that we want to see. On the right, there is the component selection panel, which is divided into inputs in the upper half and processing components and outputs in the lower half. There is also a grid with a size setting. The grid is convenient because components snap to it.


With the tools in hand, it is time to begin programming the AI. For this, as for all breadboard projects, a plan is needed. The plan for this airplane is simple. First, the parts that do not need to change depending on the situation the plane is in will be made. Then, an idle behaviour in which the plane flies around in circles at a fixed altitude if there are no enemies will be made. Finally, the plane will be programmed to circle an enemy between 700 and 800 m distance at an altitude of 100 m above the enemy if an enemy is present.

Simple beginnings

Note: the breadboard is already fully built. I found it too difficult to make it on the fly without making any mistakes or unreadable connections.

The plane needs to move forward at all times, otherwise it will fall out of the sky. For this, the forward propulsion must be active. For simplicity, it will simply be set to its maximum output, which is 1. All propulsion components take values between -1 and +1 as input. They do nothing if they receive 0.

Only two components are needed to fix the forward thrust to the maximum value, namely a Constant and a Propulsion output. To keep track of what is going on, a Printer will also be added. The Constant is placed on the panel by a left click and set to 1 using the slider. Then, the Propulsion output is placed and set to Forward/Back using the dropdown menu. Next, the two components are linked by a left click on the Constant followed by a right click on the Propulsion output. Finally, a Printer is placed above the two components stating, ‘ALWAYS GO FORWARD’, to remind us what this section does.


Next, a major decision about the control scheme is taken. Our plane should steer using its yaw controls and therefore it should not roll. As such, a roll angle of 0° is desired. This will be enforced by a PID, which is a stabilising device that takes a setpoint (in this case the 0° angle) and the variable it is trying to control as inputs. The variable is called the process variable, which in this case is the roll angle. Its output is a value between -1 and 1 that can be passed to a Propulsion output, just like the constant 1 that was passed to Forward/Back.

To put the system together, an Orientation Input set to Roll must be connected to the upper input (process variable) of the PID by a right click on the rectangle that sticks out there. A Constant 0 must be connected to the setpoint input of the PID, which is the other rectangle on the left-hand side. The output of the PID must be led through a Maths Evaluator into the Propulsion output, which is set to Roll Left/Right. The Maths Evaluator must contain a to reproduce the signal in its first (and only) input and send it to the output, or -a to invert the signal if the plane starts to roll upside down, which is not the intention.


It is always a good idea to add a Maths Evaluator just before a Propulsion output, so you can invert the signal or check if certain conditions are met before the vehicle starts moving.

Idle behaviour

To allow the plane to circle when there is no enemy and to go towards the target when there is one, the AI must be able to identify when there is a target. In a breadboard, this is done via the Primary Target Info component, which outputs target presence, altitude, distance and relative bearing. The Target Presence is either 0 (not present) or 1 (present).

To make the plane fly around in circles in the absence of an enemy, its Yaw Left/Right must be set to a constant value in a Propulsion output when Target Presence is 0. This can be done in one or two Maths Evaluators, which take Target Presence as input, invert it as (1 – a) and then multiply it by the constant value that the yaw must be set to. In this case, that is 0.1. Thus, the Maths Evaluators read (1 – a) and a * 0.1. It is possible to do this in one Maths Evaluator as (1 – a) * 0.1.


Besides the direction that it is moving in, the plane also has to worry about not falling out of the sky. To allow the plane to stay airborne, its altitude must be controlled. This is tricky, as planes cannot directly control their up- and downward motion via thrusters or rotors and therefore cannot use a Propulsion output set to Up/Down. Instead, planes use Pitch Up/Down to control their altitude, which is a little more involved.

The plan is to keep the airplane at roughly 200 m above sea level by pitching its nose up at +30° when it is below 190 m and pitching its nose down at -30° when it is above 210 m.


The Altitude input must be used to determine the altitude of the plane. This input must be connected to two Maths Evaluators that read (a < 190) and (a > 210). These transmit an output of 1 if the condition is met and 0 otherwise. Therefore, between 190 m and 210 m, both outputs are 0.

An output of 0 or 1 is not enough on its own. This output must be multiplied by either -30 or +30 in two new Maths Evaluators. The new output values are then added in a Sum component (which is handy when you don’t want to type (a + b + c + d + e)) and the Sum’s output is connected to the setpoint of a PID. This PID’s setpoint is always one of -30, 0, +30. Note that the + and – signs are flipped in the breadboard. This is normal. Pitch controls always require some fiddling with signs.

The PID must also be connected to an Orientation Input that provides the pitch angle as the process variable. Then, the same design used for roll control can be copied, with a Maths Evaluator connected to a Propulsion output for Pitch Up/Down. This time, the Maths Evaluator reads –a *(1 – b), because it is not just inverting the signal, but it is also checking that no enemy is present. A Primary Target Info component transmits Target Presence to second input (the b input) of this Maths Evaluator.

Combat behaviour

While the airplane has no weapons, it is possible to make it act as if it were some kind of bomber that drops guided bombs while circling the enemy at an altitude of 100 m above said enemy. Although there are no bombs on the plane, circling the enemy at that altitude is entirely possible.

Just as previously, the altitude must be controlled via the pitch. This is done in exactly the same way as before and therefore will not be covered in much detail. However, the altitude setpoint now depends on the altitude of the enemy, which requires a bit more math.

The desired altitude is 100 m above the enemy under most circumstances, but this will not work if the target can fly higher than the plane or if the target is a deep-water submarine. To prevent the plane from going into space or diving into the ocean, some additional restrictions must be added. Therefore, the desired altitude is given by:

(100 + a) * (a < 300) * (a > -20) + 300*(a >= 300) + 80*(a <= -20)

In this expression, a is the target altitude. The first term is not zero when the target is between -20 and 300 m in altitude and gives an altitude between 80 and 400 m as the setpoint. If the target is any higher than 300 m above sea level, the second term sets the desired altitude to 300 m. Finally, if the target is below 20 m depth, the desired altitude is set to 80 m by the third term. Note that this expression does not have to be put in a single Maths Evaluator. It could also be created using two or three Maths Evaluators and a Sum.


Besides the variable desired altitude, there are no major differences in the altitude control when compared to the idle behaviour. Because the plane’s own altitude must now be compared to the desired altitude, the Maths Evaluators that connect to the PID’s setpoint read b < (a – 10) and b > (a + 10) instead of a < 190 and a > 210. At the end, the presence of a target is verified in a Maths Evaluator that reads -a * b, where b is Target Presence from a Primary Target Info component.


Besides the altitude, the bearing must also be controlled. To circle the target, the desired angle is 90°, but circling the target at any range is not a good idea. The plane might end up circling the target at 5000 m or 100 m if the range is not controlled, which would be too far or too close for many weapons. For the purposes of this tutorial, the desired range is between 700 m and 800 m. The plane must close the distance until it is between 700 m and 800 m from the target, then maintain a 90° angle. If it gets too close to the target, the plane must fly away.


The first step in putting this together is to determine the range using three Maths Evaluators that take the distance to the target from a Primary Target Info component as input a. The first Maths Evaluator is set to (a <= 700) and is tied to the retreating behaviour. The second one is set to (a < 800)*(a > 700), which is the in-breadboard way of writing (700 < a < 800). This one is tied to the circling behaviour. The third one is set to (a >= 800) and is tied to the chasing behaviour.


The chasing and retreating behaviours are simple. There are two PIDs, one with a 0° setpoint for chasing the target and another with a 170° setpoint for running away. The process variable of both PIDs is the bearing to the target from a Primary Target Info component. The output of each PID is multiplied in a Maths Evaluator by Target Presence from the same Primary Target Info component and by one of the range conditions from the previous paragraph. If both these values are 1, True, then the PID’s signal is passed to a Propulsion output. This output is set to Yaw Left/Right and is ultimately responsible for steering the plane towards or away from the target.

Note that the setpoint for running away is 170°. It may seem logical to choose 180° to run directly away from the target, but this is a difficult bearing to maintain for a PID, as there is a discontinuity in the bearing beyond 180°. If the plane falls short of the 180° setpoint, the bearing to the target may be 179°, which is fine. However, if it overshoots, then the bearing does not become 181°; it becomes -179°, the lowest possible value. As such, the PID’s process variable can fluctuate tremendously with a 180° setpoint, resulting in an unstable yaw angle. Therefore, it is better to choose an angle such as 170° or -170°.


Finally, there is the circling behaviour. It may seem obvious to do this exactly like the retreating and chasing behaviours and simply use a PID with a 90° setpoint. However, unless you have an asymmetrically armed and armoured vehicle, this is not a good idea. Simply setting a 90° angle as the desired bearing will result in the vehicle always showing the same side to the enemy, even if it must turn more than 180° to do so.

Because the plane should turn no more than is necessary to begin circling the enemy, it must distinguish between negative and positive bearing angles. If the bearing is less than 0°, then the setpoint should be -90°. If the bearing is more than 0°, then the setpoint should be +90°. This can be done in a similar manner to choosing a pitch angle of +30° or -30° based on altitude.

The bearing is determined using two Maths Evaluators that are connected to a bearing input. They read a >= 0 and a < 0. These two expressions are 1 for a target at a positive bearing and a negative bearing, respectively, and 0 otherwise. The output values are multiplied by the 90° and -90° angles. The results from both Maths Evaluators are transferred to a PID’s setpoint input via a Sum. The PID’s process variable is the bearing from a Primary Target Info component. The PID’s output is multiplied by Target Presence from a different Primary Target Info component and by the range condition (a < 800)*(a > 700) in a Maths Evaluator that reads a * b * c. The final value is passed to a Propulsion output set to Yaw Left/Right.


At this point, the airplane is fully controlled.

Conclusion

The breadboard shown in this tutorial works well to fly an airplane, which is one of the more difficult types of vehicles to get working with a breadboard. If you’ve made it this far, you will be well-equipped to program AI for ships and tanks, which don’t need to worry about altitude, for helicopters and hovercraft, which are equipped with very handy Up/Down thrust, and for submarines, airships and airplanes.

However, there is a lot more to breadboards than what is shown in this tutorial. For example, it is possible to use the Flagship Info component to make planes land on aircraft carriers or to make small boats dock with ships. Another example is the use of the Maths Evaluator’s sine function Sin(), which can be coupled to a Timer to create oscillating signals, which can be passed to the forward Propulsion output to vary the vehicle’s speed, making for decent passive evasion without sacrificing control. These are but two of the possibilities offered by breadboards; there are many more. If you take the time to study breadboards, you will find yourself able to build more complex and effective vehicles.

SteamSolo.com