airpocket が 2025年08月01日00時17分13秒 に編集
初版
タイトルの変更
円グラフドーナツ
タグの変更
Microbit
メイン画像の変更
記事種類の変更
製作品
ライセンスの変更
(MIT) The MIT License
本文の変更
# コード 開発はmicrobit python editorで行いました。 ```python from microbit import * # --- 設定セクション --- FULL_STEPS_PER_ROTATION = 4096 # ステッピングモーター1回転のステップ数(28BYJ-48 = 4096) NOZZLE_ANGLES = [0, 90, 180, 270] # 各カラーシュガーのノズル位置(a, b, c, d) positionOpen = 120 positionClose = 30 trayIsOpened = True servoDelay = 10 stepperPins = [pin13, pin14, pin15, pin16] trayPin = pin0 color = [pin1, pin2, pin8, pin9] # カラーa, b, c, d colorCount = [0, 0, 0, 0, 0] # 各色の割合(最大5色) currentColumn = 0 screwSpeed = 55 #26~128 screwStop = 77 # --- ステッピングモーター制御クラス --- class Stepper28BYJ48: step_sequence = [ [1,0,0,0], [1,1,0,0], [0,1,0,0], [0,1,1,0], [0,0,1,0], [0,0,1,1], [0,0,0,1], [1,0,0,1] ] def __init__(self, pins, delay_ms=2): if len(pins) != 4: raise ValueError("4ピン指定が必要") self.pins = pins self.delay_ms = delay_ms self.position = 0 def move(self, steps): direction = 1 if steps > 0 else -1 for _ in range(abs(steps)): self.position = (self.position + direction) % 8 self._set_pins(self.step_sequence[self.position]) sleep(self.delay_ms) self.release() def _set_pins(self, pin_states): for pin, state in zip(self.pins, pin_states): pin.write_digital(state) def release(self): for pin in self.pins: pin.write_digital(0) # --- ユーティリティ関数群 --- def angleToSteps(angle): return int(round(FULL_STEPS_PER_ROTATION * angle / 360)) def moveServo(start, stop): trayPin.write_analog(stop) #step = 1 if start <= stop else -1 #for i in range(start, stop + step, step): # trayPin.write_analog(i) # sleep(servoDelay) def closeTray(): global trayIsOpened moveServo(positionOpen, positionClose) sleep(1000) trayIsOpened = False def openTray(): global trayIsOpened moveServo(positionClose, positionOpen) sleep(1000) trayIsOpened = True def colorCountToImage(counts, highlight=-1): rows = [] for y in range(5): row = '' for x in range(5): val = 9 if counts[x] >= 5 - y else 0 if x == highlight: val = 9 - val # 反転表示 row += str(val) rows.append(row) return Image(':'.join(rows)) def drawPieChart(counts): total = sum(counts) if total == 0: return segment_angle = 0 angle_per_counts = 360 / total for i in range(4): if counts[i] == 0: continue segment_angle = counts[i] * angle_per_counts if i != 0: motor.move(angleToSteps(NOZZLE_ANGLES[i]- NOZZLE_ANGLES[i-1])) #今回ノズル位置の位置合わせ color[i].write_analog(screwSpeed) #シュガー用モーター動作 motor.move(angleToSteps(segment_angle)) #ドーナツ回転 color[i].write_analog(screwStop) #シュガー用モーター停止 # 残りすべてゼロなら終了 if all(c == 0 for c in counts[i + 1:]): break # --- 初期化 --- motor = Stepper28BYJ48(stepperPins, delay_ms=5) trayPin.set_analog_period(positionOpen) color[0].set_analog_period(20) color[1].set_analog_period(20) color[2].set_analog_period(20) color[3].set_analog_period(20) # --- メインループ --- while True: display.show(colorCountToImage(colorCount, currentColumn)) if pin_logo.is_touched(): if trayIsOpened: closeTray() drawPieChart(colorCount) else: openTray() elif button_b.is_pressed(): currentColumn = (currentColumn + 1) % 5 sleep(200) elif button_a.is_pressed(): colorCount[currentColumn] = (colorCount[currentColumn] + 1) % 6 sleep(200) sleep(100) ```