Artificial Horizon display using a gyro

Hello guys,

i would lik to build a mini artificial Horizon display for a model airplane.
the code should take roll + pitch angles from an MPU6050 and display an articial horizon "ball" similar to that of an aircraft.
im using the SPI 1.8" display, and managed to build a static display of pitch = 0 roll = 0, similar to the attached picture.
so far im trying to run the diaply with variable angles, without the gyro, just for making sure i have the display running well.

im using the Adafruit ST7735 library, and i can fill parts of the screen with tft.fillRoundRect function, but i can not get how to fill "angled" parts of the screen.
i managed to get a code running just the Artifical horizon line using DrawLine:

  for (int16_t y=0; y < 10; y++) 
{

  for (int16_t x=40; x < 120; x++) 
  {
   tft.drawLine(0, x, 130, 160-x, color);   // startx, start y, stop x, stop y
      tft.drawLine(0, x, 130, 160-x, ST7735_BLACK);   // startx, start y, stop x, stop y
  }

    for (int16_t x=120; x >40; x--) 
  {
   tft.drawLine(0, x, 130, 160-x, color);   // startx, start y, stop x, stop y
      tft.drawLine(0, x, 130, 160-x, ST7735_BLACK);   // startx, start y, stop x, stop y
  }
  
   //     tft.drawLine(0, 70, 130, 90, color);   // startx, start y, stop x, stop y
}
}

but how do i fill the screen in color above and below that line?
under that line should be brown, and above it blue.

also, in order to get just one line on the screen at all times, i have to "delete" the line by drawing a black line over it, this wont work with full color background.

basically what im trying to get is a code like the piece of code i added, but above the line all blue, under the line all brown.

any ideas?
thanks.

i did try a for loop with a single pixel print, from 0,0 all the way up to the angled line, but it is very slow.
takes about 2 seconds to fill a whole screen - and i need to refresh it at least 1-2 times a second.

See this video: Horizon Artificiel avec Arduino UNO et MPU 6050 Gyroscope et accelerometre (Prototype) - YouTube

Thank you for the link - is that your own code?

"Published on Dec 3, 2015"
Too bad you can't get that code.

i3dm:
...

but how do i fill the screen in color above and below that line?

...

If you want to display just "roll" angle, i.e. pitch angle is zero then:

Use trigonometry (Tan) to find the coordinates of the point at the edge of the screen of a line at the angle you want which passes through the middle of the screen. Since the middle of the screen is a known point this is easy.

Then reflect the coordinate to get the point at the opposite edge. Now you have two points and you can draw two filled triangles and two filled rectangles to set the above and below horizon colours, then draw a line at the horizon.

If you want to add pitch then calculate the coordinate shift on the y axis and the use this as the point that the angled line passes though and to get the intersection coordinates at the edges of the screen. You cannot use coordinate reflection is this case. so you must use trig to get the 2 end points of the horizon line.

If you draw it out on paper you will see what I mean.

When you have debugged your code on the Adafruit library and are using an AVR processor (e.g. UNO, Mega etc) and do not achieve the refresh rate you want... then try my library here library here which is 3 to 10 times faster for graphics operations. I think you could achieve at least 5 frames per second. For a simpler display with a single line for a horizon you should be able to get at least 50 frames per second.

i already did the trig, just looking for a fast way to fill the screen up to the line.

bodmer:
If you want to display just "roll" angle, i.e. pitch angle is zero then:

Use trigonometry (Tan) to find the coordinates of the point at the edge of the screen of a line at the angle you want which passes through the middle of the screen. Since the middle of the screen is a known point this is easy.

Then reflect the coordinate to get the point at the opposite edge. Now you have two points and you can draw two filled triangles and two filled rectangles to set the above and below horizon colours, then draw a line at the horizon.

If you want to add pitch then calculate the coordinate shift on the y axis and the use this as the point that the angled line passes though and to get the intersection coordinates at the edges of the screen. You cannot use coordinate reflection is this case. so you must use trig to get the 2 end points of the horizon line.

If you draw it out on paper you will see what I mean.

When you have debugged your code on the Adafruit library and are using an AVR processor (e.g. UNO, Mega etc) and do not achieve the refresh rate you want... then try my library here library here which is 3 to 10 times faster for graphics operations. I think you could achieve at least 5 frames per second. For a simpler display with a single line for a horizon you should be able to get at least 50 frames per second.

tried your library, but for some reason your examples dont display anything on the screen?

i3dm:
i already did the trig, just looking for a fast way to fill the screen up to the line.

fillTriangle() and fillRect() as hinted in post #5

Edit: If you want to make your code much smarter and hence quicker then it is quite easy to use the old and new angle coordinates to work out the minimum size of triangles (either 2, or 4 triangles where a corner transition occursl) that needs to be filled, this would boost the frame rate significantly for smaller/slower angle changes.

i3dm:
tried your library, but for some reason your examples dont display anything on the screen?

You will need to edit the User_Setup.h file inside the library as stated in the ReadMe file to suit your pin settings and display variant ("TAB" colour)!

Edit: Forgot to mention the library is only compatible with AVR processors (UNO, Leonardo, Mega etc)

Im using Arduino Pro mini with Atmel 328P, is that compatible?
so i understand the only "fast" way to fill the screen is with fillTriangle() and fillRect() ?

bodmer:
You will need to edit the User_Setup.h file inside the library as stated in the ReadMe file to suit your pin settings and display variant ("TAB" colour)!

Edit: Forgot to mention the library is only compatible with AVR processors (UNO, Leonardo, Mega etc)

i edited the .h file with my correct pin numbers, and tried all 5 tab options - none of them seems to work. i get a white screen in all of them.

A Pro Mini should work fine. The 3.3V version does not require any level shifting.

Paste your sketch in a CODE window or attach the file. Are you just wanting a line that moves or a filled semi-circle that rotates?

You generally get the most responsive display if you just erase the old triangle and draw the new triangle. Most changes are incremental. i.e. a thin triangle.

Post a link to your actual display. There are several 128x160 controllers. I have a sketch that will diagnose which one you have.

David.

Here is my code which builds the backgorund image:

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#define TFT_CS     10
#define TFT_RST    9
#define TFT_DC     8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);
#define TFT_SCLK 13   // set these to be whatever pins you like!
#define TFT_MOSI 11   // set these to be whatever pins you like!

void setup(void) 
{
  tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
  DrawAHI();
}

void loop() 
{
// none
}



void DrawAHI() { 
  // play
  tft.fillScreen(ST7735_BLACK);
  tft.fillRoundRect(0, 0, 130, 80, 0, ST7735_BLUE); // start point X, start pint Y, Length X, Length Y, corner radius
  tft.fillRoundRect(0, 83, 130, 80, 0, 0x79E0); // start point X, start pint Y, Length X, Length Y, corner radius
  tft.fillRoundRect(35, 50, 60, 60, 30, ST7735_WHITE);
  tft.fillRoundRect(40, 55, 50, 50, 25, ST7735_BLACK);
  tft.fillRoundRect(40, 80, 50, 3, 0, ST7735_RED);
  tft.fillRoundRect(63, 55, 3, 50, 0, ST7735_RED);
// side vertical lines
  tft.fillRoundRect(15, 30, 5, 100, 0, 0x7BEF);
  tft.fillRoundRect(110, 30, 5, 100, 0, 0x7BEF);

  tft.setCursor(2, 30);
  tft.setTextColor(ST7735_WHITE);
  tft.print("20");
  tft.setCursor(2, 120);
  tft.setTextColor(ST7735_WHITE);
  tft.print("20");
  tft.setCursor(2, 50);
  tft.setTextColor(ST7735_WHITE);
  tft.print("10");
  tft.setCursor(2, 100);
  tft.setTextColor(ST7735_WHITE);
  tft.print("10");
  tft.setCursor(115, 30);
  tft.setTextColor(ST7735_WHITE);
  tft.print("20");
  tft.setCursor(115, 120);
  tft.setTextColor(ST7735_WHITE);
  tft.print("20");
  tft.setCursor(115, 50);
  tft.setTextColor(ST7735_WHITE);
  tft.print("10");
  tft.setCursor(115, 100);
  tft.setTextColor(ST7735_WHITE);
  tft.print("10");

  tft.setCursor(10, 0);
  tft.setTextColor(ST7735_GREEN);
  tft.print("SPD  LNAV WNAV PTH");
  
  tft.setCursor(10, 150);
  tft.setTextColor(ST7735_GREEN);
  tft.print("Lior Z. AHI Display");
  
/* 
 code color
 0x0000 Black
 0xFFFF White
 0xBDF7 Light Gray
 0x7BEF Dark Gray
 0xF800 Red
 0xFFE0 Yellow
 0xFBE0 Orange
 0x79E0 Brown
 0x7E0  Green
 0x7FF  Cyan
 0x1F Blue
 0xF81F Pink
 */

}

i would like the middle round to stay stationary, and the blue and brown background to move as AHI moves.

for now i will settle for automated movement, and can integrate actual gyro data later.

Even with my current sketch, if you move DrawAHI() to main loop, in order to refresh it, it is very slow to refresh, probably about 1hz and that looks bad as it blinks and fills the screen top to bottom.
so im looking for faster ways to do it.

see:

i3dm:
i edited the .h file with my correct pin numbers, and tried all 5 tab options - none of them seems to work. i get a white screen in all of them.

Just checked the library and it works fine with a Mini Pro. The only other gotcha I can think of (apart from not using hardware SPI pins and an edit error in User_Setup) is that you are using a really old and outdated version of the IDE. You need to use the latest 1.6.x IDE

bodmer:
Just checked the library and it works fine with a Mini Pro. The only other gotcha I can think of (apart from not using hardware SPI pins and an edit error in User_Setup) is that you are using a really old and outdated version of the IDE. You need to use the latest 1.6.x IDE

im using the latest IDE version, perhaps you could run me through the connections? i cant find where the mistake is.

i would like to end up with something similar to this:

bodmer:
Just checked the library and it works fine with a Mini Pro. The only other gotcha I can think of (apart from not using hardware SPI pins and an edit error in User_Setup) is that you are using a really old and outdated version of the IDE. You need to use the latest 1.6.x IDE

managed to get library working, now could use a bit of help "translating" my code which uses the Adafruit Library, to yours :slight_smile:

bodmer, i changed my code to use your library but i still find it being slow.

here's what im trying to do and what happens:

  1. fill the background with grpahics.
  2. print a AH line on the existing filled screen at a certain angle.

now, in order to refresh (change line angle) i have to do:
3. fill the background with grpahics.
4. print a AH line on the existing filled screen at a certain (different) angle.

i guess the screen filling takes some time, because this causes a lot of flashing and delay in the screen.

any ideas how to do this quickly without the flashing and delays?
i did manage to print just the line, on a black ground, with a good refresh rate. but as soon as i add the background graphics, it all becomes slow.

Thanks for the video. A picture is worth a thousand words.
A moving picture is worth even more!

As far as I know, the ST7735 can not display a separate foreground and background.
Which means that updating the display is going to need some intelligence.

Either by redrawing each object that contains the "new" triangle.
Or by reading the GRAM and replacing the CYAN or GRAY in the new triangles. Reading GRAM with an AVR is relatively slow.

I can do it both ways but it is fiddly getting the graphics to match.
I will wait until Bodmer comes up with a better method.

David.