Square waves and receive data - controlling drones

Hi,

I’m currently working on a quadcopter control system, and I’m having a small problem.
There are two parts of the whole thing:

  • a transmitter which sends messages on serial monitor like <1234123412341234> containing markers to indicate the beginning and the end of the message, and four 4-digit numbers generated according to the joystick axis values,

  • a receiver to get the message, decode it, and make 62.5Hz square waves based on the axis states.

I’ve written two codes for the receiver.

One to convert text got from serial monitor to integer values:

int y = 0, t = 0, p = 0, r = 0;
boolean mE = false;
unsigned long timer;

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

void loop() {
  static boolean mS = false;
  static byte i = 0;
  char rec;

  while (Serial.available() > 0 && mE == false) {
    rec = Serial.read();
    if (mS == true) {
      if (rec != '>') {
        if (i >= 0 && i <= 3) {
          y += digit(i, rec);
        } else if (i >= 4 && i <= 7) {
          t += digit((i % 4), rec);
        } else if (i >= 8 && i <= 11) {
          p += digit((i % 4), rec);
        } else if (i >= 12 && i <= 15) {
          r += digit((i % 4), rec);
        }
        i++;
      }
      else {
        mS = false;
        i = 0;
        mE = true;
      }
    }
    else if (rec == '<') {
      mS = true;
    }
  }
  
  if (mE == true) {
    mE = false;
  }
}

int digit(int i, int rec) {
  switch (i) {
    case 0:
      return (rec - 48) * 1000;
      break;
    case 1:
      return (rec - 48) * 100;
      break;
    case 2:
      return (rec - 48) * 10;
      break;
    case 3:
      return (rec - 48);
      break;
  }
}

And another one to generate squarewaves:

int y = 0, t = 0, p = 0, r = 0;

void setup() {
  DDRD = B11111110;
  DDRD = DDRD | B11111100;
}

void loop() {

  timer = micros();
  
  do {
    if (micros() - timer <= y) PORTD = B00010000;
    else if (micros() - (timer + y) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);

  timer = micros();

  do {
    if (micros() - timer <= t) PORTD = B00100000;
    else if (micros() - (timer + t) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);

  timer = micros();

  do {
    if (micros() - timer <= p) PORTD = B01000000;
    else if (micros() - (timer + p) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);

  timer = micros();

  do {
    if (micros() - timer <= r) PORTD = B10000000;
    else if (micros() - (timer + r) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);
}

By changing y, t, p, r values in the code above, I got decent waves, and my flight controller also worked with them. But when putting these two sketches together into something like this:

int y = 0, t = 0, p = 0, r = 0;
boolean mE = false;
unsigned long timer;

void setup() {
  DDRD = B11111110;
  DDRD = DDRD | B11111100;
  Serial.begin(9600);
}

void loop() {
  static boolean mS = false;
  static byte i = 0;
  char rec;

  while (Serial.available() > 0 && mE == false) {
    rec = Serial.read();
    if (mS == true) {
      if (rec != '>') {
        if (i >= 0 && i <= 3) {
          y += digit(i, rec);
        } else if (i >= 4 && i <= 7) {
          t += digit((i % 4), rec);
        } else if (i >= 8 && i <= 11) {
          p += digit((i % 4), rec);
        } else if (i >= 12 && i <= 15) {
          r += digit((i % 4), rec);
        }
        i++;
      }
      else {
        mS = false;
        i = 0;
        mE = true;
      }
    }
    else if (rec == '<') {
      mS = true;
    }
  }
  
  if (mE == true) {
    mE = false;
  }

  timer = micros();
  
  do {
    if (micros() - timer <= y) PORTD = B00010000;
    else if (micros() - (timer + y) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);

  timer = micros();

  do {
    if (micros() - timer <= t) PORTD = B00100000;
    else if (micros() - (timer + t) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);

  timer = micros();

  do {
    if (micros() - timer <= p) PORTD = B01000000;
    else if (micros() - (timer + p) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);

  timer = micros();

  do {
    if (micros() - timer <= r) PORTD = B10000000;
    else if (micros() - (timer + r) <= 4000) PORTD = B00000000;
  } while (micros() - timer <= 4000);
}

int digit(int i, int rec) {
  switch (i) {
    case 0:
      return (rec - 48) * 1000;
      break;
    case 1:
      return (rec - 48) * 100;
      break;
    case 2:
      return (rec - 48) * 10;
      break;
    case 3:
      return (rec - 48);
      break;
  }
}

The flight controller didn’t notice the signal, but according to my scope, they were kind of good.

Now, I’m really confused, so help me, please!

AFK

Obviously I cannot see the signal on your 'scope but it seems to me likely that your use of DO/WHILE will cause timing problems because you are blocking the Arduino from doing other things.

My suggestion has two parts. First, change the format in which you send the data to <1234,1234,1234,1234> and apply the technique in the parse example in Serial Input Basics. That example receives data in a non-blocking style. Using a higher baud rate may also be useful.

Second, replace the DO/WHILEs with simple IFs and allow loop() to do the iteration. That will allow the creation of the pulses to overlap with each other and with the receipt of Serial data.

Third (sorry :slight_smile: ) it looks to me like it may be possible to do all of the pulse timing in a single piece of code that reads micros() once and checks that value with the appropriate values for each pulse. Something like

currentMicros = micros();
for (n = 0; n < numChannels; n++) {
   if (currentMicros - prevMicrosForChannel[n] >= intervalForChannel[n]) {
     prevMicrosForChannel[n] += intervalForChannel[n];
     // pulse on or off
   }
}

…R