Skip to content

Final Project#

Rough Sketch#

Overview#

  • Upon graduation, you receive a certificate. But I wanted something more physical that could remain as a lasting memory.

Idea#

  • A memorial trophy to remind you of Fab Academy 2025 @ Node Kannai

Features#

Basic Requirements#

  • Easily recall what was done in the weekly assignments.

Basic Functions#

  • The trophy part is made of acrylic, engraved with “Fab Academy 2025 @ Kannai” and the participant’s name using a laser.
  • The base is equipped with an OLED display.
  • The base is made using a 3D printer.
  • Sliding the trophy part detaches it from the base, allowing maintenance of the circuit board.
  • Pressing a switch causes the trophy to light up.
  • The bottom of the base features a plywood puzzle piece branded with a QR code that links to the 2025 Kannai page.

Advanced Requirements#

  • Personal Fab Academy
  • Along with memories, it automatically generates new challenges to take on and creates a personal page for them.
  • The Fab Trophy will function as your own Personal Fab Academy, continuously generating new assignments to boost your creativity.
  • While the original Fab Academy provided weekly assignments with strict deadlines, the assignments in the Personal Fab Academy come with no submission deadline.

Note

The idea that constraints enhance creativity was proposed by Professor Teresa M. Amabile of Harvard Business School.
In her “Componential Theory of Creativity,” she states that creativity arises from the interaction of an individual’s abilities, motivation, and environmental factors.
Notably, it has been shown that when constraints are ** appropriately set, they can promote creative thinking.**

Advanced Functions#

  • Pressing a switch generates a challenge by combining assignments using an LLM and pushes it to each participant’s designated page.
  • The difficulty level can be changed using a rotary switch.
  • When a new challenge is created, a notification appears on the OLED, and a QR code to the page is displayed.
  • The trophy includes a hologram feature, and pressing the switch projects memories as a hologram.
  • When all four trophies are collected, they combine into one.

System Integration#

system integration’s infomation is here

System Requirements for Basic Functions#

System Configuration for Basic Functions#

System Configuration for Advanced Functions#

Project Tasks#

Project Category Task Start Date End Date Days
Basic Design Design of trophy structure and slide mechanism 2025-05-11 2025-05-13 2
Basic Design Design of veneer QR puzzle 2025-05-13 2025-05-14 1
Basic Fabrication Acrylic cutting and engraving 2025-05-14 2025-05-15 1
Basic Fabrication 3D printing of the base 2025-05-15 2025-05-16 1
Basic Fabrication Veneer processing for QR code 2025-05-16 2025-05-17 1
Basic Fabrication Implementation of sliding mechanism 2025-05-17 2025-05-18 1
Basic Electronics Implementation of LED lighting circuit 2025-05-18 2025-05-19 1
Basic Electronics Display QR code for kannai page on OLED 2025-05-19 2025-05-20 1
Basic Electronics USB power wiring and testing 2025-05-20 2025-05-21 1
Advanced Documentation Basic system diagram and fabrication record 2025-05-21 2025-05-22 1
Advanced LLM Selection and build of LLM for XIAO ESP32S 2025-05-22 2025-05-25 3
Advanced LLM Implementation of prompt and difficulty settings for task generation 2025-05-25 2025-05-26 1
Advanced LLM Integration with GitLab (Push) 2025-05-26 2025-05-27 1
Advanced LLM OLED notification and GitLab QR code generation 2025-05-27 2025-05-28 1
Advanced Hologram Optimization of OLED and acrylic reflection 2025-05-28 2025-05-31 3
Advanced Combination Mechanism Design and adjustment of divided kannai structure 2025-05-31 2025-06-01 1
Advanced Documentation Documentation of LLM integration 2025-06-01 2025-06-02 1
Advanced Video Production Creation of presentation video 2025-06-02 2025-06-05 3

Iteration 1: Implementing basic features#

Iter1-1. Modeling#

Create modeling with Fusion

Iter1-2. Laser cutting acrylic#

Iter1-3. Coloring the acrylic#

Iter1-4. Test connecter parameter#

In order to find the parameters that would allow for a proper connection between the acrylic and the base, we modeled the connection with different parameters, printed it out with a 3D printer, and tested to see if it would actually fit.

The parameter range is shown in the following image.

As a result of the actual connect, the joint clearance parameter was found to be 0.03 mm, which is appropriate.

The clearances found in this test were reflected in the model parameters.

Iter1-5. how to 3d printing#

DL the stl file from fusion and create the data for printing in bambu studio.

  1. load the data. You can load the data by clicking the cube symbol on the left end of the toolbar above. Select “split to object” surrounded by a red square in the following image to separate the object.
  2. have the objects separated by “range all objects” be organized in an appropriate manner.
  3. select “cut” to break up complex objects. This will reduce overhangs and bridge distances and reduce the probability of spaghetti. In this case, we have set up the following image.
  4. select “range all obujects” again and organize the objects again.
  5. select “auto orient” to have the object placed in the most efficient orientation.
  6. use “support painting” to paint the inevitable overhangs.
  7. create a slice plate with “slice plate” in the upper right corner. If the slice plate is in good condition, you can print by selecting “print plate” at the top right corner.

3D Printer Printing Time Lapse

The following image shows the printed result.

Iter1-6. PCB design#

Create schematics and PCB.

Once the PCB design was complete, the exported PNG file was uploaded to Mods to create gcode data.

Drills are used to cut copper plates.

Soldering was done.

Iter1-7. システムインテグレート&プロトタイプチェック#

Iteration 2: Implementing advanced features & Reproduction#

Iter2-1. gemini api keyを発行する#

Iter2-2. issue a gitlab api token#

  1. Set up the following flow in gitlab.
    • User Settings > Preferences > Access tokens > add new token
  2. set up and issue TOKEN as shown in the image.

  3. Please use the curl command to check if it is actually available.The following command will push test.md to the docs > personal fab academy directory of your project.

if you use this curl commands , you should change those parameters

  • When using the curl command, please modify the following two parts to your own information.
    1. {your_pj_id} in the url, the id number can be found in the image below.
    2. header {yourtoken}. Enter the aforementioned api token.
gitlab curl push command
curl --request POST "https://gitlab.fabcloud.org/api/v4/projects/{your_pj_id}/repository/files/docs%2Fpersonal%20fab%20academy%2Ftest.md" \
--header "PRIVATE-TOKEN:{yourtoken}" \
--header "Content-Type: application/json" \
--data '{
  "branch": "main",
  "content": "# Test\nThis is a test file created via GitLab API.",
  "commit_message": "Initial commit of test.md"
}'

Iter2-3. Generate QR code and display on OLED#

For QR code generation, I was allowed to use QRcode created by ricmoo. The implementation code is as follows.

platformio.ini
    [env:seeed_xiao_esp32s3]
    platform = espressif32
    board = seeed_xiao_esp32s3
    framework = arduino
    upload_speed = 115200
    monitor_speed = 115200
    upload_port = /your/port
    board_build.partitions = huge_app.csv
    build_flags = 
      -DARDUINO_USB_MODE=1
      -DARDUINO_USB_CDC_ON_BOOT=1
    lib_deps = 
      bblanchon/ArduinoJson @^6.21.2
      adafruit/Adafruit GFX Library@^1.12.1
      adafruit/Adafruit SSD1306@^2.5.14
      https://github.com/ricmoo/QRCode.git
    lib_ldf_mode = deep


OLEDdisplay.h
  #pragma once
  #include <Adafruit_SSD1306.h>
  #include <qrcode.h>

  class OLEDdisplay
  {
  public:
      OLEDdisplay(uint8_t width, uint8_t height);
      void begin();
      void showMessage(const String &text, uint8_t textSize = 1);
      void clear();
      void showQRCode(const String &text, uint8_t version = 3, uint8_t scale = 2);

  private:
      Adafruit_SSD1306 display;
      String currentText;
  };
#

OLEDdisplay.cpp
#include "OLEDdisplay.h"
OLEDdisplay::OLEDdisplay(uint8_t width, uint8_t height)
    : display(width, height, &Wire, -1), currentText("") {}

void OLEDdisplay::begin()
{
    Serial.println("OLEDdisplay code reading start");
    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
    {
        Serial.println("display Initialization Failure. So I freeze...");
        while (true)
            ;
    }
    display.clearDisplay();
    display.display();
}

void OLEDdisplay::showMessage(const String &text, uint8_t textSize)
{
    if (text != currentText)
    {
        currentText = text;
        display.clearDisplay();
        display.setTextSize(textSize);
        display.setTextColor(SSD1306_WHITE);
        display.setCursor(5, 5);
        display.println(text);
        display.display();
    }
}

void OLEDdisplay::clear()
{
    display.clearDisplay();
    display.display();
}

void OLEDdisplay::showQRCode(const String &text, uint8_t version, uint8_t scale)
{
    QRCode qrcode;
    uint8_t qrcodeData[qrcode_getBufferSize(version)];
    qrcode_initText(&qrcode, qrcodeData, version, ECC_LOW, text.c_str());

    int offset_x = (display.width() - qrcode.size * scale) / 2;
    int offset_y = (display.height() - qrcode.size * scale) / 2;

    display.clearDisplay();
    for (uint8_t y = 0; y < qrcode.size; y++)
    {
        for (uint8_t x = 0; x < qrcode.size; x++)
        {
            if (qrcode_getModule(&qrcode, x, y))
            {
                display.fillRect(offset_x + x * scale, offset_y + y * scale, scale, scale, SSD1306_WHITE);
            }
        }
    }
    display.display();
}

main.cpp
#include <Arduino.h>
#include "OLEDdisplay.h"

#define OLED_WIDTH 128
#define OLED_HEIGHT 64

OLEDdisplay oled(OLED_WIDTH, OLED_HEIGHT);

void setup()
{
    Serial.begin(115200);
    oled.begin();

    oled.showMessage("Ready!", 1);
    delay(500);
    oled.showQRCode("https://fabacademy.org/2025/");
}

void loop()
{
    oled.showQRCode("https://fabacademy.org/2025/");
}

I want you to watch the following video, which shows that the QR code flickers when displayed on the OLED. You cannot determine this with the naked eye, but the flickering is clearly visible through the camera lens. This is because the updates are applied in order from the top, like an electron gun on a CRT.

Iter2-4. PCB design#

Added fixing holes on the PCB and widened the copper wire. Overall spaciousness was added.

Once the PCB design was complete, the exported PNG file was uploaded to Mods to create gcode data.

Warning

When creating mods, traces are fine with ISO 1/64, but be careful with holes and outlines because the drill is 7mm.

Again, a drill is used to cut the copper plate. This time, I cut a total of four PCBs for the other members.

Improved board

Perform soldering 1. apply flux. 2. solder the ends of the components. 3. solder the other parts as well.

Soldering was done.

Iteration 3: ブロックチェーンによる相互評価システムの実装#

技術調査#

現在のざっくりした技術分類#

symbolブロックチェーンを用いることに決めた。

Iter3-1.環境構築#

Iter3-1-1. Symbolウォレットのセットアップ#

  1. Symbolウォレットのダウンロードする。 desktop-walletから自身のPC-OSにあったソフトをダウンロードする
  2. Symbolウォレットを開き、プロファイルの作成を行います。
  3. PPIを設定します。今回はtestnetを選択してください。
  4. ニーモニックフレーズを生成します。生成の様子を動画をご覧ください。Symbolウォレット画面を選択し、マウスを動かすのに連動してニーモニックフレーズの生成が進みます。

Warning

ニーモニックフレーズはあなたのお財布の鍵です。絶対に外部に漏れないように注意してください。

  1. ニーモニックパスフレーズを保存してください。
  2. ニーモニックパスフレーズの検証をしてください。これはスキップすることも可能です。
  3. セットアップの完了

Note

もしセットアップが完了しない場合 - Symbolウォレットは通信ポート3000または3001を使います。環境によってはファイヤーウォールによって接続が阻害され、セットアップが完了しない場合があります。 - その場合は以下のどちらかを対応してみてください。 1. ファイヤーウォールの設定を変える 2. 別のネットワーク環境(テザリングなど)に切り替える

Iter3-1-2. テストネット用通貨の取得#

  1. テストネット用通貨XYMの取得をする。テストネット用通貨XYMを無料で取得するためのサービス:フォーセットにアクセスし、ログインします。
  2. フォーセットサイトが開くので、Twitterアカウントでログインします。

Note

  • 自動アカウントによる悪意あるフォーセットの不正利用を防止するため、10人以上のフォロワーを持つXアカウント でログインする必要があります。
  1. フォーセットに自分のSymbolアドレスと必要なXYMをCLAIMします。
  2. Symbole desktop walletを見てみるとXYMが追加されたことがわかります。

Iter3-1-3. トランザクションの作成(基本的な送金など)#

  1. 追加のアカウントを作成する。Symbol desktop walletを用いて送金テストのためのアカウントを2つ作りましょう。
  2. 受信側のアドレスを取得する。今回はアカウント_Bのアドレスを取得します。アカウントBを選択し、アドレスをコピーしてください。
  3. 送信側のアカウントAに切り替えます。アカウントAを選択してください。
  4. アカウントAのホームで送信設定を行います。
    • 4-1:左サイドバーのHOMEをクリックしてください。
    • 4-2:中央にあるSENDをクリックしてください。
    • 4-3:アカウントBのアドレスを貼り付けてください
    • 4-4:symbol.xymが選択されていることを確認し、送りたい量を入力します。今回は10を送信しました。
    • 4-5:トランザクションのメッセージを入力してください。
    • 4-6:チェックを入れることでメッセージを暗号化できます。
    • 4-7:Feeを選択してください。処理速度とFeeは連動しています。処理速度が速ければ速いほどFeeも高くなります。
      • Averageより遅いFeeを選択するとネットワークの輻輳状態によっては処理が適切に行われない可能性があります。
      • 特に理由がなければ基本的な設定はAverageにしましょう。

5. 送信するためのパスワードを入力します。 6. 無事送信できました。Account_AのXYMが減り、Account_BのXYMが10増えたことが確認できます。

Iter3-1-4. Symbolエクスプローラーでトランザクションを確認してみる#

  1. Symbolエクスプローラーでトランザクションを表示・検索する
  2. Symbolエクスプローラーでアカウント情報を表示・検索する

Iteration 4: ハードウェア・ソフトウェアのUI向上#

joystickの3Dデータはここから取得できる 3dcontentcentral link

joystickのY軸とX軸の値をクラスタリングする まずは以下のコードとシリアルモニターでY軸とX軸の値を取得する

```cpp title=”“

include #

include “Joystick.h”#

// ピン定義(XIAO ESP32S3のGPIO番号) const uint8_t X_AXIS_PIN = 2; // A0に対応するGPIO const uint8_t Y_AXIS_PIN = 3; // A1に対応するGPIO const uint8_t BUTTON_PIN = 4; // A2に対応するGPIO

// ジョイスティックオブジェクトの作成 Joystick joystick(X_AXIS_PIN, Y_AXIS_PIN, BUTTON_PIN);

void setup() { Serial.begin(115200); }

void loop() { joystick.update(); // ジョイスティックの状態を更新

// 状態をシリアルモニターに出力
Serial.print("X軸: ");
Serial.print(joystick.getX());
Serial.print(" | Y軸: ");
Serial.print(joystick.getY());
Serial.print(" | ボタン: ");
Serial.println(joystick.isPressed() ? "押下" : "未押下");

delay(200); // 200ミリ秒待機

}

この情報をLLMに渡してCSVファイルを作成させる
```cpp title="CSV作成プロンプト"
以下のデータをCSV形式にしてください。
{
  ここにデータを貼り付ける。
}

次に、いかのPythonコードを用いて、クラスタリングを行う。

クラスタリングコード
import pandas as pd
from sklearn.cluster import KMeans
from ace_tools import display_dataframe_to_user

# データの読み込み
df = pd.read_csv('/mnt/data/download.csv')

# KMeans を用いて 5 クラスタにクラスタリング
kmeans = KMeans(n_clusters=5, random_state=0)
df['クラスタ'] = kmeans.fit_predict(df[['X軸', 'Y軸']])

# 各クラスタのサンプル数を集計
counts = df['クラスタ'].value_counts().sort_index()
cluster_summary = pd.DataFrame({
    'クラスタ': counts.index,
    'サンプル数': counts.values
})

# 結果を表示
display_dataframe_to_user('クラスタ別サンプル数', cluster_summary)
display_dataframe_to_user('クラスタリング結果', df)

こうしてクラスタリングしたデータを散布図で表現すると以下のようになる。 綺麗に値が分かれていることが確認できるため、joystickが問題なく反応していることがわかる。

散布図作成.py
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

# Load data
df = pd.read_csv('/mnt/data/download.csv')

# Perform clustering if not already present
kmeans = KMeans(n_clusters=5, random_state=0)
df['cluster'] = kmeans.fit_predict(df[['X軸', 'Y軸']])

# Create scatter plot with English labels
plt.figure(figsize=(6, 6))
plt.scatter(df['X軸'], df['Y軸'], c=df['cluster'])
plt.xlabel('X axis')
plt.ylabel('Y axis')
plt.title('Scatter Plot of X axis vs Y axis (colored by cluster)')
plt.grid(True)
plt.show()