3D Accelerometer Portrait

Views:4747Difficulty: 5 Status: Deprecated
Screen_shot_2013-03-07_at_7.35.57_pm

3d view of a face using an SD card, accelerometer and a TFT LCD Screen

Mapping an accelerometer to a set of images of a face taken from all angles, we create something like a 3D picture frame. As you turn the PCB in space the face displayed on the screen seems to turn in response, as if you are looking at someone from different vantage points. The images are stored on a micro SD Card . We also use the TFT LCD Screen available at adafruit . The PCB has a silkscreened frame from our EAGLE bitmap library .

Pinch corner

Screen_shot_2013-03-07_at_7.35.57_pm
Looking up and to the right

3D Accelerometer Face

As the PCB is held in different orientations the screen displays different views of the face. It as if there is a little 3D person inside the circuit, and the screen is not a screen but a window!

Arduino Code

We use the ST7735 library from adafruit , as well as the SPI Arduino library to communicate with the SPI devices (screen and SD card) and the Arduino SD library as well. This code listens to the x and y values coming from the accelerometer. The critical code is here:
String img2 = "fs_";    img2 += String(x_index);    img2 += String(y_index);    img2 += ".bmp";    char  img2c[10] ;    for(int ii = 0; ii < 9; ii++){      img2c[ii] = img2.charAt(ii);    }    img2c[9] = 0;    open_file(img2c,file_pos);
We take the normalized x and y values from the accelerometer and use them to choose an image from a set of bitmaps stored on the SD card. The images have names like "fs_XY.bmp" where X is a number between 0 and 6 and y is a number between o and 4. Each of these numbers corrseponds to different points of view of the face along the horizontal and vertical axes.
Download File
/* LucidTronix 3D Accelerometer Picture Frame  * For instructions, details and schematic, See: * http://www.lucidtronix.com/tutorials/31 * Uses the adafruit st7735 library * calibrates the accelerometer readings */#include #include #include // If we are using the hardware SPI interface, these are the pins (for future ref)#define sclk 13#define mosi 11// You can also just connect the reset pin to +5V (we do a software reset)#define rst 8// these pins are required#define cs 10#define dc 9// Color definitions#defineBLACK           0x0000#defineBLUE            0x001F#defineRED             0xF800#defineGREEN           0x07E0#define CYAN            0x07FF#define MAGENTA         0xF81F#define YELLOW          0xFFE0  #define WHITE           0xFFFF// For Arduino Uno/Duemilanove, etc//  connect the SD card with MOSI going to pin 11, MISO going to pin 12 and SCK going to pin 13 (standard)//  Then pin 4 goes to CS (or whatever you have set up)#define SD_CS 4    // Set the chip select line to whatever you use (4 doesnt conflict with the library)// to draw images from the SD card, we will share the hardware SPI interfaceST7735 tft = ST7735(cs, dc, rst);// the file itselfFile bmpFile1;// information we extract about the bitmap fileint bmpWidth, bmpHeight;uint8_t bmpDepth, bmpImageoffset;int btn1 = 1;int btn0  = 0;int cur_h = 1;int cur_v = 1;int sensor_maxx = 0;int sensor_minx = 1024;int sensor_maxy = 0;int sensor_miny = 1024;int old_x = 0;int old_y = 0;boolean change_img = false;void setup(void) {  //Serial.begin(9600);     pinMode(cs, OUTPUT);  digitalWrite(cs, HIGH);       // initialize a ST7735R TFT  tft.initR();      // change this to initB() for ST7735B TFT's  // Just do a simple test  tft.writecommand(ST7735_DISPON);  tft.fillScreen(WHITE);  delay(200);  tft.drawString(10,20,"Gyro setup..." , GREEN);  tft.drawString(12,22, "Try SD" ,BLUE);  if (!SD.begin(SD_CS)) {    tft.drawString(12,42, "SD Failed" ,RED);    return;  }  tft.drawString(12,42, "SD Good" ,BLUE);    delay(500);  pinMode(btn0,INPUT);  pinMode(btn1,INPUT);  tft.fillScreen(BLACK);    bmp_load_and_draw_image("frame.bmp",0,0);  bmp_load_and_draw_image("fs_00.bmp",40,50);  delay (1000);  change_img = true;}void loop() {  bmpdraw(40,50);}void open_file(char * filename, unsigned int file_pos){  bmpFile1.close();  delay(20);  bmpFile1 = SD.open(filename);  delay(20);  bmpFile1.seek(0);  bmpFile1.seek(file_pos);  if (!bmpFile1) {    tft.drawString(12,62, "Coodn't open image" ,RED);    return;  }}  void bmp_load_and_draw_image(char* filename, int ax, int ay) {  bmpFile1 = SD.open(filename);  if (!bmpFile1) {    tft.drawString(12,62, "Coodn't find image" ,RED);        return;  }    if (!bmpReadHeader(bmpFile1)) {      tft.drawString(12,82, "Bad image" ,RED);     return;  }  tft.drawString(12,102, "Try 2 draw image" ,GREEN);  bmpdraw( ax, ay);  //bmpFile1.close();}/*********************************************/// 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 20void bmpdraw(int x, int y) {  bmpFile1.seek(bmpImageoffset);  unsigned int file_pos = bmpImageoffset;  uint32_t time = millis();  uint16_t p;   uint8_t g, b;  int i, j;    uint8_t sdbuffer[3 * BUFFPIXEL];  // 3 * pixels to buffer  uint8_t buffidx = 3*BUFFPIXEL;  if ( change_img ) check_acc_data(file_pos);  for (i=0; i< bmpHeight; i++) {    // bitmaps are stored with the BOTTOM line first so we have to move 'up'       for (j=0; j= 3*BUFFPIXEL) {           bmpFile1.read(sdbuffer, 3*BUFFPIXEL);        buffidx = 0;                }          // convert pixel from 888 to 565      b = sdbuffer[buffidx++];     // blue      g = sdbuffer[buffidx++];     // green      p = sdbuffer[buffidx++];     // red           file_pos += 3;            p >>= 3;      p <<= 6;            g >>= 2;      p |= g;      p <<= 5;            b >>= 3;      p |= b;      tft.drawPixel(x+j, y+i, p);    }      }}boolean bmpReadHeader(File f) {   // read header  uint32_t tmp;  f.seek(0);  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);    bmpImageoffset = read32(f);   //Serial.print("offset "); Serial.println(bmpImageoffset, DEC);    // read DIB header  tmp = read32(f);  //Serial.print("header size "); Serial.println(tmp, DEC);  bmpWidth = read32(f);  bmpHeight = read32(f);  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 check_acc_data(unsigned int file_pos){  int ax = analogRead(1);  int ay = analogRead(0);  if ( ay > sensor_maxy) sensor_maxy = ay;  if ( ay < sensor_miny ) sensor_miny = ay;  if ( ax > sensor_maxx) sensor_maxx = ax;  if ( ax < sensor_minx ) sensor_minx = ax;  float y_adjust = ay - sensor_miny;  float ratioy = y_adjust / (float)(1+sensor_maxy-sensor_miny);  float x_adjust = ax - sensor_minx;  float ratiox = x_adjust / (float)(1+sensor_maxx-sensor_minx);  int x_index = (int)(ratiox*6.0);  int y_index = (int)(ratioy*4.0);  boolean changed = false;    if ( x_index != old_x || y_index != old_y ){    String img2 = "fs_";    img2 += String(x_index);    img2 += String(y_index);    img2 += ".bmp";    char  img2c[10] ;    for(int ii = 0; ii < 9; ii++){      img2c[ii] = img2.charAt(ii);    }    img2c[9] = 0;    open_file(img2c,file_pos);    old_y = y_index;    old_x = x_index;  }}

Parts

Title Description # Cost Link Picture
HSB Joy PCB PCB controls a screen, thermal printer, joystick and SD card 1 $11.95 Link Screen_shot_2013-03-01_at_7.31.39_pm
SD Card (micro 4GB) MicroSD Card 4GB with full-size SD card adapterValue:4GB 1 $5.35 Link Microsd4gb
microSD Card Connector Secure Digital - microSD™ Push In, Push OutValue: microSD 1 $3.44 Link
Accelerometer ±4g, 9gValue:X, Y 1 $3.22 Link Screen_shot_2012-12-28_at_7.34.36_pm
ATMEGA328P-AU Integrated Circuits (ICs) MCU AVR 32K FLASH 32TQFPValue:1.8 V ~ 5.5 V 20MHz 1 $3.05 Link Screen_shot_2012-12-28_at_7.31.33_pm
USB connector USB Mini type BValue:female 1 $0.68 Link Usb-m26ftr
Crystal CRYSTAL 16.00000 MHZ 20PF SMDValue:16MHz 1 $0.53 Link Ecs-270-20-3x-en-tr
CD4050 IC BUFF/CONVERTER HEX 16SOICN 8mA, 48mAValue: 3 V ~ 18 V 1 $0.45 Link 16-soic_(7.5mmwidth)
Capacitor CAP CER 0.1UF 50V Y5V 0805Value:0.1µF 4 $0.1 Link 0805(6_0mm_thickness)
Resistor Chip Resistor - Surface Mount RES 10K OHM 1/8W 5% 0805 SMDValue: 10k 4 $0.1 Link Screen_shot_2012-12-28_at_7.29.44_pm

    Comments:

Permalink: http://lucidtronix.com/tutorials/31

Tutorials

Print bitmaps, cellular automata, drawings and text.....
Mixing pixels from two face images together....
Our take on the classic bouncing ball, paddle game....
Display bitmap images and text files and folders with this TFT LCD screen and SD Card navigator....
Play pong on a little LCD screen with two big joysticks....
The Wearable Wayfinder is a totally programmable, beautiful little computer for your wrist packed wit...
Control the hue, value and saturation on this pocket-sized joystick drawing machine....
Coupling the HMC5883L Compass with our color library turns the Wearable Wayfinder into a handy naviga...