0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【電子工作】ATtiny402とI2Cカラーセンサーで作る、ミニ四駆のPWM速度制御回路

0
Last updated at Posted at 2026-03-17

はじめに

最近ミニ四駆の改造にハマっています。
タイムを良くするためには、スピードを上げることが重要です。しかし、ミニ四駆のコースには高低差があるため、速度を出しすぎるとジャンプしてコースアウトしてしまいます。

このような速度とコースアウトのトレードオフを解決するために、
「コースの色を検出することで、上り坂に差し掛かる直前で速度を落とせないか!?」
と考えました。

そこで、コースの色を検出してモーターの出力を調節することができる回路を設計しました。
今回は設計編ということで、組み上げた回路の動作確認までをまとめます。

使用部品

回路図

本システムは、大きく2つのコンポーネントから構成されます。

  • カラーセンサーモジュール:色を識別し、I2C通信でAttiny402に色情報を送信する
  • モーター駆動(PWM制御)回路:色情報をもとに、モーターへPWM信号を送り速度を調節する

カラーセンサーモジュールは、上述のリンクで作成したものを流用します。

モーター駆動回路の設計図は以下のようになっています。

  • バイパスコンデンサC1,C2:直流電源の安定性確保のため、周波数帯に応じた2種のセラミックコンデンサを配置
  • 逆起電力対策のショットキーダイオードD1:PWMがOFFになる際に生じる逆起電力対策
  • ゲート抵抗・プルダウン抵抗R1, R2

image.png

カラーセンサーモジュールとモーター駆動モジュールを配線すれば、完成です!
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を決めています。適当に入れた値になっているので、調節してください。

ColorSensor_PWM.ino
#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:動作確認の様子。コネクタを持っていないので、気合で配線しました泣 実使用時には、きれいに配線したいですねえ。

おわりに

いろいろ苦労しましたが、無事に意図通り動作してよかったです。
次は実際にミニ四駆のシャーシに組み込んで、動作テストをしたいと思います。
スペース確保のために、シャーシを改造する必要もありそうです、、、

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?