Hi there,
Zloyhan'18
Please I wish urgent help.
I am currently working on an RC project with fixed-wing aircraft. The goal of the project is to use an esp-32-based microprocessor (it is not esp32, a card named deneyap) to apply some flight controls to the system via an Autopilot / RC input. Basically a homemade autopilot. We will use this in an contest upcoming.
The current state of the project:
- I have two different power sources: USB and 3s 25c lipo (11.1v - 12.4v)
- There are 1 Reciever (Rx), 1 Radio controller (fly sky i6x with 10 ch, Tx), 4 servo motors (tower pro sg90, 180deg) 1 ESC (brandless 30A), 1 brushless motor (brandless 1400KV). and some sensors with an I2C connection.
I am basically taking ppm signal from Rx, and analysing its signals in interrupts, dividing it into 8 channel inputs with microseconds.
Here you can see the whole wiring scheme I created. I only had paint in my hand so please excuse me for not having any technical electrical scheme.
Basically, the lipo powers the Rx, Servos, ESC, and Brushless motor; while the signal cables are connected to the microprocessor which is powered by the USB cable. I read and write data for debugging and testing from console commands.
I then do not edit the data, I basically re-write the channel inputs only reversing if necessary. I create PWM signals 250hz for all of the components.
Here is my whole code with explanations:
// LIBRARIES USED
#include "deneyap.h"
#include <Wire.h>
//PIN SETTINGS
const int BZRpin = D0; //inout pin for buzzer
const int PPMpin = D1; //pinout for ppm
const int RightAileronPin = D12;
const int LeftAileronPin = D13;
const int ElevatorPin = D14;
const int ThrottlePin = D4;
const int RudderPin = D15;
//CHANNEL ASSIGNMENTS
const int RightAileronCH = 1;
const int LeftAileronCH = 1; // must be negative value (reversed)
const int ElevatorCH = 2;
const int ThrottleCH = 3;
const int RudderCH = 4;
//RC INPUT SETTINGS
const int channelNum = 8; //num of channels inputed - PUBLIC
//PPM SETTINGS
volatile long PW[channelNum] = {0}; // array of pulse-width of channels in micro sec PRIVATE
volatile long ptime = 0; // specific pulse time in micro sec PRIVATE
volatile long crtime = 0; // current time in micro sec PRIVATE
volatile int pulse = 0; // num of encountered pulses PRIVATE
//RC OUTPUT SETTINGS
float ThrottleInput;
float RightAileronInput;
float LeftAileronInput;
float ElevatorInput;
float RudderInput;
float TestServoInput;
//MPU SETTINGS
float RateROLL, RatePITCH, RateYAW;
float ROLLcal, PITCHcal, YAWcal;
int NUMcal; // private
const int NUMtotalcal = 4000;
// MAIN METHOD
void setup(){
Serial.begin(57600); // initlize serial com
pinMode(BZRpin, OUTPUT); // buzzer initiated
pinMode(RightAileronPin, OUTPUT); // pins for servos for Right Aileron initiated
pinMode(LeftAileronPin, OUTPUT); // pins for servos for Left Aileroninitiated
pinMode(ElevatorPin, OUTPUT); // pins for servos for Elevator initiated
pinMode(RudderPin, OUTPUT); // pins for servos for Rudder initiated
pinMode(ThrottlePin,OUTPUT); // pins for ESC for Throttle initiated
Serial.print("Please wait...");
//PWM setup
analogWriteFrequency(250);
analogWriteResolution(12);
delay(250);
//Set control surfaces to safe oriantation for pre-flight
analogWrite(RightAileronPin,1.024*1500);
analogWrite(LeftAileronPin,1.024*1500);
analogWrite(ElevatorPin,1.024*1500);
analogWrite(RudderPin,1.024*1500);
delay(2000);
//system message on power
Serial.println(" ");
Serial.println("SYSTEM POWERED");
Serial.println("==============");
buzzersig(200);
buzzersig(200);
delay(1000);
//--------------- CONFIGURATIONS -----------------//
Serial.println("- Configuring settings -");
delay(500);
Serial.print("MPU (I2C Settings)..."); // Settings for MPU I2C Com.
Wire.setClock(400000); //I2C
Wire.begin();
delay(250);
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
Serial.println("DONE");
delay(500);
/*
Serial.print("Calibrqation 2") //desc
//cal
Serial.println("DONE");
delay(500);
*/
Serial.println("SUCCESS!");
buzzersig(200);
Serial.println(" ");
delay(500);
//---------------- CALIBRATIONS ------------------//
Serial.println("- Sensor Calibrations - (INITIATING)!");
delay(500);
Serial.print("Calculating IMU - Do not touch the platform!");
delay(2000);
buzzersig(500);
for(NUMcal = 0; NUMcal < NUMtotalcal; NUMcal++) {
gyro_sig();
ROLLcal+= RateROLL;
PITCHcal+= RatePITCH;
YAWcal+= RateYAW;
delay(1);
if(NUMcal%1000 == 0 ) {
Serial.print(".");
buzzersig(100);
}
}
ROLLcal/=NUMtotalcal;
PITCHcal/=NUMtotalcal;
YAWcal/=NUMtotalcal;
Serial.println("DONE");
delay(500);
/*
Serial.print("Calculating X - Do not touch the platform!");
delay(2000);
buzzersig(500);
cal 2
Serial.println("DONE");
delay(500);
*/
Serial.println("SUCCESS!");
buzzersig(200);
Serial.println(" ");
delay(500);
//system message on succesful Initialization
Serial.println(" ");
Serial.println("SYSTEMS INITIATED");
Serial.println("================");
buzzersig(200);
buzzersig(200);
buzzersig(200);
//Inıtiated PPM Reading functions
delay(500);
attachInterrupt(digitalPinToInterrupt(PPMpin), ppmread, FALLING); // Attach interrupt to pin for reading PPM channels.
Serial.println(" ");
Serial.println("Waiting for Tx Signal! (CH1 is sampling)");
while(PW[0] < 900 || PW[0] > 2100) {
delay(1000);
Serial.print(".");
Serial.print(PW[0]);
delay(1000);
}
Serial.println(" ");
Serial.println("CONNECTED!");
buzzersig(200);
//safety for microporcessor resets
while(PW[ThrottleCH-1] > 1020 ) {
delay(4);
Serial.println("ATTENTION!! LOWER THE THROTTLE STICK!!");
Serial.print(PW[ThrottleCH-1]);
Serial.print("[/µs] ");
Serial.println();
buzzersig(200);
//delay(200);
}
//electronically starting the burshless motors
/*
analogWriteFrequency(250);
buzzersig(200);
analogWrite(ThrottlePin,1.024*1000);
delay(200);
analogWrite(ThrottlePin,1.024*2000);
delay(200);
analogWrite(ThrottlePin,1.024*1000);
delay(2000);
*/
}
void loop() {
gyro_sig(); // get gyro data and apply calibration
RateROLL-=ROLLcal;
RatePITCH-=PITCHcal;
RateYAW-=YAWcal;
/*
Serial.print("ROLL r: ");
Serial.print(RateROLL);
Serial.print(" PITCH r: ");
Serial.print(RatePITCH);
Serial.print(" YAW r: ");
Serial.println(RateYAW);
delay(50);
/*
7*
for (int i =0 ; i<channelNum; i++) {
Serial.print("Ch");
Serial.print(i+1);
Serial.print(": ");
if(i==7)
{
Serial.println(PW[i]);
}
else
{
Serial.print(PW[i]);
Serial.print(" ");
}
}
*/
//write throttle to ESC
if(PW[ThrottleCH-1] < 1030)
{ //prevents twitching
ThrottleInput = 1.024*1000;
analogWrite(ThrottlePin, (ThrottleInput));
}
else
{ //applies throttle
ThrottleInput = 1.024*PW[ThrottleCH-1];
analogWrite(ThrottlePin, (ThrottleInput));
}
//write Right Aileron
RightAileronInput = 1.024*PW[RightAileronCH-1];
analogWrite(RightAileronPin, (RightAileronInput));
//write Left Aileron
LeftAileronInput = 1.024*map(PW[LeftAileronCH-1],1000,2000,2000,1000);
analogWrite(LeftAileronPin, (LeftAileronInput));
//write Rudder
RudderInput = 1.024*PW[RudderCH-1];
analogWrite(RudderPin, (RudderInput));
//write Elevator
ElevatorInput = 1.024*PW[ElevatorCH-1];
analogWrite(ElevatorPin, (ElevatorInput));
/*
Input = 1.024*PW[CH-1];
analogWrite(Pin, (Input));
*/
//prints out channel inputs for debugging
for(int j=0; j<channelNum; j++) {
Serial.print("CH");
Serial.print(j+1);
Serial.print(": ");
if(j==7)
{
Serial.println(PW[j]);
}
else
{
Serial.print(PW[j]);
Serial.print(" ");
}
}
delay(4);
}
void ppmread() { //interrupt method
switch (pulse) {
default:
pulse++;
ptime = micros();
break;
case 1:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse++;
ptime = crtime;
if (PW[pulse-2]>2100) {
pulse = 1;
}
break;
case 2:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse++;
ptime = crtime;
if (PW[pulse-2]>2100) {
pulse = 1;
}
break;
case 3:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse++;
ptime = crtime;
if (PW[pulse-2]>2100) {
pulse = 1;
}
break;
case 4:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse++;
ptime = crtime;
if (PW[pulse-2]>2100) {
pulse = 1;
}
break;
case 5:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse++;
ptime = crtime;
if (PW[pulse-2]>2100) {
pulse = 1;
}
break;
case 6:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse++;
ptime = crtime;
if (PW[pulse-2]>2100) {
pulse = 1;
}
break;
case 7:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse++;
ptime = crtime;
if (PW[pulse-2]>2100) {
pulse = 1;
}
break;
case 8:
crtime = micros();
PW[pulse-1] = crtime - ptime;
pulse = 0;
ptime = crtime;
if (PW[pulse+channelNum-1]>2100) {
pulse = 1;
}
break;
}
}
void buzzersig(int ms) {
digitalWrite(BZRpin,HIGH);
delay(ms);
digitalWrite(BZRpin,LOW);
delay(ms);
}
void gyro_sig() {
Wire.beginTransmission(0x68);
Wire.write(0x1A);
Wire.write(0x05);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x1B);
Wire.write(0x8);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x43);
Wire.endTransmission();
Wire.requestFrom(0x68,6);
int16_t GyroX=Wire.read()<<8 | Wire.read();
int16_t GyroY=Wire.read()<<8 | Wire.read();
int16_t GyroZ=Wire.read()<<8 | Wire.read();
RateROLL=(float)GyroX/65.5;
RatePITCH=(float)GyroY/65.5;
RateYAW=(float)GyroZ/65.5;
}
There are a few other codes for system initialization etc. Do not mind them.
The whole system works fine, BUT I have a persistent issue:
The problem I cannot solve is that whenever I start moving servos a bit fast, the brushless motors start "twitching" moving and spinning sometimes.
I have tried writing the channel values and the variable ( ThrottleInput
float) I input for the esc in the form of a PWM signal. I see that I input the lowest input, BUT SOMEHOW motor still spins and "twitches" to this day.
Note for PPM signalling: 1000 microseconds (lowest, min input) for CH length in PPM pulse, I convert it in the code to a form that can be inputted as an arg in analogWrite
, so I have a PWM wave at the end.
I have observed that:
- Only motor experiences such behaviour. Not other servos.
- More vigorously the servo channel input from the transmitter, Tx, (moving sticks faster to left and right) the spinning of the motor movement increases and becomes more significant.
I have read about servos exceeding 5v and creating voltage spikes (mine are 4.8 - 5.3 depending on the way I move them through Tx, I measured.) may be causing this problem.
I have talked with a professor from a university (a professional) and he stated that the problem could be caused by using the same ground. for signalling and powering.
I need the USB cable for reading data till I finish this project, I have ordered I PCB for a more streamlined 5V output (BEC integrated PDB). Do I need to power everything from lipo? I will be unable to use USB when the system is powered on, I do not want this.
Please I wish urgent help.