Final Project: Shikumen Time Machine

Final Result

This is a cultural and creative installation dedicated to preserving the traditional culture of Shikumen in Shanghai.

Shikumen carries the warm memories of many older generations of Shanghainese. It is also one of the symbols of Shanghai's modern urban civilization. I want this installation to be a captivating toy for kids. The idea is to spark children's interest with its visual appeal, motion, and lights.

Hero Shots


The exterior is designed to resemble the ruins of a Shikumen from the year 1920. By inserting life scene cards into the courtyard, colorful lights can be activated, bringing new life to the past Shikumen.


          Scene Cards              Look Inside the Door              Top View

Idea and Sketch

I have launched an outdoor experiential learning course, taking children to explore traditional residential architecture in Shanghai - Shikumen. In the course, I introduce how people used to live in Shikumen buildings, as well as how Shikumen has been transformed and repurposed in contemporary times. Since they cannot see the authentic Shikumen courtyards during the visits, I aim to create an installation to help them understand this space better and learn how the people in the past utilized the courtyards in Shikumen houses.

The reason why the Shikumen building in Shanghai is called "Shikumen" is because of its beautiful entrance gate. The gate is adorned with beautiful stone carvings on the lintel, leaving a profound impression on people. Therefore, the building is referred to by the name of its grand entrance gate - "Shikumen." So, the first thing this installation needs to showcase is the beautiful gate. I've decided to use 3D printing technology to create this model. The space below the lintel is suitable for placing an LCD screen, resembling a nameplate and providing a perfect combination.

As for the surrounding walls, I've decided to use laser cutting to showcase the texture of bricks and beautiful Chinese-style lattice windows. The historical life scene cards inside are designed in a paper-cut style, and laser cutting can effectively achieve this effect. On the base, I will design three slots, each containing an LED strip and a magnetic sensor. Children will need to insert the cards into the correct slot according to my description. If inserted correctly, the magnetic sensor will detect the magnet and illuminate the LED strip. Once all the LED strips are lit, their task is complete.

Rough Sketches

3D Model

Below you can see the 3D model of my idea. In the model, the primary focus is on determining the form and structure of the door, and it is directly imported into slicing software for 3D printing. For the walls and the base, the main consideration is to determine the dimensions, making it convenient to draw 2D graphics for laser cutting.

Modeling in Fusion 360

The modeling process is mainly divided into the following steps:

  1. Sketch the design in AutoCAD, then import the DXF file into Fusion 360.
  2. Use the "extrude" command to create the main form.
  3. Refine the position of the door axis and the structure in coordination with the electronics.
  4. Modeling to determine the dimensions of the outer walls.

[Files]

Sketch - dxf file3D model - f3d file

Shikumen 3D Printing

I chose a matte finish PLA filament for the 3D printing of the gate, aiming for a texture closer to stone. The printing parameters are as follows:

Since the automatically generated tree supports are very thin, it's crucial to apply some glue to the print bed. Without this, the supports may loosen and shift during the printing process, leading to a failed print.


During testing, the lack of glue caused the supports to loosen, resulting in failure.

After completing the print, I noticed that the nozzle temperature of 210°C was not quite sufficient. There were some signs of under-extrusion on the surface. The 3D printer I used, the Bambu P1P, has a fast printing speed, requiring a higher temperature to ensure smooth extrusion of the filament from the nozzle. For a more perfect surface finish, increasing the nozzle temperature to 230°C is more suitable. However, the slightly under-extruded effect on the surface happened to create a mottled texture, coincidentally achieving the effect I desired. A pleasant surprise.

[Files]

Shikumen Slicing - 3mf file

2D Design

The Walls
During the modeling process in Fusion 360, I noticed that creating complete walls would result in a very enclosed internal space, making it difficult to see the interior scenes from the front. Therefore, during the 2D design phase in AutoCAD, I modified the front and two sides of the walls to appear as broken and crumbling. This not only allows for a more complete display of the internal scenes but also aligns with the theme of a time machine, creating a story of traveling to the past within the ruins of an old Shikumen.

The Scene Cards
The design of the scene cards drew inspiration from the paper-cut works of the artist Li Shoubai . I extracted characters and scenes from his Shikumen series, collaging and reconstructing them in Photoshop. Using three cards, the scenes depict children playing in the Shikumen courtyard, taking a break in the afternoon, hanging laundry, and cultivating flowers and plants, capturing various aspects of life in the Shikumen courtyard.

After exporting the three images from Photoshop, importing them into Inkscape for image tracing, and adjusting them to the correct dimensions, you will obtain vector files suitable for laser cutting.

[Files]

Walls - dxf fileScene Card 1 - dxf fileScene Card 2 - dxf fileScene Card 3 - dxf file

Laser Cutting

3mm Plywood
I generated a basic box on the MakerCase website and set a kerf of 0.1mm based on previous tests. I imported the generated DXF file into AutoCAD to draw the openings for the light slot and button. Afterward, I configured the cutting parameters in Laserbox.
For 3mm wooden board


        MakerCase                      Laser Cutting                    Laser Engraving

2mm Acrylic
The scene cards are sandwiched between two acrylic boards and a cardboard sheet, so each scene card needs to be cut three times. Subsequently, magnets are installed on the two acrylic boards to securely hold the cardboard sheet in the middle.The following are the cutting parameters for a 2mm acrylic board:


              Laser Cutting                                    Laser Engraving

0.5mm Cardboard
The following are the cutting parameters for a Cardboard:


              Laser Cutting                               Video of Laser Cutting

PCB Design and Production

PCB design is documented in Week06 and production in Week08.

Below is a table with the components used:

PartValueDevicePackageDescription
XIAO10201038814PIN_600MIL-SMD10201038814PIN_600MIL-SMD14PIN_SMD-600MIL
PINS1PINHD-1X7/901X07/90PIN HEADER
PINS2PINHD-1X4/901X04/90PIN HEADER
R1499 ohmRES-US1206FABR1206FABResistor (US Symbol)
R21k ohmRES-US1206FABR1206FABResistor (US Symbol)
S16MM_SWITCH6MM_SWITCH6MM_SWITCHOMRON SWITCH
SUPPLYPINHD-2X3-SMD2X03SMDPIN HEADER
U$1LEDFAB1206LEDFAB1206LED1206FABLED

Programming

First, I tested each function separately.

1. LCD Screen: Pressing the button, the LCD screen displays "Welcome to SHIKUMEN 1920."


        #include "DFRobot_RGBLCD1602.h"

        DFRobot_RGBLCD1602 lcd(/*RGBAddr*/ 0x60, /*lcdCols*/ 16, /*lcdRows*/ 2);  //16 characters and 2 lines of show

        //Button
        int buttonPin = D7;
        int buttonState;
        int lastButtonState = LOW;
        long lastDebounceTime = 0;
        long debounceDelay = 50;

        void breath(unsigned char color) {
          for (int i = 30; i < 255; i++) {
            lcd.setPWM(color, i);
            delay(1);
          }

          delay(500);
          for (int i = 254; i >= 30; i--) {
            lcd.setPWM(color, i);
            delay(1);
          }

          delay(500);
        }

        void setup() {
          // initialize
          lcd.init();
          pinMode(buttonPin, OUTPUT);
        }

        void loop() {
          // Print a message to the LCD.
          int reading = digitalRead(buttonPin);
          if (reading != lastButtonState) {
            lastDebounceTime = millis();
          }

          if ((millis() - lastDebounceTime) > debounceDelay) {
            if (reading != buttonState) {
              buttonState = reading;
              if (buttonState == HIGH) {
                lcd.clear();
                lcd.setCursor(3, 0);
                lcd.print("Welcome to");
                lcd.setCursor(1, 1);
                lcd.print("SHIKUMEN 1920");
              }
            }
          }
          lastButtonState = reading;
          breath(lcd.REG_ONLY);
        }
      

2. Servos: Pressing the button, the servo motor opens the two doors.


        #include 
          Servo leftdoor;
          Servo rightdoor;
          int pos = 0;
          int doorState = 0;

          //button
          int buttonPin = D7;
          int buttonState ;
          int lastButtonState = LOW;
          long lastDebounceTime = 0;
          long debounceDelay = 50;

          void setup() {
            //servo
            leftdoor.attach(D1, 544, 2400);
            rightdoor.attach(D0, 544, 2400);
            leftdoor.write(0);
            rightdoor.write(180);

            //button
            pinMode(buttonPin, INPUT);
          }

          void loop() {

            int reading = digitalRead(buttonPin);

            if (reading != lastButtonState) {
              lastDebounceTime = millis();
            }

            if ((millis() - lastDebounceTime) > debounceDelay) {
              if (reading != buttonState) {
                buttonState = reading;

                if (buttonState == HIGH) {

                  if (doorState == 0) {
                    for (pos = 0; pos <= 100; pos += 1) {  //open
                      leftdoor.write(pos);
                      rightdoor.write(180 - pos);
                      delay(15);
                    }
                    doorState = 1;
                  } else {

                    for (pos = 100; pos >= 0; pos -= 1) {  //close
                      leftdoor.write(pos);
                      rightdoor.write(180 - pos);
                      delay(15);
                    }
                    doorState = 0;
                  }
                }
              }
            }
            lastButtonState = reading;
          }
      

3. LED Strip: When the magnetic sensor detects the magnet, the corresponding LED lights up.


        //magnetic sensor
          int magnetic_1 = D8;
          int val_1 = 0;

          int magnetic_2 = D9;
          int val_2 = 0;

          int magnetic_3 = D10;
          int val_3 = 0;

          //LED strip
          #include 
          #define LED_PIN D3
          #define NUM_LEDS 60
          CRGB leds[NUM_LEDS];

          void setup() {
            //meganetic sensor
            pinMode(magnetic_1, INPUT);

            //led
            FastLED.addLeds(leds, NUM_LEDS);
          }

          void loop() {
            val_1 = digitalRead(magnetic_1);
            if (val_1 == LOW) {
              for (int i = 0; i < 20; i++) {  // turn LED ON
                leds[i] = CRGB(150, 150, 255);
              }
              FastLED.show();
              Serial.println("Magnetic Sensor is Attracted.");
            } else {
              for (int i = 0; i < 20; i++) {  // turn LED off
                leds[i] = CRGB::Black;
              }
              FastLED.show();
              Serial.println("No Magnetic");
            }

            val_2 = digitalRead(magnetic_2);
            if (val_2 == LOW) {
              for (int i = 20; i < 40; i++) {  // turn LED ON
                leds[i] = CRGB(50, 150, 200);
              }
              FastLED.show();
            } else {
              for (int i = 20; i < 40; i++) {  // turn LED off
                leds[i] = CRGB::Black;
              }
              FastLED.show();
            }

            val_3 = digitalRead(magnetic_3);
            if (val_3 == LOW) {
              for (int i = 40; i < 60; i++) {
                leds[i] = CRGB(0, 50, 255);
              }
              FastLED.show();
            } else {
              for (int i = 40; i < 60; i++) {
                leds[i] = CRGB::Black;
              }
              FastLED.show();
            }
          }
        

Finally, merge all the code and debug.


        //LCD Screen
        #include "DFRobot_RGBLCD1602.h"
        DFRobot_RGBLCD1602 lcd(/*RGBAddr*/ 0x60, /*lcdCols*/ 16, /*lcdRows*/ 2);  //16 characters and 2 lines of show

        //Servo
        #include 
        Servo leftdoor;
        Servo rightdoor;
        int pos = 0;
        int doorState = 0;

        //button
        int buttonPin = D7;
        int buttonState ;
        int lastButtonState = LOW;
        long lastDebounceTime = 0;
        long debounceDelay = 50;

        //meganetic sensor
        int magnetic_1 = D8;
        int val_1 = 0;

        int magnetic_2 = D9;
        int val_2 = 0;

        int magnetic_3 = D10;
        int val_3 = 0;

        //LED strip
        #include 
        #define LED_PIN D3
        #define NUM_LEDS 60
        CRGB leds[NUM_LEDS];

        void setup() {
          //lcd screen
          lcd.init();
          lcd.clear();

          //servo
          leftdoor.attach(D1, 544, 2400);
          rightdoor.attach(D0, 544, 2400);
          leftdoor.write(0);
          rightdoor.write(180);

          //button
          pinMode(buttonPin, INPUT);

          //meganetic sensor
          pinMode(magnetic_1, INPUT);

          //led
          FastLED.addLeds(leds, NUM_LEDS);

        }


        void loop() {

          int reading = digitalRead(buttonPin);

          if (reading != lastButtonState) {
            lastDebounceTime = millis();
          }

          if ((millis() - lastDebounceTime) > debounceDelay) {
            if (reading != buttonState) {
              buttonState = reading;

              if (buttonState == HIGH) {

                if (doorState == 0) {
                  lcd.init();  //screen showcase
                  lcd.setCursor(3, 0);
                  lcd.print("Welcome to");
                  lcd.setCursor(1, 1);
                  lcd.print("SHIKUMEN 1920");
                  for (pos = 0; pos <= 100; pos += 1) {  //open the door
                    leftdoor.write(pos);
                    rightdoor.write(180 - pos);
                    delay(15);
                  }
                  doorState = 1;
                } else {
                  lcd.init();  //screen showcase
                  lcd.setCursor(5, 0);
                  lcd.print("Thanks");
                  lcd.setCursor(1, 1);
                  lcd.print("for visiting");

                  for (pos = 100; pos >= 0; pos -= 1) {  //close the door
                    leftdoor.write(pos);
                    rightdoor.write(180 - pos);
                    delay(15);
                  }
                  doorState = 0;
                }
              }
            }
          }
          lastButtonState = reading;

          //megnetic sensors
          val_1 = digitalRead(magnetic_1);
          if (val_1 == LOW) {
            for (int i = 0; i < 20; i++) {  // turn LED ON
              leds[i] = CRGB(150, 150, 255);
            }
            FastLED.show();
            Serial.println("Magnetic Sensor is Attracted.");
          } else {
            for (int i = 0; i < 20; i++) {  // turn LED off
              leds[i] = CRGB::Black;
            }
            FastLED.show();
            Serial.println("No Magnetic");
          }

          val_2 = digitalRead(magnetic_2);
          if (val_2 == LOW) {
            for (int i = 20; i < 40; i++) {  // turn LED ON
              leds[i] = CRGB(50, 150, 200);
            }
            FastLED.show();
          } else {
            for (int i = 20; i < 40; i++) {  // turn LED off
              leds[i] = CRGB::Black;
            }
            FastLED.show();
          }

          val_3 = digitalRead(magnetic_3);
          if (val_3 == LOW) {
            for (int i = 40; i < 60; i++) {
              leds[i] = CRGB(0, 50, 255);
            }
            FastLED.show();
          } else {
            for (int i = 40; i < 60; i++) {
              leds[i] = CRGB::Black;
            }
            FastLED.show();
          }
        }

      

Bill of Materials

 Components  Quantilty  Price P.P.  Shop  Notes 
 PLA Filament  93g  7 rmb  Taobao  75 rmb per kg 
 3mm plywood board  30*45mm*6   48 rmb  Taobao 
 2mm Acrylic  30*45mm*5   150 rmb  Shop in Tongji University 
 Cardboard  A3*3   6 rmb  Taobao 
 Seeed XIAO  1   --   --  Provided by FabLab Formshop
 Button  1   --   --  Provided by FabLab Formshop
 Magnetic Sensor  3   --   --  Provided by FabLab Formshop
 LED Strip  1 meter with 60 leds   12.5 rmb   Taobao  
 Servo  2   --   --  Provided by FabLab Formshop
 LCD  1   --   --  Provided by FabLab Formshop
 Magnetic  27   --   --  Provided by FabLab Formshop