Auto hovering

Hi, I am a final year student doing a project which require me to build a quad copter which is able to perform the function of auto leveling. I have manged to write a code that allow me to power up my quad copter using arduino uno which is connected to a reciver and naza flight controller. However, i have a problem with writing a code for the auto hovering or altitude hold which uses a ultrasonic sensor.

I require some assistance in bulding a code for the auto hovering function which require me to be able to hover at a specific height of 30cm. Am i right in saying that the sensor have to take a few sample of the height and compare the height to a reference hight?

Thanks for the help

A specific height of 30cm above sea-level or 30cm above local ground-level (whichever is higher)?

AWOL:
A specific height of 30cm above sea-level or 30cm above local ground-level (whichever is higher)?

It will be 30cm above local ground level.

Panda01:
Am i right in saying that the sensor have to take a few sample of the height and compare the height to a reference hight?

Yes. If the hover is too high, reduce throttle. If too low, increase throttle. In such a noisy environment it is a good idea to average the sensor readings.
You should probably tether the quadcopter at near the desired altitude while you do initial testing so a programming error can't ram it into anything or anyone.

johnwasser:
Yes. If the hover is too high, reduce throttle. If too low, increase throttle. In such a noisy environment it is a good idea to average the sensor readings.
You should probably tether the quadcopter at near the desired altitude while you do initial testing so a programming error can't ram it into anything or anyone.

Thank you for the advice

This is the code that I have done. Could I have some advice on how to write a code for the new current altitude to hold at a fixed height. Thanks

#include <Servo.h>
Servo esc1; //Create servo object for the 4 esc
Servo esc2;
Servo esc3;
Servo esc4;

int ch1 = 3;
int ch2 = 4;
int ch3 = 5;
int ch4 = 6;
int ch5 = 7;

int trigPin = 12;
int echoPin = 13;
long duration, duration2;
int distance, distance2;

int roll_channel = 8;
int pitch_channel = 9;
int throttle_channel = 10;
int yaw_channel = 11;

unsigned long alt_hold_switch;
unsigned long throttle_output;

void setup()
{
  Serial.begin(9600);

  pinMode(ch1, INPUT); //Attach pin to the recevier input
  pinMode(ch2, INPUT);
  pinMode(ch3, INPUT);
  pinMode(ch4, INPUT);
  pinMode(echoPin, INPUT);

  pinMode(trigPin, OUTPUT); //Attach pin to the HC-SR04 output
  pinMode(roll_channel,OUTPUT); //Attach pin to the motor controlling the roll
  esc1.attach(8); //Attach pin 8 to esc 1 to control the motor
  pinMode(pitch_channel, OUTPUT);
  esc2.attach(9);
  pinMode(throttle_channel, OUTPUT);
  esc3.attach(10);
  pinMode(yaw_channel, OUTPUT);
  esc4.attach(11);
}

void loop()
{
  digitalWrite(trigPin, LOW); //Program to measure the distance in cm
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration*0.034/2;
  delay(100);
  
  roll_channel = pulseIn(ch1, HIGH); //Program to start the motor and to control it
  esc1.writeMicroseconds(roll_channel);
  delay(100);
  pitch_channel = pulseIn(ch2, HIGH);
  esc2.writeMicroseconds(pitch_channel);
  delay(100);
  throttle_channel = pulseIn(ch3, HIGH);
  esc3.writeMicroseconds(throttle_channel);
  delay(100);
  yaw_channel = pulseIn(ch4, HIGH);
  esc4.writeMicroseconds(yaw_channel);
  delay(100);

  alt_hold_switch = pulseIn(ch5, HIGH); //Read the pulse from channel 5

  if (alt_hold_switch < 1800) // Pulse for switching the altitude hold function
  {
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    duration2 = pulseIn(echoPin, HIGH);
    distance2 = duration*0.034/2; //Gets the current altitude which will be compared to the reference altitude
  }

  Serial.print("Channel 1 (Roll): ");
  Serial.print(roll_channel);
  Serial.print("\t\tChannel 2 (Pitch): ");
  Serial.print(pitch_channel);
  Serial.print("\t\tChannel 3 (Throttle): ");
  Serial.print(throttle_channel);
  Serial.print("\t\tChannel 4 (Yaw): ");
  Serial.print(yaw_channel);
  Serial.print("\t\tDistance: ");
  Serial.println(distance);
}

One piece of advice is to set a timeout on the pulseIn() function. The default is 1,000,000 microseconds which will cause your control to be very unresponsive if it misses a pulse (like when the radio is out of range or the sonar doesn't get an echo). pulseIn() - Arduino Reference

Most flight controllers use Pin Change interrupts rather than the pulseIn() function to avoid waiting for pulses.

Since you don't really need to control anything but the throttle to adjust altitude you can hook the roll, pitch, and yaw channels straight to the flight controller.

void loop() {
  if the altitude hold switch is on {
    if the altitude is too high (or no echo is seen), reduce the throttle signal
    if the altitude is too low, increase the throttle signal
  } else {
    get the throttle signal from the radio and use that.
  }
}

Thanks for the help. I will go and try that first

This is the code to write for the altitude hold. Could I ask how do I write the the code to ask the motor to maintain the speed which is under the "if (distance2 > distance). Distance 2 is the new altitude while distance is the reference altitude

alt_hold_switch = pulseIn(ch5, HIGH); //Read the pulse from channel 5
  if (alt_hold_switch < 1800) // Pulse for switching the altitude hold function
  {
    while (alt_hold_switch < 1800);
    {
     duration2 = pulseIn(echoPin, HIGH);
     distance2 = duration*0.034/2; //Gets the current altitude which will be compared to the reference altitude
     delay(100);
     if (distance2 > distance)

delay(100);Nope.

What do you mean by nope?

AWOL:
delay(100);Nope.

I use "nope" as an emphatic "no"

So in that case I should not put the delay(100) in the code right

AWOL:
I use "nope" as an emphatic "no"

Yup.

I bet the writers of the arduino superset of C are regretting they ever wrote the delay function..

Allan

Thanks for the help

AWOL:
Yup.

You're welcome.
Reply #6 is well-worth reading again.

Panda01:

  while (alt_hold_switch < 1800);

{
    duration2 = pulseIn(echoPin, HIGH);
    distance2 = duration*0.034/2; //Gets the current altitude which will be compared to the reference altitude

  • Warning: You have to re-sample the alt_hold_switch pulse inside this loop or it will never exit.
  • Warning: The Echo pin only provides a pulse after you ping the Trigger pin.
  • Warning: The Echo pin does not provide a pulse if the echo is too early (2cm) or too late (out of range).
  • Warning: Since you did not specify a timeout the pulseIn() function will take a full second to return if no pulse is seen.
  • Warning: If you are too high when you switch on altitude hold and no echo is seen you will calculate a height of zero. The throttle will be increased without limit and if you don’t switch out of altitude hold before leaving radio range the quadcopter will continue upward until reaching space or running out of power. :slight_smile:

Warning: misleading braces.

Hi guys. I am still having trouble with writing the code to hold it at a max height of 30 cm while allowing me the freedom to move the quad copter in different way. I managed to write the code which help to keep the distance at 30 cm using the “distance = constrain(distance, 0, 30);” function. Now, I have a problem in writing the code to ensure the quad copter won’t go beyond the height limit of 30cm. Thanks

#include <Servo.h>
Servo esc1; //Create servo object for the 4 esc
Servo esc2;
Servo esc3;
Servo esc4;

int ch1 = 3;
int ch2 = 4;
int ch3 = 5;
int ch4 = 6;

int trigPin = A1;
int echoPin = A2;
long duration;
int distance;

int roll_channel = 8;
int pitch_channel = 9;
int throttle_channel = 10;
int yaw_channel = 11;

void setup()
{
  Serial.begin(9600);
  pinMode(ch1, INPUT); //Attach pin to the recevier input
  pinMode(ch2, INPUT);
  pinMode(ch3, INPUT);
  pinMode(ch4, INPUT);
  pinMode(echoPin, INPUT);

  pinMode(trigPin, OUTPUT); //Attach pin to the HC-SR04 output
  pinMode(roll_channel,OUTPUT); //Attach pin to the motor controlling the roll
  esc1.attach( 8 ); //Attach pin 8 to esc 1 to control the motor
  pinMode(pitch_channel, OUTPUT);
  esc2.attach(9);
  pinMode(throttle_channel, OUTPUT);
  esc3.attach(10);
  pinMode(yaw_channel, OUTPUT);
  esc4.attach(11);
}

void loop()
{
  digitalWrite(trigPin, LOW); //Program to measure the distance in cm
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH, 20000);
  distance = duration*0.034/2;
  distance = constrain(distance, 0, 30);
  delay(20);
  
  roll_channel = pulseIn(ch1, HIGH, 20000); //Program to start the motor and to control it
  esc1.writeMicroseconds(roll_channel);
  delay(20);
  pitch_channel = pulseIn(ch2, HIGH, 20000);
  esc2.writeMicroseconds(pitch_channel);
  delay(20);
  throttle_channel = pulseIn(ch3, HIGH, 20000);
  esc3.writeMicroseconds(throttle_channel);
  delay(20);
  yaw_channel = pulseIn(ch4, HIGH, 20000);
  esc4.writeMicroseconds(yaw_channel);
  delay(20);

  if (distance == 30)
  {
    while (distance == 30)
    {
      if (throttle_channel > 1350)
      {
        throttle_channel -= 1;
      }
      esc3.writeMicroseconds(throttle_channel);
    }
  }
    
  Serial.print("Channel 1 (Roll): ");
  Serial.print(roll_channel);
  Serial.print("\t\tChannel 2 (Pitch): ");
  Serial.print(pitch_channel);
  Serial.print("\t\tChannel 3 (Throttle): ");
  Serial.print(throttle_channel);
  Serial.print("\t\tChannel 4 (Yaw): ");
  Serial.print(yaw_channel);
  Serial.print("\t\tDistance: ");
  Serial.println(distance);
}