Skip to content

Hayashi tmp

Following was documented by Hayashi

Improvements

Rake improvements

I re-designed the rake attachment which was unstable during the assignment, ended up using flexible 3D printed joints so that it passively follows the movement on the sand.

rakes

STEP file: rake_v3.stp

Program

Based on the program written for the last year’s THE LONE ANGLER project, I modified it to test Karesansui functions without relying on a network.

Modifications:

  • Swapped the motor A and C, run coreXY on motor B and C (Because of an issue on the motor A module while testing)
  • Added a function to grade the sand garden
  • Zeroing for Z motor (added in goToHome)
  • Modified the UI for testing
Modular Things program
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Code_yuichi4
// warning: without a powered usb-hub, currentScale > 0.5 are likely to fail 
//
// Open browsers DevTools console with
//  cmd + shift + j (Linux)
//  ctrl + shift + j (win)
//  command + option + j (mac)
//

// UI用の要素を作成
const el = document.createElement("div");
el.style = `padding: 10px; font-family: sans-serif;`;

// UIのHTMLを追加(シンプル版)
el.innerHTML = `
  <div style="display: flex; flex-direction: column; justify-content: flex-end; height: 120px;">
    <img src="https://fabacademy.org/2025/labs/kannai/images/logo2022-tate-g.png" 
         alt="FabLab Kannai" 
         width="90" 
         style="margin: auto;">
  </div>

  <h1>RYOAN-JI XY 2024.9</h1>
  <p style="color: black;">FabAcademy2025 / Modular-Things coreXY</p>
  <hr>

  <!-- XY移動ボタン -->
  <div style="text-align: center; margin: 10px;">
    <button id="yPlus">✌️</button>
  </div>
  <div style="text-align: center; margin: 10px;">
    <button id="xMinus">👈</button>
    <button id="Home">🏠</button>
    <button id="xPlus">👉</button>
  </div>
  <div style="text-align: center; margin: 10px;">
    <button id="yMinus">👇</button>
  </div>

  <!-- Z移動up/down -->
  <div style="text-align: center; margin: 10px;">
    <button id="down">🔄</button>
    <button id="up">🧹</button>
  </div>

  <hr>
  <!-- 図形描画コマンド -->
  <div style="text-align: center; margin: 10px;">
    <button id="drawSquare">drawSquare</button>
    <button id="Draw">Draw</button>
    <button id="Grade">Grade</button>
    <!-- <button id="Test">test</button> -->
  </div>

  <hr>
  <p style="font-size: small; color: black;">
    Open DevTools console with<br>
    cmd + shift + j (Linux)<br>
    ctrl + shift + j (Win)<br>
    command + option + j (Mac)
  </p>
`;

// bodyに追加
document.body.appendChild(el);


//--------------------------------------
// Testボタンの処理
//--------------------------------------
/*
el.querySelector("#Test").addEventListener("click", () => {
  delay(100);
  test();
});

function test() {
  machine.setPosition([0, 0]);
  goTo(10, 10);
}
*/
//--------------------------------------
// CoreXYモーション制御
//--------------------------------------

// 同期モーションマシンを作成
const machine = createSynchronizer([motorC, motorB]); // motorC, motorBを使用

// XY移動関数
async function goTo(x, y) {
  console.log(`Moving to (${x}, ${y})`);
  await machine.absolute([-1 * (x + y), 1 * (x - y)]); 
}

//--------------------------------------
// 各UIボタンのイベント設定
//--------------------------------------
el.querySelector("#xPlus").addEventListener("click", () => xPlus());
el.querySelector("#xMinus").addEventListener("click", () => xMinus());
el.querySelector("#yPlus").addEventListener("click", () => yPlus());
el.querySelector("#yMinus").addEventListener("click", () => yMinus());
el.querySelector("#up").addEventListener("click", () => up());
el.querySelector("#down").addEventListener("click", () => down());
el.querySelector("#Home").addEventListener("click", () => goToHome());
el.querySelector("#drawSquare").addEventListener("click", () => { delay(100); drawSquare(); });
el.querySelector("#Grade").addEventListener("click", () => { delay(100); Grade(); });
el.querySelector("#Draw").addEventListener("click", () => { delay(100); draw(); });

// DOMにUIを追加
render(el);

//--------------------------------------
// モーター設定
//--------------------------------------
motorA.setCurrent(1);
motorA.setStepsPerUnit(1);
motorA.setAccel(10);

motorB.setCurrent(1);
motorB.setStepsPerUnit(3);
motorB.setAccel(20);

motorC.setCurrent(1);
motorC.setStepsPerUnit(9); // motorB とバランスするため
motorC.setAccel(20);

machine.setPosition([0, 0]); // 現在位置を (0,0) に設定
motorA.setPosition(0);

//--------------------------------------
// 動作関数群
//--------------------------------------

// 原点復帰処理
async function goToHome() {
  while (await motorA.getLimitState()) {
    motorA.relative(1, 500, 100);
    await delay(50);
  }
  motorA.relative(-25); //中立位置
  await delay(100);

  while (await motorC.getLimitState()) {
    // motorC.velocity(-10);
    // motorB.velocity(-10);
    motorC.relative(1, 800, 100);
    motorB.relative(-1, 800, 100);
    await delay(50);
  }
  while (await motorB.getLimitState()) {
    // motorC.velocity(-10);
    // motorB.velocity(10);
    motorC.relative(1, 800, 100);
    motorB.relative(1, 800, 100);
    await delay(50);
  }
  // motorC.velocity(0);
  // motorB.velocity(0);
  machine.setPosition([0, 0]);
  motorA.setPosition(0);
  await delay(100);

  // Backoff
  goTo(10, 10);
  await delay(1000);
}

//--------------------------------------
// XY移動系 (手動操作)
//--------------------------------------
function xPlus() {
  machine.setPosition([0, 0]);
  for (let i = 0; i < 10; i++) goTo(i, 0);
}

function xMinus() {
  machine.setPosition([0, 0]);
  for (let i = 0; i < 10; i++) {
    goTo(-i, 0);
    delay(200);
  }
}

function yPlus() {
  machine.setPosition([0, 0]);
  for (let i = 0; i < 10; i++) goTo(0, i);
}

function yMinus() {
  machine.setPosition([0, 0]);
  for (let i = 0; i < 10; i++) goTo(0, -i);
}

async function up() {
  motorA.relative(10);
  await delay(1000);
}

async function down() {
  motorA.relative(-10);
  await delay(1000);
}

//--------------------------------------
// 図形描画
//--------------------------------------
async function drawSquare() {
  // await goToHome();
  motorA.relative(24); //Down
  await delay(200);
  for (let i = 0; i < ptsSquare.length; i++) {
    await goTo(ptsSquare[i][0], ptsSquare[i][1]);
    await delay(200);
  }
  motorA.relative(-24); //UP
  await delay(200);
}

async function draw() {
  // await goToHome();
  motorA.relative(24); //Down
  await delay(200);
  for (let i = 0; i < pts.length; i=i+4) { //i++
    await goTo(pts[i][0], pts[i][1]);
    await delay(200);
  }
  motorA.relative(-24); //UP
  await delay(200);
}

// 均し
async function Grade() {
  // await goToHome();
  motorA.relative(-24); //UP (Grading)
  await delay(200);
  for (let i = 0; i < ptsGrade.length; i++) {
    await goTo(ptsGrade[i][0], ptsGrade[i][1]);
    await delay(200);
  }
  motorA.relative(24); //Down
  await delay(200);
}

//--------------------------------------
// 描画パターンの座標定義
//--------------------------------------
var ptsSquare = [[80, 20], [80, 80], [20, 50], [20, 20]];
var ptsStar   = [[20, 10], [30, 50], [40, 10], [10, 40], [50, 40], [20, 10]];
var ptsGrade  = [[221,245],[221,45],[197,45],[197,245],[173,245],[173,45],[149,45],[149,245],[125,245],[125,45],[101,45],[101,245],[77,245],[77,45],[53,45],[53,245],[29,245],[29,45]];
// Draw
var pts = [];

Drawing

I created a simple Grasshopper definition to convert a path to a point and ultimately to XY coordinates like [0, 10], ... I found a useful feature called “Stream contents”, which streams data on a panel to a specified text file.

Grasshopper: Draw.gh

gh

Preparations

Panel design and Booth planning

A2 and A3 panel explaining how the machine works and some photos of the 2 weeks process. We used Accea to print, which cost 5,500 JPY and was delivered in a few days in (overly) well packaging.

panel

In Rhino, I laid everything out on a table to test whether it would fit in the space.

booth

Reflections on the panels

Good points:

  • It helps explain overview of how it (supposed to) work
  • Some cues to engage for different audiences; AI, Karesansui, coreXY, Haiku etc.

Points to improve:

  • Haiku generation was not self explanatory
  • Overview in English could help increase interest among international audiences
  • More descriptions about Fab Academy program, Machine building assignment and things we inherited from Fab network would have been helpful

Power setup

Because it found out that we can’t use power outlets, we decided to use the following mobile battery and DC-DC power supply, borrowed from Ito-san and Tamiya-san for each.

  • Mobile battery: Anker 737 Power Bank
    • Input: 5V=3A
    • Output: USB-C: 5V=3A (Max. 140W)
    • Battery Capacity: 24,000mAh
  • DC-DC power supply: DP100
    • This case, it was set as: CV (Constant voltage): 5V

power

Modular-things can be powered by mobile battery

It worked without any problems. On the day 2, the machine ran from 10am to 5pm with 61% battery power remaining.

Trouble shooting

Burned H-bridge circuit

During testing, I noticed that the X and Y directions were jagged and unstable. I later discovered that one of the H-bridge IC and a 0.1uF capacitor on the modular-stepper circuit were burned out (left image below). I guess this was probably due to a voltage setting error when I first connected the mobile battery.

circuits

I then borrowed a capacitor and an IC from Tamiya-san and replaced them. Some of the surrounding traces were burnt and peeled off, so I connected a 0.1uF capacitor to the 1uF capacitor next to it, added extra solder, and used a short wire to temporarily fix it (right image). Surprisingly, it worked.

Broken limit switch pin while transportation

After transporting the machine to Tokyo Big Sight, I noticed a limit switch socket was broken. We found that there were a nice soldering place in the venue and soldered jump wires.

Anything that can go wrong will go wrong

Murphy’s law

Transportation

We packed and fastened the machine on a handcart to transport it to Tokyo Big Sight by train.

Ref: JR East | Size and weight of luggage that can be carried on the train

transportation