Building a RC pilot kite

I’ve attempted to revamp old simple cheap lift kite controller project.
TLDR the IMU is unreliable.

Recap: I used a model yachting servo on a remote control to effectively steer a lifter. But with poor battery life and the need for a human to steer the control I have since just used standard soft kite lifters.

The parts I had lying around were,
Various Arduino’s (used an elegoo UNO R3)
MPU6050 IMU (a very cheap IMU)
DSD Tech HM-10 Bluetooth module (for phone to control)
HiTEC HS-785HB 10 turn high torque servo (probably too heavy on the juice for a decent battery life)
Toothed belt and matching servo head for toothed belt. (belt would be cut and ends attached to steering bridles)
Some Lego Technic (technically I stole this from the kids)
An amazing W&I LiPo battery (wooo stand back folks, form a queue.)
Smart Phone with BT serial app for ardunio comms.

Parts go together like this


and

The intent was to thread the 3 main bridling lines A,B & C of an HQ KAP kite through the holes with A (leading edge) through the top hole, B mid, C lower trailing set … This way the servo would hang straightish down with the toothed belt turns freely underneath the bridle lines.

The IMU sensor was either to be tied to a rod and attached across the bridles… Or just set hung on the servo. Depending on the physical configuration you’d read a different value in the arduino code.
The MPU6050 is fiddly. It requires holding still for around 10 seconds on initialization and then even after that it drifts. Maybe I have to read up more through the spec sheet but… It’s a weak link in this project.

Also, my BT interface is rudimentary at best. You get a stream of data on your phone showing the roll angle and how far the servo is being steered… and you can send back a number 0 - 9 as an offset level for the steering to pull the kite to one side.

You know what… it kinda works… just that the drift in the IMU would be totally head doing.
Here’s the code…


//Really basic Lift Kite steering 

//WARNING MPU6050 IMU READINGS DRIFT SIGNIFICANTLY 
//SO MUCH DRIFT THAT THIS IS IMPRACTICAL

//Using MPU6050 IMU to get roll data for adjusting servo setting   
//Any value deviating fron 0 straight up maps straight to a servo steering

//roll reading is through a running smoothing matrix

//Reading an value from phone bluetooth and applying it to further offset the kite angle
// only acceptting 1 char at a time just now until we sort out parsing number data
// each offset value is case set as an offset steering angle


//STILL NEED TO ADD A PID setpoint for where we want to sit @ e.g. val = offsetangleselected

//BTserial software from somewhere internety

//  Sketch: basicSerialWithNL_001
// 
//  Uses hardware serial to talk to the host computer and software serial 
//  for communication with the Bluetooth module
//  Intended for Bluetooth devices that require line end characters "\r\n"
//
//  Pins
//  Arduino 5V out TO BT VCC
//  Arduino GND to BT GND
//  Arduino D11 to BT RX through a voltage divider
//  Arduino D10 BT TX (no need voltage divider)
//
//  When a command is entered in the serial monitor on the computer 
//  the Arduino will relay it to the bluetooth module and display the result.
//


#include <MPU6050_tockn.h>
#include <Wire.h>
#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11); // RX | TX BT05 Uno connections


const long baudRate = 9600; 
short c = 0;
boolean NL = true;//4


#include <Servo.h>
Servo myservo;  // create servo object to control a servo

long val;    // variable to set as roll value read from MPU6050
int offsetANGLEselected; //a variable to set as chosen offset angle
int steer;  // variable to send to the servo 
int slowcount;  // dont send every reading over bluetooth only when this count is...
int slowamount;// only every 5 (as set in setup) over BT



const int numReadings = 8;  //size of array for smoothing roll readings 

int readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average



MPU6050 mpu6050(Wire);

void setup() {
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");
 
    BTserial.begin(9600);  
    BTserial.print("BTserial started at "); BTserial.println(baudRate);
    BTserial.println(" ");
    
    delay (1);      //because rods messed with programme timing


    
     
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
                          readings[thisReading] = 0;} //clear array    
                          Serial.println("smoothing array ready");
      delay(10);

    Wire.begin();

   delay(10);

  mpu6050.begin();
  mpu6050.calcGyroOffsets(true);
  delay (10);      //because rods messed with programme timing
      // attaches the servo on pin 9 to the servo object
    myservo.attach(9);  
     
    delay(1);       //because rods messed with programme timing
    
    slowcount=(0);  //count reset
    slowamount=(10);  //count limit

    
    BTserial.print("Sketch:   ");   BTserial.println(__FILE__);
        delay (1);
    BTserial.print("Uploaded: ");   BTserial.println(__DATE__);
        delay (1);
    BTserial.println(" ");
  
}

void loop() {


 if (Serial.available())
    BTserial.write(Serial.read());
     delay(10);
          // Read from the Bluetooth module and send to the Arduino Serial Monitor
          if (BTserial.available())
          {
              c = BTserial.read();
                    switch(c) { 
                      //case 48: /* Number 0 */
                      case '0':
                    offsetANGLEselected = (0);     
                            break;      
                      //case 49: /* Number 1 */
                      case '1':
                    offsetANGLEselected = (5);     
                            break;
                     case '2':
                    offsetANGLEselected = (10);     
                            break;      
                      case '3':
                    offsetANGLEselected = (15);     
                            break;      
                       case '4':
                    offsetANGLEselected = (20);     
                            break;      
                      case '5':
                    offsetANGLEselected = (25);     
                            break; 
                     case '6':
                    offsetANGLEselected = (30);     
                            break;      
                      case '7':
                    offsetANGLEselected = (35);     
                            break;
                      case '8':
                    offsetANGLEselected = (40);     
                            break;      
                      case '9':
                    offsetANGLEselected = (65);     
                            break;         
                            default:
                              //Serial.print("Offset Angle: ");
                             //Serial.println(offsetANGLEselected);
                            BTserial.print("Offset Angle: ");
                            BTserial.print(offsetANGLEselected);

                            break;
                            }
                   delay(1);
           }
              
   
   delay(1);
  mpu6050.update();
  
      val = (mpu6050.getAngleZ());       //set readable roll to val 
    //Serial.print(val);
      
        total = total - readings[readIndex];// subtract the last reading:
        readings[readIndex] = val;// read roll value from this program:
        total = total + readings[readIndex];// add the reading to the total:
        readIndex = readIndex + 1;// advance to the next position in the array:
        
        if (readIndex >= numReadings) { // if we're at the end of the array...wrap around to the beginning:
           readIndex = 0;             }
           delay(1);        // delay in between reads for stability
           
        average = total / numReadings; // calculate the average:  
            delay(1);   

      
            steer = map(average, -40, 40, 30, 150);      // set human readable kite roll limits to servo range
            delay(1); 

            steer = (steer - offsetANGLEselected);
            if (steer <30) { steer = 30; }
            if (steer >150) { steer = 150; }
            myservo.write(steer);                        // sets the servo position according to roll 
            delay(5);                              // wait for the servo to get there

           // Serial.print("    Steer =  ");
           // Serial.println(steer);  

      slowcount++;
      
      if (slowcount >= slowamount){
                slowcount = (0);
               // BTserial.write(val);
               
                BTserial.println(average);
                BTserial.print("    Steer =  ");
                BTserial.println(steer);


                      //Serial.print(val);
                      //Serial.print("Smoothed Average Angle: ");
                      //Serial.println(average);
                      //Serial.print("    Steer =  ");
                      //Serial.println(steer);  
                }
  
delay (20);
}

2 Likes