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.
- 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.
- have the objects separated by “range all objects” be organized in an appropriate manner.
- 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.
- select “range all obujects” again and organize the objects again.
- select “auto orient” to have the object placed in the most efficient orientation.
- use “support painting” to paint the inevitable overhangs.
- 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#
- Set up the following flow in gitlab.
- User Settings > Preferences > Access tokens > add new token
-
set up and issue TOKEN as shown in the image.
-
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.
- {your_pj_id} in the url, the id number can be found in the image below.
- header {yourtoken}. Enter the aforementioned api token.
- {your_pj_id} in the url, the id number can be found in the image below.
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.
[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;
};
#
#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;
};
#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();
}
#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ウォレットのセットアップ#
- Symbolウォレットのダウンロードする。 desktop-walletから自身のPC-OSにあったソフトをダウンロードする
- Symbolウォレットを開き、プロファイルの作成を行います。
- PPIを設定します。今回は
testnet
を選択してください。 - ニーモニックフレーズを生成します。生成の様子を動画をご覧ください。Symbolウォレット画面を選択し、マウスを動かすのに連動してニーモニックフレーズの生成が進みます。
Warning
ニーモニックフレーズはあなたのお財布の鍵です。絶対に外部に漏れないように注意してください。
- ニーモニックパスフレーズを保存してください。
- ニーモニックパスフレーズの検証をしてください。これはスキップすることも可能です。
- セットアップの完了
Note
もしセットアップが完了しない場合 - Symbolウォレットは通信ポート3000または3001を使います。環境によってはファイヤーウォールによって接続が阻害され、セットアップが完了しない場合があります。 - その場合は以下のどちらかを対応してみてください。 1. ファイヤーウォールの設定を変える 2. 別のネットワーク環境(テザリングなど)に切り替える
Iter3-1-2. テストネット用通貨の取得#
- テストネット用通貨XYMの取得をする。テストネット用通貨XYMを無料で取得するためのサービス:フォーセットにアクセスし、ログインします。
- フォーセットサイトが開くので、Twitterアカウントでログインします。
Note
- 自動アカウントによる悪意あるフォーセットの不正利用を防止するため、10人以上のフォロワーを持つXアカウント でログインする必要があります。
- フォーセットに自分のSymbolアドレスと必要なXYMをCLAIMします。
- Symbole desktop walletを見てみるとXYMが追加されたことがわかります。
Iter3-1-3. トランザクションの作成(基本的な送金など)#
- 追加のアカウントを作成する。Symbol desktop walletを用いて送金テストのためのアカウントを2つ作りましょう。
- 受信側のアドレスを取得する。今回はアカウント_Bのアドレスを取得します。アカウントBを選択し、アドレスをコピーしてください。
- 送信側のアカウントAに切り替えます。アカウントAを選択してください。
- アカウント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にしましょう。
- 4-1:左サイドバーの
5. 送信するためのパスワードを入力します。
6. 無事送信できました。Account_AのXYMが減り、Account_BのXYMが10増えたことが確認できます。
Iter3-1-4. Symbolエクスプローラーでトランザクションを確認してみる#
- Symbolエクスプローラーでトランザクションを表示・検索する
- 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が問題なく反応していることがわかる。
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()