-1

I'm trying to build a quadcopter flight controller from scratch using an ESP32, BNO055 IMU, and Turnigy TGY-i6 Transmitter/Receiver. So far I've been able to get everything to work together and give me reasonable data using PID control loops, filters, and various libraries. Previously I was using an Arduino Nano in place of the ESP32 because it was what I had at the time and I thought it worked well with it.

After doing some (very rough) flight testing I ended up coming to the conclusion that the code was not executing fast enough with the Nano to sustainably keep the quadcopter in the air. I decided to measure the loop time by setting a t1 and t2 at the beginning and end of the loop, and took the difference to find the time it took to execute one loop of the code. With the Nano, it took roughly 80000 microseconds exactly with little deviation.

Seeing this, I bought the ESP32 knowing that it had a much faster CPU clock speed and overall performance compared against the Nano. After getting the code to work on the ESP32 with a few changes, I ran a speed test again, and got the same 80ms. I was a bit confused at first but I decided to try and isolate the problem by taking out chunks of the code to see if the loop time would change - and it did not. After reading about some specific inefficencies of Arduino IDE [such as digitalWrite()] I kept trying to take away specific parts of the code, and no difference arose as I kept measuring the clock speed. It kept at roughly 80000 microseconds no matter the changes I made.

This leads me to believe that there is something quite important that I'm unaware about in my code that is causing it to run so slow. Ideally, I would like to be able to lower the loop time to at most 10ms so that the quadcopter can autolevel with little to no oscillation.

I've used Arduino for a few years now, but by no means am an expert - so any help on optimizing the code and/or solving this odd problem would be very much appreciated, Thank you.

Note: I have a suspicion that it may be something related to the IMU (BNO055) because that is one part of the hardware and software I know very little about.

These are the libraries I'm using:

#include "ESC.h"               //ESC
#include <ESP32Servo.h>        //ESC 
#include <Wire.h> 
#include <Adafruit_Sensor.h>   //IMU
#include <Adafruit_BNO055.h>   //IMU
#include <utility/imumaths.h>  //IMU
#include <PID_v1.h>            //PID    

Here is the rest of the code.

WhyF4
  • 21
  • 5
  • I'd suspect some periferial library has blocking delay. Try to localize delaying function in main loop by bisecting it, i.e. set measurement points in the beginning and in the middle of loop, then in the middle of delaying part and so on. Then check library sources for delay loops, waiting for bits in registers etc. – dimich Jul 21 '22 at 03:43
  • `Serial.println()` itself can make significant delays. I would generate pulses with unused GPIO and measure time with oscilloscope, without serial port communication. – dimich Jul 21 '22 at 03:57
  • Hi @WhyF4, welcome to Stack Overflow. Please don't link to code. Links can expire and aren't searchable from within Stack Overflow. Instead please edit your question to include a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the code which demonstrates the problem. – romkey Jul 21 '22 at 03:57
  • -Dimich, I used your idea of bisecting it and putting measurement points throughout the loop and narrowed it down to the `pulseIn()` This may seem obvious now, but the function waits for the pin to go from low to high, starts timing, and waits for it to return low again. Clearly, this is blocking the code from running. I suppose my next pursuit will be on how to read PPM signals from receivers without using `pulseIn()` -- And on the `Serial.println()`, I have read that it causes delays and will make sure to remove them before using the code in flight. Thank you for the insight help Dimich! – WhyF4 Jul 21 '22 at 04:22
  • 1
    Just a note about posting the link to the code and trying to include a "minimal, reproducible example," if I don't know what the problem is in my code, and I cannot find it, and come here to ask it, should I be posting the entire 300 lines of code and filling up the entire screen... or just post a link to it. Besides I did include a segement of my code that I thought could be the problem, and only then included the rest. – WhyF4 Jul 21 '22 at 16:30

1 Answers1

2

After reviewing the code and segmenting it further, I discovered the problem was coming from the pulseIn() functions I use to read the PPM signal from the receiver.

The function works by:

Reads a pulse (either HIGH or LOW) on a pin. For example, if value is HIGH, pulseIn() waits for the pin to go from LOW to HIGH, starts timing, then waits for the pin to go LOW and stops timing. Returns the length of the pulse in microseconds or gives up and returns 0 if no complete pulse was received within the timeout. Link

Looking back, this clearly causes a delay in the code.

Thank you to dimich for putting me on the right path to solve the problem.

Edit: How you can solve this:

Rather than use pulseIn(), you can use interrupts to solve the problem. I did this by attaching an interrupt to the pin that is sending the PPM signal and listening for a CHANGE to happen on it. You then check whether the pin is HIGH or LOW and either begin or stop your timer. This avoids using delays in the program and allows for a clean signal to be read.

Note: Some receivers use a PPMsum on one pin rather than individual pins. On my receiver, I use 4 different channels and 4 different GPIO pins for each axis + throttle.

WhyF4
  • 21
  • 5