かずいの雑記帳4

趣味でいろいろ実験やってます。 2021年6月21日よりhttpsの利用が可能になりました。 当ブログも設定を変更しましたので、画面の乱れ等ありましたら教えて下さい。

Aruduino

MCP41050 デジタルポテンショメータを試してみる

SPI通信の習作です。
といっても、Arduinoの場合、誰かが作ってくれたデバイスドライバを探してきてインストールするだけなので、SPIプロトコルを直接操作するようなことはありません。

ハードウエア的にはこのようなものを用意し、2つのMCP41050を同時に操作し、アナログ電圧でフィードバックを取って動作を確認してみました。

WS020061


MCP41050のライブラリは、こちらから頂いてきました。
https://github.com/sleemanj/MCP41_Simple

結果です。
ほぼ同期出来てますね。個体差も僅かです。
WS020062

もう少し分解能が高ければ、可変抵抗で出力調整をしている機器をデジタル化するのに使えそうです。
惜しい。

以下ソースです。
//
//    FILE: MCP41050_Demo.ino
//  AUTHOR: hirayama540-blog@yahoo.co.jp
// PURPOSE: MCP41050 DemoPG
//     URL: http://kazuikazui.dreamlog.jp
//
// Rev.1 First release 2024.01.09

#include <MCP41_Simple.h>

MCP41_Simple MyPot;

const uint8_t CS_PIN = 10;
uint8_t CUR_VAL = 0;
uint8_t DIRECTION = 1;
uint16_t sensorPin = A0;   // select the input pin for the potentiometer
uint16_t sensorValue = 0;  // variable to store the value coming from the sensor
uint16_t Wiper1 = A1;
uint16_t Wiper2 = A2;
uint16_t WiperValue1 = 0;
uint16_t WiperValue2 = 0;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("MCP41050_LIB_VERSION: ");
  Serial.println("xxxx");
  Serial.println();
  delay(500);

  // put your setup code here, to run once:
  MyPot.begin(CS_PIN);

  // Analog Setting
  analogReference(EXTERNAL);  // the voltage applied to the AREF pin (0 to 5V only) is used as the reference.
}

void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);
  uint8_t WiperSetValue = sensorValue / 4;


  // put your main code here, to run repeatedly:
  MyPot.setWiper(WiperSetValue);

  WiperValue1 = analogRead(Wiper1);
  WiperValue2 = analogRead(Wiper2);

  Serial.print("sensorValue: ");
  Serial.print(sensorValue);
  Serial.print("\t");
  Serial.print("WiperValue1: ");
  Serial.print(WiperValue1);
  Serial.print("\t");
  Serial.print("WiperValue2: ");
  Serial.print(WiperValue2);
  Serial.print("\t");
  Serial.println();

  delay(100);
}

ロボットカーでWiFiリモコンの基礎を学ぶ(その2)

2.超音波即距離センサ HC-SR04を使った距離測定
※写真は秋月電子さんから
M-11009
超音波を発信、反射波を受信し、その時間差で距離を測定するアクティブソナーセンサ。
データシートに記載された仕様は以下のとおり。
制御電圧Vcc:3.5~5.5V
制御電流Icc:2.2~3mA
最大測定長:350~600cm
不感帯最小長:2~4cm
測定精度:±2%(FSまたはRD?不明)
分解能:1mm
最大測定角:±15~±20°
最小測定周期:200msec

ロボットカーで重要になるのは太字で書いたあたりじゃなかろうか。
その中でも測定周期は1秒間に5回しか測定できない。これはGPIOでもシリアル通信でも同じ。
また、対象が近すぎると測定できないので、厳密に制御するには不感帯をカバーするようなセンサが必要になるかも。
GPIOでの動作としては、Trig Hi 10[μsec] →内部で40[kHz]の応答パルスを8回カウントし、その時間を測定→Echo Hiのパルス幅T[μsec]で音波発信からエコーの応答までの時間を表現しているそうだ。
このパルス幅から距離を計算する。

ちなみに、20cmだとこのような波形になる。
ch1がTRIG、ch2がECHOで、この山の幅とTRIGからの応答時間がセンサ先端から対象までの距離によって伸び縮みする。
NewData1


ECHOのパルス幅から距離[cm]は次式で与えられる。
距離=T×C/2
T:パルス幅(応答時間)[μsec]
C:音速[m/sec]

ここで、音速C[m/sec]は気温によって変化するので、次式で補正が必要になる。
C=(331.45+0.61×t)[m/sec]
t:気温[℃]
例:@23℃、C=331.45+0.61*23=345.48[m/sec]

先の例ではTが11720[μsec]なので、
距離=1172*10^-6×345.48÷2=20.24512[cm]

ちなみに1digit(=1μsec)あたりの分解能は0.17mmなので、センサの誤差としては、pulseIn()の読み取り誤差1digit(±0.17mm)又は測定精度±2%がFSなら±12mm、RDなら±0.70mmのいずれか大きい方ということになるのかな?

測定周期について、テストプログラムで実測してみるとデータシートのものよりかなりレスポンスが良いようで、600cmの測定でも計算上は測定サイクルが38msくらいだし、100ms周期でも余裕があると思う。
1m以下の近距離なら50ms周期でも問題はなかった。
なので、距離が近づくにつれて測定頻度を上げるようなプログラムを組めばより高精度の位置決めができる可能性がある。
ただ残念なことに、手元のブツにはデータシートで記されているジャンパのPADが存在せず、モード切替ができない。
データシート上ではI2CやUARTの通信も可能となっていたんだけれど、基盤のリビジョンが違うのか?

HC-SR04.ino
// 超音波測距離センサ HC-SR04を使って距離を測定する

/* Defintion of I/O device */
// for ESP-WROOM-02 WeMos D1 R2 & mini
const int ONBOARD_LED = D4;
const int EchoPin = D2;
const int TrigPin = D3;

/* Prototyping */
void calcDistance();

/* Configration */
void setup() {
  delay(500);
  Serial.begin(115200);
  Serial.println();
  Serial.print("HC-SR04 UltraSonic distance measurement sensor");
  delay(500);

  // for ESP-WROOM-02 WeMos D1 R2 & mini
  pinMode(ONBOARD_LED, OUTPUT);
  digitalWrite(ONBOARD_LED, true);

  pinMode(EchoPin, INPUT);
  pinMode(TrigPin, OUTPUT);

  Serial.println("Distance measurement started");
}

/* Demonstration PG */
void loop() {
  calcDistance();
}

/* Sencer Control SUB */
void calcDistance() {
  float distance = 0.0;  // 距離[cm]
  float duration = 0.0;  // パルス幅[μsec]
  const float airTemperature = 23.0;  // 気温[℃]
  static long last_time = 0;  // 直前実行時の積算時間[ms]
  long now_time = millis();  // 現在の積算時間[ms]
  
  if ((now_time - last_time) < 100) {
    return;
  }
  last_time = now_time;

  digitalWrite(TrigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(TrigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(TrigPin, LOW);

  duration = pulseIn(EchoPin, HIGH);
  if (duration > 0) {
    duration = duration / 2;  //往復距離なので半分の時間
    distance = duration * (331.45 + 0.61 * airTemperature) / 10000;  // 距離[cm]を計算
    Serial.print(distance);
    Serial.println("cm");
  } else {
    Serial.println("no echo");
  }
}


ロボットカーでWiFiリモコンの基礎を学ぶ(その1)

それでは駆動部から攻めてみよう。
1.モータードライバ L298N を使ったモーターの制御
PWM出力にも対応した高速2軸Hブリッジドライバ。
DUAL FULL-BRIDGE DRIVER IC の L298を使用したモータードライバモジュールで、ICの制御回路と電源回路用のバイパスコンデンサとモーターから発生するサージ対策のフライバックダイオードが実装されていて、電気に詳しくないビギナでも安全に使えるものになっている。
WS500201

61EuvoL8n3L._AC_SL1000_

フルブリッジ、すなわち負荷のハイサイドとローサイド両方のスイッチング。
PWMはイネーブラをON/OFFさせて、これもハイサイドとローサイド両方のスイッチングを行い、速度調整を行う。
データシートに記載された定格パラメータは以下のとおり。
給電圧Vs:2.5~46V
制御電圧Vss:4.5~7V
連続出力電流(瞬間最大)Io:2A(3A)

イネーブラは軸毎に実装されているので、左右の車輪を別々に256段階で速度調整、スムーズなコーナーリングや加減速も可能だな。
なるほど、楽勝♪ 

の、はずだったが、実際にバンドルされていたのはMX1508だった。orz
IMG_6253
WS500200

一応、各通販サイトでモータードライバモジュール「L298N」として売られているものだし、完成品の写真をよくよく見れば確かにコレなので販売者が嘘をついていたわけではないんだけど、正直、ちょっとがっかりじゃった。(´・ω・`)

このICのデータシートを探してみたのだが見つからず、とりあえずモジュールのスペックを拾い出してみた。

MX1508 DC Motor Driver with PWM Control
Features and Specifications of MX1508 DC Motor Driver
The section mentions a few of the features and specifications of the MX1508 motor driver:

Module supply Voltage: 2-10V DC
Voltage output: 1.8-7V  DC
Operating Current: 1.5A
Peak current:2A
Low standby current (less than 0.1uA)
Integrated H-bridge driver circuit
Low quiescent operating current
Module has inbuilt capacitors ad flyback diodes to tackle reverse EMF voltage spike’
Dual H-bridge motor driver
 
給電圧が低くなったのはまだカバーできるが、連続/ピーク定格電流が1.5A/2.0Aと低くなっており、130モーターでもロックすると定格電流を超えてしまうということが解った。1)

また、イネーブラが無く、PWM制御はブリッジのおそらくハイサイドをチョッパするハーフブリッジということになるが、PWMの最高周波数の記載が無いので、なるだけ低い周波数(おそらく20kHz以下)で使うのが無難とうことになるのだろう。
また、MX1508はフリーホイルダイオードやフライバックダイオードが実装されていない。
この状態でモータのコイルにPWMのパルスを流したりするとサージパルス発生器となることは必至。
それでなくても、ブラシモーターは常時ノイズは出しまくりである。
よって、サージ対策回路外付けは必須となるだろう。
MX1508 vs L9110S vs TB6612 vs L293D Motordriver board2)

ICのデータシートがリンクされていたので、メモっておく。
MX1508の製造元とされるShenzhen Guanghui Electronics Co., Ltdのデータシートのようなもの。 

サージ対策はとりあえずモーター側に0.1μFのセラコンを付けておいた。とりあえずラジオノイズは減るだろう。
IMG_6255

ヘッダピンのピッチは2.54mmだけれど、電源、入力、出力のブロック間のピッチがデタラメなのでそのままではブレッドボードにはささらない。
ブレッドボード直刺しにこだわる必要も無いので、ピンヘッダを付けてリード線引き出し仕様とした。
IMG_6254

WeMos D1 R2 & mini用のスケッチを書いてベンチテスト。3)
モーターはまだ繋がず、代わりに220Ωの抵抗をつけて電圧をモニタした。

ESP-WROOM-02のPWMの基底周波数は1kHzで分解能は1023だそうだ。
とりあえずデューティー比50%で出力してみた。
電動機正転。

NewData1

電動機逆転させたところ。
NewData2

基底周波数を20kHzにしてみた。
追従性があまりよろしくなく、デューティー比に狂いが出ている。
やはり低めの周波数で使うべきなのだろう。
NewData3


MX1508.ino
// モータードライバ MX1508 を使いDCモーターを制御する

/* Defintion of I/O device */
// for ESP-WROOM-02 WeMos D1 R2 & mini
const int ONBOARD_LED = D4;
const int IN1 = D5;
const int IN2 = D6;
const int IN3 = D7;
const int IN4 = D8;

int leftValue, rightValue;  // 左設定値、右設定値(0-1023)[count]
const int STALL = 50;       // ストール速度(0-1023)[count]

/* Prototyping */
void motorControl(int leftValue, int rightValue); // 前進、後退、旋回
void freeRunStop();         // フリーラン停止
void suddenStop();          // 急停止&ブレーキ

/* Configration */
void setup() {
  // for ESP-WROOM-02 WeMos D1 R2 & mini
  analogWriteRange(1023); // PWM range of duty ratio.default 1023
  analogWriteFreq(1000);  // PWM base frequency.default 1000(=1kHz)

  pinMode(IN1, OUTPUT);   // 出力ピンを設定
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);

}

/* Demonstration PG */
void loop() {
  delay(1000);

  /* Drive Test */
  leftValue = 511;
  rightValue = 1023;
  motorControl(leftValue, rightValue);

//  /* Fowerd */
//  leftValue = 1023;
//  rightValue = 1023;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Back */
//  leftValue = -1023;
//  rightValue = -1023;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Spin Turn Left 超信地旋回*/
//  leftValue = -1023;
//  rightValue = 1023;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Spin Turn Right */
//  leftValue = 1023;
//  rightValue = -1023;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Pivot Turn Left 信地旋回*/
//  leftValue = 0;
//  rightValue = 1023;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Pivot Turn Right */
//  leftValue = 1023;
//  rightValue = 0;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Swich Back Pivot Turn Left 後退信地旋回*/
//  leftValue = -1023;
//  rightValue = 0;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Swich Back Pivot Turn Right 後退信地旋回*/
//  leftValue = 0;
//  rightValue = -1023;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Power Turn Left 緩旋回*/
//  leftValue = 1023;
//  rightValue = 512;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
//  /* Power Turn Right */
//  leftValue = 512;
//  rightValue = 1023;
//  motorControl(leftValue, rightValue);
//  delay(2000);
//  freeRunStop();
//
}


/* Moter Control SUB */
void motorControl(int leftValue, int rightValue) {

  if (leftValue >= 0) {
    if (leftValue >= 1023) leftValue = 1023;
    if (leftValue <= STALL) leftValue = 0;
    if (leftValue > 0) {
      analogWrite(IN1, leftValue);
      digitalWrite(IN2, LOW);
    }
    else {
      digitalWrite(IN1, LOW);
      digitalWrite(IN2, LOW);
    }
  }
  if (leftValue < 0) {
    leftValue = leftValue * -1;
    if (leftValue >= 1023) leftValue = 1023;
    if (leftValue <= STALL) leftValue = 0;
    if (leftValue > 0) {
      digitalWrite(IN1, LOW);
      analogWrite(IN2, leftValue);
    }
    else {
      digitalWrite(IN1, LOW);
      digitalWrite(IN2, LOW);
    }
  }

  if (rightValue >= 0) {
    if (rightValue >= 1023) rightValue = 1023;
    if (rightValue <= STALL) rightValue = 0;
    if (rightValue > 0) {
      analogWrite(IN3, rightValue);
      digitalWrite(IN4, LOW);
    }
    else {
      digitalWrite(IN3, LOW);
      digitalWrite(IN4, LOW);
    }
  }
  if (rightValue < 0) {
    rightValue = rightValue * -1;
    if (rightValue >= 1023) rightValue = 1023;
    if (rightValue <= STALL) rightValue = 0;
    if (rightValue > 0) {
      digitalWrite(IN3, LOW);
      analogWrite(IN4, rightValue);
    }
    else {
      digitalWrite(IN3, LOW);
      digitalWrite(IN4, LOW);
    }
  }
}

void freeRunStop() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  delay(100);
}

void suddenStop() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, HIGH);
}






続きを読む

ロボットカーでWiFiリモコンの基礎を学ぶ(その0)

冬ごもりに備えてさらなる遊びの準備。
【新品】ラジコン ロボットカー 電子工作 Arduino プログラミング 1、PayPayフリマ、コミコミで¥2,100

完成イメージ(※teatree-s氏のgithubより転載)
robot-car

teatree-s氏による紹介文より、抜粋要約。
WeMos D1 Mini と、モータードライバー Mini L298N を使ったロボットカーのキット。
D1 Mini を WiFi アクセスポイント ・Webサーバーとして仕立て、スマホやPCのWebブラウザからアクセスし、表示されたページからロボットカーを操作するというもの。
超音波即距離センサで自動運転もできるそうだ。へぇ~。
https://github.com/teatree-s/ESP8266/blob/main/ROBOT-CONTROLLER/README.md

万年初心者の自分がいきなり全部をやろうとすると消化不良になるし、サンプルプログラムを突っ込んで動きました。簡単でしたw(ドヤ)。というのは(他所でよく見かけはするものの)本ブログ的にもイチ技術者的にもどうかと思うので、構成要素を順に追って勉強していこう。


以降予定
1.モータードライバ mini L298N を使ったモーターの制御
2.超音波即距離センサ HC-SR04を使った距離測定
3.ESP8266base WeMos D1 Mini でWiFiアクセスポイントとHTTPサーバーの構築
4.PCやスマホを使ったリモコン操作

うまくできればこのように動くそうです。

ESP-WROOM-02 を使ってみた

出来心の記録。

何故今頃ESP-WROOM-02かというと、Over The Air (OTA)を最低のコストでやってみたかった。
購入したのは所謂、Arduino Uno同一形状 ESP-WROOM-02開発ボードというやつ。
UNO R3とピンの配置は同じで、ESP8266はUNOほどI/Oデバイスを持ってないので、一部のピンアサインが異なる。
今回購入したのはShenzhen Sibo Zhilian Technology Co., Ltd の ESPDUINO×1個。ヤフオクでコミコミ¥1,020。
こちらはスマート家電のメーカーらしい。技適マーク有りなので、堂々と電波を飛ばせる。
IMG_6242


もう一式がAliexpressで販売されていたESP8266baseの WeMos D1 R2×2個。コミコミ¥1,204。
こちらは当然、技適マーク無し。一応、FCC&Wifi認定品なので、輸入日から90日間1)、開発試験用で申請すれば180日間2)の試用に限られるが利用は可能だ。
IMG_6243



いずれも中華製名物ディスクリート部品のはんだ付けの荒さと雑な洗浄ではあるものの、まずまずの外観。
ソケット類を一旦全部外して付け直し、洗浄し直した。

Arduino IDE は 1.8.19 と 2.0.1でテスト。
いずれも問題なく接続できる。
1.8.19のほうが設定が一覧表になっていてわかりやすい。
WS020055

WS020056

Flash Size確認したら全部4Mだった。よしよし。

基本的な使い方はスイッチサイエンスさんの資料による。
ESP-WROOM-02開発ボードをArduino IDEで開発する方法
ESP-WROOM-02 Arduino互換ボードのデジタルI/Oの番号について

Python3.11.0をPC開発環境にインストールして自宅のWifiに繋いでみた。

リリース後かなり時間が経っている言わば十分に枯れたハードであり、先達が沢山いらっしゃるので情報には事欠かない。
開封から最初の接続テストまで概ね1時間。この手軽さはさすがArduinoファミリーだなぁ。

最後、ヘッダピンアサインが横からでもわかるようにステッカーを作成して貼っておく。
IMG_6244

また一つおもちゃを手に入れた。続きを読む
記事検索
月別アーカイブ
プロフィール

かずい

QRコード
QRコード
  • ライブドアブログ