Aviation do-dad

Hi all,

I have some newbie questions that I think that this fall under “Advice on general approaches or feasibility” (all the above).

My goal is to “re-display” data for real aviation gauges in an Experimental/Homebuilt airplane that I’m helping to fix (a Van’s RV6). I’d like to take output from a Dynon D10A EFIS and a Dynon D10 EMS and create a small display that will sit on top of the panel.

This will not replace my actual gauges. Those gauges will still be in the tradition 6-pack locations.

I’d also like to take data from a LIDAR device and add that into the display to show my elevation as I fly over the runway.

The Dynon baud rates are 115200 and the LIDAR is 9600.

My plan is to:

  1. read and buffer the LIDAR to get an elevation value, then
  2. read/buffer/parse the EFIS
  3. write the EFIS and LIDAR values to screen
  4. read/buffer/parse the EMS
  5. write EMS to screen
  6. goto 1

There is no need for this to be super fast, in fact twice a second would be okay and 6 times a second would be plenty (too much?). There are only a few calculations involved in the output, and most of the display would be text inside rectangles. (see attached png)

My questions are:

Would this take something like a Mega 2560 to handle the three inputs?

Can the different baud rates be accommodated?

cheers,
rv6ator

I see no problems with the different baud rates as the two devices will have to be on different serial ports anyway, either use a Mega or use at least one softserial on an Uno or similar.

wade

Have you contacted the relevant authorities that approve airworthiness to see what they think about unapproved modifications to the aircraft? Adding circuits that do not connect to existing approved electronics is one thing but interfering with the approved electronics may void your approval.

Weedpharma

Thanks Wade. I'll proceed with the Mega.

Hi Weedpharma,

The plane is an Experimental/Homebuilt. In Canada it is classified as "Amateur-Built Aircraft Category", and will be inspected by a Transport Canada representative before flight testing. https://www.tc.gc.ca/eng/civilaviation/publications/tp11957-chapter12-amateur-1147.htm

The AME co-owner and I are the legal "manufacturer" of said aircraft. This is unlike the certified airplane world. We are wiring the airplane from scratch so all of the electronics will be approved by the manufacturer.

FWIW my plan is to take just the serial out from an RS232 pins on the back of the two Dynons. There are no changes to these instruments.

cheers, RV6ATOR

the panel https://www.flickr.com/photos/47739358@N04/14343433879/in/album-72157635351189197/

RV6ATOR: Hi Weedpharma,

The plane is an Experimental/Homebuilt. In Canada it is classified as "Amateur-Built Aircraft Category", and will be inspected by a Transport Canada representative before flight testing. https://www.tc.gc.ca/eng/civilaviation/publications/tp11957-chapter12-amateur-1147.htm

The AME co-owner and I are the legal "manufacturer" of said aircraft. This is unlike the certified airplane world. We are wiring the airplane from scratch so all of the electronics will be approved by the manufacturer.

FWIW my plan is to take just the serial out from an RS232 pins on the back of the two Dynons. There are no changes to these instruments.

cheers, RV6ATOR

the panel https://www.flickr.com/photos/47739358@N04/14343433879/in/album-72157635351189197/

You will also have to add RS232 to TTL level converters for each channel.

Chuck.

chucktodd: You will also have to add RS232 to TTL level converters for each channel.

Chuck.

Thanks Chuck.

I want only the pin out with the serial data from the Dynon RS-232. I'm not pulling power or anything (as far as I know). What does the level converter convert, voltage? If so I'll have to check the voltage out on the Dynon first.

RV6ATOR

RV6ATOR: Thanks Chuck.

I want only the pin out with the serial data from the Dynon RS-232. I'm not pulling power or anything (as far as I know). What does the level converter convert, voltage? If so I'll have to check the voltage out on the Dynon first.

RV6ATOR

RS232 uses positive and negative voltages. TTL just uses positive voltages. You'll need the converter for sure if it says it is RS232 because Arduino can't handle negative voltages.

Thanks Delta_G,

I'll check the voltages on the pin out before anything else.

If it says "RS232" then the voltage is specified by the standard. The actual voltages used can cover a very wide range and still meet the standard. You really need a proper RS232 converter, which contains a MAX232 chip (or one of the other Maxim chips from that family.)

Your basic idea seems sound. However you don't usually make a program dependent on serial data. Even the slowest Arduino can execute thousands of instructions between each serial character arriving, so you usually set up your program to accept data as it arrives and it has other activities to do while data is arriving. Usually Arduino screens are slow to update so the program spends most of its time writing pixels to the screen and the serial data just kind of arrives at its own schedule. You then keep track of the last time that a valid value was observed from the LIDAR or Dynon and the screen may show something like "Error, no data for 5 seconds" when the data gets old.

The examples in Serial Input Basics my be useful for receiving your data.

...R

Morgan,

The intent of this project is to bring important data from three separate items into one place. Display the data simply in an uncluttered manner, and do nothing else.

A more detailed explanation is that I want the program to read LIDAR, convert cm to ft, if LIDAR < 100ft write ELEVATION value from LIDAR.
Read four values from EFIS, and write three values as text, and draw a series of lines for the AOA value.
Read four EMS values, calculate three numbers, post the seven values as text.

Along the way I want to check the values of eight of those variables against set parameters. If they fall out of a certain range the text and rectangle colours will change from grey to yellow to red as warnings.

Thanks Robin2. That tutorial will be really helpful.

Robin2

I finally made some progress in my project. The Serial Input Basics was very helpful. +1 again.

Overview - I’m reading output from a LIDAR LITE rangefinder into an Uno (sender) and using serial communication to transmit to a Mega. The data will always be a one byte number (usually 0-100). Most of the data is good, but there are regular times where the numbers 10, 13, and 56 are displayed (see csv attached txt).

The sender code is bodged from GitHub - PulsedLight3D/LIDARLite_Basics: This repository contains sample code demonstrating different features and functions of the LIDAR-Lite Sensor
and my attempt to pare down the code to just stream data my not be very elegant.

#include <I2C.h>
#include <Wire.h>

// Global Variables
char LIDARLite_ADDRESS = 0x62;           // LIDAR-Lite I2C Address
#define    RegisterMeasure     0x00      // Register to write to initiate ranging.
#define    MeasureValue        0x04      // Value to initiate ranging.
#define    RegisterHighLowB    0x8f      // Register to get both High and Low bytes in 1 call.
unsigned long time;

void setup(){
  Serial.begin(9600);  // Opens serial connection at 9600 baud.     
  I2c.begin();         // Opens & joins the irc bus as master
  delay(100);          // Waits to make sure everything is powered up before sending or receiving data  [was 100  HB]
  I2c.timeOut(40);     // Sets a timeout to ensure no locking up of sketch if I2C communication fails   [was 50  HB]
}

void loop(){
  smRunStateMachine(); // Run the State Machine that controls actions based on user input
}

/* ==========================================================================================================================================
Basic read and write functions for LIDAR-Lite, waits for success message (0 or ACK) before proceeding
=============================================================================================================================================*/

char myAddress;
  
// Write a register and wait until it responds with success
void llWriteAndWait(char myAddress, char myValue){
  uint8_t nackack = 100;    // Setup variable to hold ACK/NACK resopnses     
  while (nackack != 0){     // While NACK keep going (i.e. continue polling until sucess message (ACK) is received)
    nackack = I2c.write(LIDARLite_ADDRESS, myAddress, myValue);     // Write to LIDAR-Lite Address with Value
    delay(2);               // Wait 2 ms to prevent overpolling
  }
}

// Read 1-2 bytes from a register and wait until it responds with sucess
byte llReadAndWait(char myAddress, int numOfBytes, byte arrayToSave[2]){
  uint8_t nackack = 100;    // Setup variable to hold ACK/NACK resopnses     
  while (nackack != 0){     // While NACK keep going (i.e. continue polling until sucess message (ACK) is received)
    nackack = I2c.read(LIDARLite_ADDRESS,myAddress, numOfBytes, arrayToSave);    // Read 1-2 Bytes from LIDAR-Lite Address and store in array
    delay(5);              // Wait 2 ms to prevent overpolling - wait minimum of 30 [HB]
  }
  return arrayToSave[2];    // Return array for use in other functions
}

/* ==========================================================================================================================================
Get 2-byte distance from sensor and combine into single 16-bit int
=============================================================================================================================================*/

int llGetDistance(){
  llWriteAndWait(0x00,0x04); // Write 0x04 to register 0x00 to start getting distance readings
  byte myArray[2];           // array to store bytes from read function
  llReadAndWait(0x8f,2,myArray);   // Read 2 bytes from 0x8f
  int distance = (myArray[0] << 8) + myArray[1];   // Shift high byte [0] 8 to the left and add low byte [1] to create 16-bit int
  byte distf = distance * 0.0328;  // convert distance from cm to ft, this number will always be less than 256
  Serial.write(distf);
  return(distf);                   // output distance in feet [HB]
  // I don't need the return for output, but what function do I have here that required a return?
}

// GLOBAL VARIABLES FOR STATE MACHINE
int configureFlag = 0;
int i = 0;
char serialArray[3];
char serialRead;
  
// The state machine
void smRunStateMachine(){
  if(Serial.available() > 0){
    while(Serial.available() > 0){
      if(i==0){
        configureFlag = 0;
      }
      serialRead = Serial.read();
      if(serialRead == 10 || serialRead == 32 ){
      }else{
        serialArray[i] = serialRead;
        i++;  
      }
    }
  }else{
    i = 0;
  }
      Serial.println(llGetDistance());
}

The receiver code is modified from your tutorial to add timestamps. I’ll remove the timestamps after I get this running without errors. I’ve changed the delays in the receiver code to try and minimize the unusual/spurious values. My hope is that there is a way to remove the delay and eliminate the spurious data.

// Receiver Code after Robin
// http://forum.arduino.cc/index.php?topic=288234.0

byte distf;        // distance in feet
byte timeDiff;     // the time between readings
unsigned long timeLast;
unsigned long timeCount;  // time since start in seconds
char receivedChar;
boolean newData = false;

void setup() {
  Serial.begin(115200); // Serial Monitor matches baud of Dynons (to be added)
  Serial1.begin(9600);  // Serial to/from LIDAR
//  Serial2.begin(115200); // Dynon EFIS
//  Serial3.begin(115200); // Dynon EMS  
  timeLast = millis();  // set the timelast to the current clock
  delay(100);           // wait for the LIDAR to start
}

void loop() {
    showTime();
    recvLidar();
    showNewData();
//    distf = Serial1.read();    //  read the LIDAR output line 66: Serial.write(distf);
//    Serial.println(distf);     //  print the LIDAR output
}

void showTime(){                 // function calculates and displays the millis between readings
    timeDiff = millis() - timeLast;  // calc the time between readings
    timeCount = millis() / 1000;
    Serial.print(timeCount);          // show the time between readings
    Serial.print("   ");
    Serial.print(timeDiff);          // show the time between readings
    Serial.print("   ");
    timeLast = millis();       //  reset the timelast to the current clock
    delay (35);                //  arbitrary?  delay 35 or 36 work well
                               //  but still pass "10", "13", or "56" instead of real data
}

void recvLidar() {
  if (Serial1.available() > 0) {
    distf = Serial1.read();
    newData = true;
  }
}

void showNewData() {
  if (newData == true) {
    Serial.println(distf);
    newData = false;
  }
}

Q1) Can you tell why I’m getting the spurious data values?
Q2) Is there a better way getting the data from the Uno to the Mega?

My goal is to have the LIDAR and the Uno about 10’ from the Mega and transmit by wire to the Mega. (I’m okay with using a dedicated Uno to run the Lidar.) The Mega will read the data stream from the Uno and display it on a TFT. The Mega will also read a Dynon EFIS and a Dynon EMS at 115200 on serial2 and 3 and parse the data from those to display on the TFT.

regards,
RV6ATOR

lidar_output_delay35.txt (2.4 KB)

When you get strange numbers it is always useful to look at their ascii codes
10 is a line-feed character
13 is a carriage return
56 is the number 8

I suspect you would be better using the recvWithEndMarker() version from Serial Input Basics

I can’t make sense of the piece of code you say is the sender. It seems mostly to be using Serial.read()

…R

I can't make sense of the piece of code you say is the sender.

Me too for the most part. There was a lot copy/paste/delete...

The code that sends the data to the Mega is on line 58:

  Serial.write(distf);

I've incorporated the recvWithEndMarker() version and the "10" no longer occurs. I still get the "13" and "56". Should 13 be included in your endMarker code?

In the sender code the variable distf is defined as byte. How am I sending carriage returns and line-feeds?

RV6

13 is carriage return (CR), 10 is line feed (LF), ASCII text characters that literally drove teletype typewriters. Your device sends both, some only send the LF. You can ignore the CR's.

Google ASCII table and pick a simple one that covers 0 to 127, not the extended set. Every programming book I used to have (pre-2000) had an ASCII table in the front or back.

RV6ATOR:
I’ve incorporated the recvWithEndMarker() version and the “10” no longer occurs. I still get the “13” and “56”. Should 13 be included in your endMarker code?

Without seeing your latest code I can’t say

In the sender code the variable distf is defined as byte. How am I sending carriage returns and line-feeds?

The sender code has this line

Serial.println(llGetDistance());

which certainly adds a linefeed. I can’t remember if it also sends a carraige return

But the function llGetDistance() also writes the same character - which seems strange, if not simply stupid.

…R

Robin2

re: recvWithEndMarker() code and passing 13 and 56

Without seeing your latest code I can't say

Doh, sorry. Sadly, I probably won't be the last person to ask you to psychically debug code.

// Receiver Code after Robin
// http://forum.arduino.cc/index.php?topic=288234.0

byte distf;
byte timeDiff;     // the time between readings
unsigned long timeLast;
unsigned long timeCount;  // time since start in seconds
// char receivedChar;
const byte numChars = 1;
char receivedChars[numChars];
boolean newData = false;

void setup() {
  Serial.begin(115200); // Serial Monitor matches baud of Dynons (to be added)
  Serial1.begin(9600);  // Serial to/from LIDAR
//  Serial2.begin(115200); // Dynon EFIS
//  Serial3.begin(115200); // Dynon EMS  
  timeLast = millis();  // set the timelast to the current clock
  delay(100);           // wait for the LIDAR to start
}

void loop() {
    showTime();
    recvWithEndMarker();
//    recvLidar();
    showNewData();
//    distf = Serial1.read();    //  read the LIDAR output line 66: Serial.write(distf);
//    Serial.println(distf);     //  print the LIDAR output
}

void showTime(){                 // function calculates and displays the millis between readings
    timeDiff = millis() - timeLast;  // calc the time between readings
    timeCount = millis() / 1000;
    Serial.print(timeCount);          // show the time between readings
    Serial.print("   ");
    Serial.print(timeDiff);          // show the time between readings
    Serial.print("   ");
    timeLast = millis();       //  reset the timelast to the current clock
    delay (35);                //  arbitrary delay?  delay 35 or 36 works well
                                    //  but still pass "13", or "56" instead of real data
}

/* void recvLidar() {
  if (Serial1.available() > 0) {
    distf = Serial1.read();
    newData = true;
  }
} */

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
  
  // if (Serial.available() > 0) {
           while (Serial1.available() > 0 && newData == false) {
    rc = Serial1.read();

    if (( rc != endMarker )  || ( rc != endMarker ){
      distf = rc;
      newData = true;
    }
  }
}

void showNewData() {
   if (newData == true) {
    Serial.println(distf);
    newData = false;
  }
}

Some of the time distf was the value (number) 8, some time distf was the ASCii character 56 for the value 8, and some time distf was the ASCii character for LF or CR (although LF no longer occurs with the new recvWithEndMarker() version code above).

Is this caused by the use of serial.print and serial.write in the sender code from Mar 29, 2016, 11:33 am?

I got the stand-alone sender code to send data to the serial monitor in a format that I wanted. I'd guessed that the butchered code was "inelegant" and I was ready to move on to the receiver. I'm now going down the rabbit hole reading about the differences between serial.print and serial.write to try and resolve this. Then on to clean up the sender code. It's been 30 years since I took Pascal at university so I've a bit of a learning curve ahead of me.

Thanks for your time and effort on this. Also thanks for the plain speaking. I'm not a big fan of sugarcoating.

RV6ATOR: I'm not a big fan of sugarcoating.

You want to become an old pilot then?