SC Cosplay: Help programming Arduino Uno to play GIFs?

DirectorGunner

Space Marshal
Officer
Donor
Sep 17, 2016
2,906
12,670
2,900
RSI Handle
DirectorGunner
Howdy,
I'm working on making the Heavy Marine as a personal cosplay project.
The two displays on the Torso I have been trying to find a reasonable solution to make it happen IRL.
I bought an Elegoo Arduino Uno and an Elegoo LCD TFT display

I'm trying to get this gif to run on the displays (for now, can do UI animations later in a new gif)

To try to save potential bandwidth, I reduced the gif to 32 colors.

Supposedly, even though Arduino Uno doesn't have enough SRAM to display a 320px by 240px video at a reasonable FPS... supposedly... based on the following video, it still can power a LCD to display gifs.

With the LCD's library (for the particular LCD I'm using)
https://mega.nz/#!gkJjSITL!G5nRTcXfnv2GIMAewIaHoDDw-fQ4GygO2IiwZ9SaYS4

I can display a sequence of BMPs easy enough but it doesn't look great as it draws each new BMP line by line rather slowly. Like the old days of downloading a large image on 56k dial up.
And I had to change the orientation... so this as it is could only barely work for the back facing LCD that's longer on the vertical pixels (240px x 320px). Instead of like the GIF I shared above which would be for the front side of the armor.


Code:
// IMPORTANT: ELEGOO_TFTLCD LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.
// SEE RELEVANT COMMENTS IN Elegoo_TFTLCD.h FOR SETUP.
//Technical support:[email protected]

#include <Elegoo_GFX.h>    // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <SD.h>
#include <SPI.h>


// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
// double up the pins with the touch screen (see the TFT paint example).
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define PIN_SD_CS 10 // Elegoo SD shields and modules: pin 10

#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

// When using the BREAKOUT BOARD only, use these 8 data lines to the LCD:
// For the Arduino Uno, Duemilanove, Diecimila, etc.:
//   D0 connects to digital pin 8  (Notice these are
//   D1 connects to digital pin 9   NOT in order!)
//   D2 connects to digital pin 2
//   D3 connects to digital pin 3
//   D4 connects to digital pin 4
//   D5 connects to digital pin 5
//   D6 connects to digital pin 6
//   D7 connects to digital pin 7
// For the Arduino Mega, use digital pins 22 through 29
// (on the 2-row header at the end of the board).

// Assign human-readable names to some common 16-bit color values:
#define    BLACK   0x0000
#define    BLUE    0x001F
#define    RED     0xF800
#define    GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
// If using the shield, all control and data lines are fixed, and
// a simpler declaration can optionally be used:
// Elegoo_TFTLCD tft;


#define MAX_BMP         10                      // bmp file num
#define FILENAME_LEN    20                      // max file name length

const int __Gnbmp_height = 240;                 // bmp hight
const int __Gnbmp_width  = 320;                 // bmp width

unsigned char __Gnbmp_image_offset  = 0;        // offset

int __Gnfile_num = 6;                           // num of file

char __Gsbmp_files[6][FILENAME_LEN] =           // add file name here
{
"test000.bmp",
"test004.bmp",
"test008.bmp",
"test012.bmp",
"test016.bmp",
"test020.bmp"
};
File bmpFile;

/*********************************************/
// This procedure reads a bitmap and draws it to the screen
// its sped up by reading many pixels worth of data at a time
// instead of just one pixel at a time. increading the buffer takes
// more RAM but makes the drawing a little faster. 20 pixels' worth
// is probably a good place

#define BUFFPIXEL       60                      // must be a divisor of 240
#define BUFFPIXEL_X3    180                     // BUFFPIXELx3

void bmpdraw(File f, int x, int y)
{
    bmpFile.seek(__Gnbmp_image_offset);

    uint32_t time = millis();

    uint8_t sdbuffer[BUFFPIXEL_X3];                 // 3 * pixels to buffer

    for (int i=0; i< __Gnbmp_height; i++) {
        for(int j=0; j<(240/BUFFPIXEL); j++) {
            bmpFile.read(sdbuffer, BUFFPIXEL_X3);
       
            uint8_t buffidx = 0;
            int offset_x = j*BUFFPIXEL;
            unsigned int __color[BUFFPIXEL];
       
            for(int k=0; k<BUFFPIXEL; k++) {
                __color[k] = sdbuffer[buffidx+2]>>3;                        // read
                __color[k] = __color[k]<<6 | (sdbuffer[buffidx+1]>>2);      // green
                __color[k] = __color[k]<<5 | (sdbuffer[buffidx+0]>>3);      // blue
           
                buffidx += 3;
            }

        for (int m = 0; m < BUFFPIXEL; m ++) {
              tft.drawPixel(m+offset_x, i,__color[m]);
        }
        }
    }

    Serial.print(millis() - time, DEC);
    Serial.println(" ms");
}

boolean bmpReadHeader(File f)
{
    // read header
    uint32_t tmp;
    uint8_t bmpDepth;

    if (read16(f) != 0x4D42) {
        // magic bytes missing
        return false;
    }

    // read file size
    tmp = read32(f);
    Serial.print("size 0x");
    Serial.println(tmp, HEX);

    // read and ignore creator bytes
    read32(f);

    __Gnbmp_image_offset = read32(f);
    Serial.print("offset ");
    Serial.println(__Gnbmp_image_offset, DEC);

    // read DIB header
    tmp = read32(f);
    Serial.print("header size ");
    Serial.println(tmp, DEC);

    int bmp_width = read32(f);
    int bmp_height = read32(f);

    if(bmp_width != __Gnbmp_width || bmp_height != __Gnbmp_height)  {    // if image is not 320x240, return false
        return false;
    }

    if (read16(f) != 1)
    return false;

    bmpDepth = read16(f);
    Serial.print("bitdepth ");
    Serial.println(bmpDepth, DEC);

    if (read32(f) != 0) {
        // compression not supported!
        return false;
    }

    Serial.print("compression ");
    Serial.println(tmp, DEC);

    return true;
}

/*********************************************/
// These read data from the SD card file and convert them to big endian
// (the data is stored in little endian format!)

// LITTLE ENDIAN!
uint16_t read16(File f)
{
    uint16_t d;
    uint8_t b;
    b = f.read();
    d = f.read();
    d <<= 8;
    d |= b;
    return d;
}

// LITTLE ENDIAN!
uint32_t read32(File f)
{
    uint32_t d;
    uint16_t b;

    b = read16(f);
    d = read16(f);
    d <<= 16;
    d |= b;
    return d;
}

void setup(void) {
  Serial.begin(9600);
  Serial.println(F("TFT LCD test"));

#ifdef USE_Elegoo_SHIELD_PINOUT
  Serial.println(F("Using Elegoo 2.4\" TFT Arduino Shield Pinout"));
#else
  Serial.println(F("Using Elegoo 2.4\" TFT Breakout Board Pinout"));
#endif

  Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());

  tft.reset();

  uint16_t identifier = tft.readID();

  if(identifier == 0x9325) {
    Serial.println(F("Found ILI9325 LCD driver"));
  } else if(identifier == 0x9328) {
    Serial.println(F("Found ILI9328 LCD driver"));
  } else if(identifier == 0x4535) {
    Serial.println(F("Found LGDP4535 LCD driver"));
  }else if(identifier == 0x7575) {
    Serial.println(F("Found HX8347G LCD driver"));
  } else if(identifier == 0x9341) {
    Serial.println(F("Found ILI9341 LCD driver"));
  } else if(identifier == 0x8357) {
    Serial.println(F("Found HX8357D LCD driver"));
  } else if(identifier==0x0101)
  { 
      identifier=0x9341;
       Serial.println(F("Found 0x9341 LCD driver"));
  }else {
    Serial.print(F("Unknown LCD driver chip: "));
    Serial.println(identifier, HEX);
    Serial.println(F("If using the Elegoo 2.8\" TFT Arduino shield, the line:"));
    Serial.println(F("  #define USE_Elegoo_SHIELD_PINOUT"));
    Serial.println(F("should appear in the library header (Elegoo_TFT.h)."));
    Serial.println(F("If using the breakout board, it should NOT be #defined!"));
    Serial.println(F("Also if using the breakout, double-check that all wiring"));
    Serial.println(F("matches the tutorial."));
    identifier=0x9341;

  }

  tft.begin(identifier);
  tft.fillScreen(BLUE);



  //Init SD_Card
  pinMode(10, OUTPUT);

  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
    tft.setCursor(0, 0);
    tft.setTextColor(WHITE);
    tft.setTextSize(1);
    tft.println("SD Card Init fail.");
  }else
  Serial.println("initialization done.");
}

void loop(void) {
     for(unsigned char i=0; i<__Gnfile_num; i++) {
        bmpFile = SD.open(__Gsbmp_files[i]);
        if (! bmpFile) {
            Serial.println("didnt find image");
            tft.setTextColor(WHITE);    tft.setTextSize(1);
            tft.println("didnt find BMPimage");
            //while (1);
        }

        if(! bmpReadHeader(bmpFile)) {
            Serial.println("bad bmp");
            tft.setTextColor(WHITE);    tft.setTextSize(1);
            tft.println("bad bmp");
            //return;
        }

        bmpdraw(bmpFile, 0, 0);
        bmpFile.close();
        delay(1000);
        delay(1000);
    }

}

Some related posts on the topic
http://forum.arduino.cc/index.php?topic=265354.0
http://www.avrfreaks.net/comment/2334081#comment-2334081
https://github.com/prenticedavid/MCUFRIEND_kbv
https://forum.arduino.cc/index.php?topic=359442.0
 
Last edited:
  • Like
Reactions: Sraika and Dalarast

Sraika

Space Marshal
Nov 7, 2017
2,750
10,555
2,860
RSI Handle
Sraika
this got far too technical for me, far too quickly. If you can make it work, though, it's gonna look bloody awesome. Send us a video when you're done?
 
  • Like
Reactions: DirectorGunner

DirectorGunner

Space Marshal
Officer
Donor
Sep 17, 2016
2,906
12,670
2,900
RSI Handle
DirectorGunner
I know nothing about coding the Arduino but looks like a fun project.

If you need more power maybe try one of these.

http://www.hardkernel.com/main/products/prdt_info.php?g_code=G143452239825
Thanks for the link!
Although if this doesn't work.. which is seems it might not as desired...
I'm thinking about just getting two sets of these, Raspberry Pi 3 with a 3.5 LCD HDMI display

or use a Pi Zero
At least this for sure would work and allow more options, at the cost of more space and more power usage... and a slightly higher price.

Edit:
For bookmarking so I don't lose it. Project part 2 is using the Heavy Marine HUD overlay for a live camera v2 feed through Pi Zero W to LCD display on Helmet Visor. Since goal is to have the helmet visor come down over the face like Judge Dredd, which I think was the original intention of that helmet. But even if it wasn't, It'll be fing badass. One problem is the sliding hinge mechanism.. trying to figure that one out.
 
Last edited:

Metal-Muffin

Space Marshal
Aug 28, 2015
684
1,944
1,510
RSI Handle
Metal-Muffin
This is using oled displays, but I think the library is adaptable for TFT/IPS displays. it’s a proof of concept to get you going in the right direction and deals specifically with animations and higher refresh rates. https://learn.adafruit.com/animated-electronic-eyes-using-teensy-3-1/overview

Edit: it may just be easier to use a Pi. Plus, you can add more functionality, and even add discord. If you have any lights or other fun stuff, they’d be just as easy to manipulate thru the GPIO as the arduino; e.g. touch a button on your display- turn on helmet light; touch another button- activate penis pump.... if you want, I even have a bare bones custom UI I’ve been working on that runs in python over raspian that I’m incorporating into my simpit. Be happy to shoot it over.
 
Last edited:
  • Like
Reactions: DirectorGunner

SilverGhost

Ensign
Feb 14, 2018
5
7
25
RSI Handle
SilverGhost
Hey! Cool to see such enthusiasm around the project.

The Youtube video you posted uses a 4D Systems screen, which has a Picaso advanced video processor, that's how it's able to play video fast enough, but it cost around 80 bucks, we are far from the 20 or 30 that an Elegoo costs. And closer to the price of a real TFT LCD with HDMI for a Raspberry Pi.

Basically the difference is easy to understand, the culprit in the current state of the project is the power of the Arduino, mostly the lack of SRAM, but more importantly the lack of a high bandwidth interface (i.e. HDMI). With your screen you are required to send raw pixel data to the screen, which as we computed yesterday means around 170kB per frame.

With a controller like the Picaso, all the arduino does is send a command to the screen saying "Display XXXX.bmp from SD Card" which is around 10 bytes long, then the screen processor handles it. Using that you could send the pixel data for the full image then send a command like 'Scroll up by 1 pixel' and it would work.

I'm confident it's possible to optimize the current setup to use less bits per pixel and thus manage to make it work faster, but unless there is a way to manually control the refresh, you will be stuck with seeing the screen draw line by line, and the Elegoo TFTLCD library REALLY lacks some documentation.

So yes, path of least resistance is a Pi 3 + HDMI. Maybe a Zero would be better suited but I have 0 experience with those.

Please note that the Pi3 have wifi which could make the project a lot more interesting, like one armor acting as AP, and others connecting on it, etc... possibilities becomes endless once you have a few wearable linux computers!

And the video processing with the Pi is well... easy as Pi :D It even have a builtin accelerator to display Full HD H264 video, for 35 bucks it's a bargain.
 

SilverGhost

Ensign
Feb 14, 2018
5
7
25
RSI Handle
SilverGhost
This is using oled displays, but I think the library is adaptable for TFT/IPS displays. it’s a proof of concept to get you going in the right direction and deals specifically with animations and higher refresh rates. https://learn.adafruit.com/animated-electronic-eyes-using-teensy-3-1/overview
Oh cool project! I didn't think at all about the Teensy board mainly because I didn't know about them more than their names, looks like it could be your solution DirectorGunner as those are 32bits Cortex ARM core 72 to 180MHz processor, they might have enough horsepower to drive any screen close to perfectly.

Compared to the measly 8bits AVR Core locked at 16MHz of the Arduino, that's a big improvement, and I believe the price range is in the same area.
 
  • Like
Reactions: DirectorGunner

DirectorGunner

Space Marshal
Officer
Donor
Sep 17, 2016
2,906
12,670
2,900
RSI Handle
DirectorGunner
Oh cool project! I didn't think at all about the Teensy board mainly because I didn't know about them more than their names, looks like it could be your solution DirectorGunner as those are 32bits Cortex ARM core 72 to 180MHz processor, they might have enough horsepower to drive any screen close to perfectly.

Compared to the measly 8bits AVR Core locked at 16MHz of the Arduino, that's a big improvement, and I believe the price range is in the same area.
Thank you @SilverGhost I went ahead and ordered a Pi3 B and a couple of Pi Zero W and the Noir V2 camera and two of these larger LCD displays shown above for the Pi. For the price, and effort to make work, seems like will be the best route. It's been hard finding a phablet quality display for the Pi, for backside of the visor something between 5 to 6 inches with a high pixel count would be fantastic. Any suggestions?
 

SilverGhost

Ensign
Feb 14, 2018
5
7
25
RSI Handle
SilverGhost
Just to be sure for the heavy marine helmet you want to close it completely and use the screen in front of your face+the camera for vision / night vision, right?

If so you need to make sure the latency between capture & display is really extremely low, otherwise, welcome nausea.

Regarding phablet quality display, the easiest thing is to find an old (still working) phablet, and do some android development, I mean, we are talking about high power wearable computers with crisp screens, and embedded batteries, so... :D

Honestly the PPI on phablet displays are overkill, unless you look at it with a magnifier you will be completely unable to identify individual pixels.

My sources for most electronic DIY projects are Adafruit and Sparkfun, and for more specific components stuff I like to use digikey.
 
  • Like
Reactions: DirectorGunner

DirectorGunner

Space Marshal
Officer
Donor
Sep 17, 2016
2,906
12,670
2,900
RSI Handle
DirectorGunner
So, just to recap: you want to use a phablet screen powered by a RasPi to overlay a display on top of video streamed from the Noir V2 camera?
For part 2, yes :3

And quick question to all,
Any ideas on a mechanism to allow the visor to slide down into place and back up when not wanted?
 
Last edited:

ThomSirveaux

Space Marshal
Sep 12, 2014
1,162
2,036
2,670
RSI Handle
Thom_Sirveaux
For part 2, yes :3
And this will be used as a personal HUD? So, no other way to see outside than the screen, itself?

If yes, do a quick test: take your phone and turn on the camera; next, hold it as close to your face as possible so you can actually see what the camera is showing. Unless you're planning on incorporating some sort of Google Cardboard lenses into the system, that's how far away the phone would need to be, lest you go crosseyed and get serious vertigo from staring at a screen that close to your eyes.

And quick question to all,
Any ideas on a mechanism to allow the visor to slide down into place and back up when not wanted?
Servos with piano wire should allow easy movement forward and back. If you have a specific animation you can show, I might be able to provide further details, as well as a proposed four-bar linkage, if need be. Depending on how heavy it is, a microservo should be fine with the four-bar.
 
  • Like
Reactions: DirectorGunner

DirectorGunner

Space Marshal
Officer
Donor
Sep 17, 2016
2,906
12,670
2,900
RSI Handle
DirectorGunner
Hey @DirectorGunner you got your raspberry pi now for your scrolling display, did you make that work yet? Otherwise I can write a simple program in C to make the display show what you wanted, both horizontally and vertically ;)
I got the display working! I'm working on creating/rendering a video for better motion graphic quality, yea anything that could play the video on a loop either horizontally or vertically would be fantastic! Is there a way to prevent accidental stopping the video from the touch screen being touched?


And this will be used as a personal HUD? So, no other way to see outside than the screen, itself?

If yes, do a quick test: take your phone and turn on the camera; next, hold it as close to your face as possible so you can actually see what the camera is showing. Unless you're planning on incorporating some sort of Google Cardboard lenses into the system, that's how far away the phone would need to be, lest you go crosseyed and get serious vertigo from staring at a screen that close to your eyes.



Servos with piano wire should allow easy movement forward and back. If you have a specific animation you can show, I might be able to provide further details, as well as a proposed four-bar linkage, if need be. Depending on how heavy it is, a microservo should be fine with the four-bar.
I talked with my Uncle who's an engineer. The cheapest options are 1) pneumatic double action actuators with a 4 post pivot or 2) curved rack gears with a DC motor pinion and 2 rollers.
So.. after looking at the options... 3D printing a curved rack gear system would be best. Looking into it now, should have design figured out within a few days.
 
Last edited:

SilverGhost

Ensign
Feb 14, 2018
5
7
25
RSI Handle
SilverGhost
I got the display working! I'm working on creating/rendering a video for better motion graphic quality, yea anything that could play the video on a loop either horizontally or vertically would be fantastic! Is there a way to prevent accidental stopping the video from the touch screen being touched?
Video would be a way, but you will lose quality, I'd make a simple looping program for you with a lot of customization options.

Can you please just confirm the distribution you are using on the PI? Thanks.
 
  • Like
Reactions: DirectorGunner

DirectorGunner

Space Marshal
Officer
Donor
Sep 17, 2016
2,906
12,670
2,900
RSI Handle
DirectorGunner
I just found out Disco Lando responded to my tweet!! Wha wha what??!!!!

https://twitter.com/DavidAELevy/status/966039675184926720

So here's the working raspi torso rear display :P

I've also fixed the incorrect readings on vitals for the final integrity check.

Yea it's a Raspi Zero W for the Torso displays @SilverGhost , and if it fits I'll be using a Raspi 3 B board for inside the visor with a 3.5 inch display as that's the max that will fit due to the inside curvature of the visor.
 
Last edited:
Forgot your password?