はじめに
最近ミニ四駆の改造にハマっています。
タイムを良くするためには、スピードを上げることが重要です。しかし、ミニ四駆のコースには高低差があるため、速度を出しすぎるとジャンプしてコースアウトしてしまいます。
このような速度とコースアウトのトレードオフを解決するために、
「コースの色を検出することで、上り坂に差し掛かる直前で速度を落とせないか!?」
と考えました。
そこで、コースの色を検出してモーターの出力を調節することができる回路を設計しました。
今回は設計編ということで、組み上げた回路の動作確認までをまとめます。
使用部品
-
AVRマイコン ATTINY402-SSNR
・以前の記事で使用したAttiny202では容量が足りず、Attiny402にしました。使用方法やピン配置は同じです。 - 整流用ショットキーダイオード 100V1A 1S10
- 積層セラミックコンデンサー 0.1μF250V X7R 5mmピッチ
- 電源用電解コンデンサー100μF35V105℃ ルビコンZLH
- NchパワーMOSFET 60V5A 2SK4017(Q)
- 抵抗 (100 Ω・100 kΩ)
- DCモーター
- I2C対応カラーセンサー S13683-03DT含む、以下の記事で作成したモジュール。
回路図
本システムは、大きく2つのコンポーネントから構成されます。
- カラーセンサーモジュール:色を識別し、I2C通信でAttiny402に色情報を送信する
- モーター駆動(PWM制御)回路:色情報をもとに、モーターへPWM信号を送り速度を調節する
カラーセンサーモジュールは、上述のリンクで作成したものを流用します。
モーター駆動回路の設計図は以下のようになっています。
- バイパスコンデンサC1,C2:直流電源の安定性確保のため、周波数帯に応じた2種のセラミックコンデンサを配置
- 逆起電力対策のショットキーダイオードD1:PWMがOFFになる際に生じる逆起電力対策
- ゲート抵抗・プルダウン抵抗R1, R2
カラーセンサーモジュールとモーター駆動モジュールを配線すれば、完成です!
SDAとSCL用のピンは指定されているので、配線時には注意です。
プログラム
容量の都合上、カラーセンサー単体動作時のプログラムから縮小しています。
if (total < 50) { analogWrite(PWM_PIN, 2); }
else if (r_f > g_f * 1.2 && r_f > b_f * 1.2) { analogWrite(PWM_PIN, 128); }
else if (b_f > g_f * 1.2 && b_f > r_f * 1.2) { analogWrite(PWM_PIN, 40); }
else { analogWrite(PWM_PIN, 255); }
この部分で、色情報$\leftrightarrow$PWMのdutyを決めています。適当に入れた値になっているので、調節してください。
#include <Wire.h>
const int S13683_ADDR = 0x2A;
const uint8_t PWM_PIN = PIN_PA3; // 物理3番ピン
float k_r = 1.0; float k_g = 0.7; float k_b = 1.0;
void setup() {
// --- 通信安定化のための処理 ---
pinMode(PIN_PA1, INPUT_PULLUP); // SDA: 物理4番
pinMode(PIN_PA2, INPUT_PULLUP); // SCL: 物理5番
delay(100);
Wire.begin();
Wire.setClock(100000); // 100kHz
pinMode(PWM_PIN, OUTPUT);
// 起動確認:一瞬点灯
analogWrite(PWM_PIN, 50);
delay(500);
analogWrite(PWM_PIN, 0);
// センサー初期設定
writeReg(0x00, 0x89);
delay(20);
writeReg(0x00, 0x09);
delay(50);
}
void loop() {
Wire.beginTransmission(S13683_ADDR);
Wire.write(0x03);
uint8_t error = Wire.endTransmission(false);
if (error != 0) {
// 通信エラー:5回高速点滅して、少し待つ
for(int i=0; i<5; i++){
digitalWrite(PWM_PIN, HIGH); delay(50);
digitalWrite(PWM_PIN, LOW); delay(50);
}
delay(500);
return;
}
Wire.requestFrom(S13683_ADDR, 8);
if (Wire.available() == 8) {
uint16_t r_raw = (Wire.read() << 8) | Wire.read();
uint16_t g_raw = (Wire.read() << 8) | Wire.read();
uint16_t b_raw = (Wire.read() << 8) | Wire.read();
uint16_t comp = (Wire.read() << 8) | Wire.read();
int32_t r_c = (int32_t)r_raw - comp;
int32_t g_c = (int32_t)g_raw - comp;
int32_t b_c = (int32_t)b_raw - comp;
if(r_c < 0) r_c = 0; if(g_c < 0) g_c = 0; if(b_c < 0) b_c = 0;
float r_f = r_c * k_r; float g_f = g_c * k_g; float b_f = b_c * k_b;
float total = r_f + g_f + b_f;
if (total < 50) { analogWrite(PWM_PIN, 2); }
else if (r_f > g_f * 1.2 && r_f > b_f * 1.2) { analogWrite(PWM_PIN, 128); }
else if (b_f > g_f * 1.2 && b_f > r_f * 1.2) { analogWrite(PWM_PIN, 40); }
else { analogWrite(PWM_PIN, 255); }
}
delay(20);
}
void writeReg(byte reg, byte val) {
Wire.beginTransmission(S13683_ADDR);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
動作
いまだに動画の載せ方が分からず、見せられないのが残念です。(youtubeにのせるか?)
実際にモーターをつないで色紙を近づけると、狙い通りにモーターの回転速度を制御することができました。
画像
![]() 図1:モーター制御回路 |
![]() 図2:PWM出力の様子 |
![]() 図3:動作確認の様子。コネクタを持っていないので、気合で配線しました泣 実使用時には、きれいに配線したいですねえ。 |
おわりに
いろいろ苦労しましたが、無事に意図通り動作してよかったです。
次は実際にミニ四駆のシャーシに組み込んで、動作テストをしたいと思います。
スペース確保のために、シャーシを改造する必要もありそうです、、、



