2022年9月23日金曜日

Sky Fight X用に260mAhのバッテリを試してみた。

 1000円で買ったSky Fight X、やっぱりバッテリが1個だと5分ぐらいしか遊べないので追加のバッテリを買ってみた。公式だと880円ぐらいするし、HS210用のやつも結構高いのでPHコネクタで入りそうなサイズのものをAliexpressでポチった。

もともと付属していたのが702025の220mAだったんだけど、今回は751732の260mAにしてみた。純正の交換用は852025の300mAっぽいけど。
純正のCレートがわからないけどとりあえず25Cのものを選択。どうやらCレートが低いと容量があっても1分ぐらいしか飛ばないらしい。容量詐欺の疑いもあるけど…

JJRCの260mAh 25Cが10個入で2550円だった。コネクタはPHコネクタで極性も純正と同じ。e010用らしいのでサイズも良さそうな感じがしたので。
搭載してみたところ、厚みはもともとついてた220mAのやつより薄いのでバッテリホルダに入れやすい。むしろこっちのほうが純正じゃないかっていうぐらいの収まり具合だった。

とりあえず落ちるぐらいまで飛ばして4~5分ぐらいは飛ぶ感じ。本体付属の充電器にUSBチェッカーを繋いで充電してみたら充電開始時で420mAぐらいで充電している。43分で満充電で220mAhっぽいのでいい感じのバッテリかも。

そんでもって充電器も一個だと大変だし、仲間内で山分けする予定だったので充電器も10個ポチってみた。これはTP4056のTypeCタイプの充電基板。Aliexpressで10枚セット390円だった。
PHコネクタは足を広げればギリギリハンダできた。
デフォルトだと充電電流設定用の抵抗(R3)に1.2kΩがついていて1A設定になっていたので、R3を2.2kΩに変更してみた。TypeC版の基板だと抵抗は1005サイズだった。
これでUSBチェッカーで見てみると520mAぐらいだったので大丈夫だろう。本来はバッテリの方の電流を測定するべきだけど…
特に発熱とかもなく充電できた。
こんな感じで容量が小さいバッテリに使う場合はR3を変更しないと危険なので注意。

あとこの基板、TypeCなのにCC1とCC2に何もつながっていないのでTypeAのケーブルしか使えない。

これでバッテリ3個ぐらい運用ならちょうどよい感。HS210用の250mAに比べて1/3のお値段で手に入ったし。
飛び方は純正バッテリと変わらない感。


2022年9月11日日曜日

aitendoの7セグ液晶をArduinoで使ってみた。

 先日解析した、aitendoのSVM343-1っていう7セグ液晶なんだけど、Arduinoで扱いやすい様にスケッチを作ってみた。ライブラリ化するともっと使いやすいかもしれないけどあんまり大きくないのでそのままスケッチに取り込んで使ってもいいかなとか思ったり。

ベースはこの前の解析用スケッチで、HT1621にソフトウェアSPIでデータを送るんだけど、各桁に表示しやすいようにした感じ。桁をまたぐようにレジスタが設定されているのでちょっと面倒だったけど、バッファに一旦orで書き込んで一気に転送する形にしてみた。LCD側から読み出すこともできそうだけど面倒だったので…

#define CLOCK 12
#define DATA 13
#define CS 11

#define COMMAND_MODE 0b10000000
#define WRITE_MODE 0b10100000

#define SYS_EN 0b00000010   //LCDバイアス発生機と発振器有効化
#define LCD_OFF 0b00000100  //LCDバイアス発生機無効化
#define LCD_ON 0b00000110   //LCDバイアス発生機有効化
#define RC256K 0b00110000   //内蔵RC発振器使用 (256kHz)

//7セグ表示用リスト
const uint8_t numArray[11] = {
  0b00111111,  //0
  0b00000110,  //1
  0b01011011,  //2
  0b01001111,  //3
  0b01100110,  //4
  0b01101101,  //5
  0b01111101,  //6
  0b00000111,  //7
  0b01111111,  //8
  0b01101111,  //9
  0b01000000   //マイナス
};

void writeBits(uint8_t data, uint8_t cnt) {
  for (uint8_t i = 0; i < cnt; i++, data <<= 1) {
    digitalWrite(CLOCK, LOW);
    digitalWrite(DATA, data & 0x80 ? HIGH : LOW);
    digitalWrite(CLOCK, HIGH);
  }
}

void write(uint8_t address, uint8_t data) {
  digitalWrite(CS, LOW);
  writeBits(WRITE_MODE, 3);
  writeBits(address << 3, 6);
  writeBits(data, 8);
  digitalWrite(CS, HIGH);
}

void cmd(uint8_t data) {
  digitalWrite(CS, LOW);
  writeBits(COMMAND_MODE, 4);
  writeBits(data, 8);
  digitalWrite(CS, HIGH);
}

void setSegments(uint8_t segData[4], uint8_t dotData) {
  uint8_t lcdBuffer[16] = {};
  for (uint8_t i = 0; i < 4; i++) {
    if (i <= 1) {
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00000001) << 3;  //a
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00000010) << 6;  //b
      lcdBuffer[15 - 2 * i] |= (segData[i] & 0b00100000) << 2;  //f
      lcdBuffer[15 - 2 * i] |= (segData[i] & 0b01000000) >> 3;  //g
    } else {
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00000001) << 7;  //a
      lcdBuffer[13 - 2 * i] |= (segData[i] & 0b00000010) << 2;  //b
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00100000) >> 2;  //f
      lcdBuffer[15 - 2 * i] |= (segData[i] & 0b01000000) << 1;  //g
    }
    lcdBuffer[1 + 2 * i] |= (segData[i] & 0b00000100) << 5;  //c
    lcdBuffer[2 * i] |= (segData[i] & 0b00001000);           //d
    lcdBuffer[2 * i] |= (segData[i] & 0b00010000) << 3;      //e
  }
  lcdBuffer[5] |= (dotData & 0b00000001) << 3;  //2桁目のドット
  lcdBuffer[3] |= (dotData & 0b00000010) << 2;  //3桁目のドット
  lcdBuffer[1] |= (dotData & 0b00000100) << 1;  //4桁目のドット
  lcdBuffer[11] |= (dotData & 0b00001000);      //コロン
  for (uint8_t i = 0; i < 16; i++) {
    write(i, lcdBuffer[i]);
  }
}

void displayInt(int intData, uint8_t dotPos) {
  uint8_t data[4] = {};
  uint8_t digit = 1;
  data[3] = numArray[abs(intData) % 10];
  if (abs(intData) > 9) {
    data[2] = numArray[abs(intData) / 10 % 10];
    ++digit;
  }
  if (abs(intData) > 99) {
    data[1] = numArray[abs(intData) / 100 % 10];
    ++digit;
  }
  if (abs(intData) > 999) {
    data[0] = numArray[abs(intData) / 1000 % 10];
    ++digit;
  }
  if (intData < 0) {
    data[3 - digit] = numArray[10];
  }
  setSegments(data, dotPos);
}

void setup() {
  pinMode(CLOCK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);

  cmd(RC256K);
  cmd(0b01010010);  // 1/3バイアス 1/4デューティー
  cmd(SYS_EN);
  cmd(LCD_ON);

  for (uint8_t i = 0; i < 16; i++) {
    write(i, 0);
  }
}

void loop() {
  static int i = 0;
  displayInt(i, 0b00000000);
  i--;
  delay(100);
}

こんな感じでとりあえずはintに対応で小数点の位置は手動で入力するタイプにしてみた。液晶の仕様上-999から9999までしか正常に表示できない。範囲外はテキトーに表示されるので注意かも。

センサのデータとかを表示したい場合はfloatのほうが使いそうなのでfloatにも対応してみたい。

2022年9月10日土曜日

7セグメント液晶を使ってみた。

 aitendoでSVM343-1っていう7セグメント液晶が安く売っていたので試しに使ってみた。SPIで制御できるようなコントローラチップが乗っているっぽい。液晶部分は秋月で売ってるSP-521に似ているんだけど、SVM343-1に搭載されている液晶は全部の桁が7セグらしい。

コントローラチップはHT1621やHT1632ではないだろうかと製品ページには書いてあったのでとりあえずArduinoで動かしてみることに。

ピンアサインは基板に直接書いてあるんだけど、ケーブルの色が全然あっていないので注意かも。
VDD(5V):黒
CLOCK:赤
DATA IN:白
バックライト:青
CS:黄色
VSS(GND):緑

とりあえずArduinoのHT1632ライブラリで動かしてみた。これは6桁の7セグ用のライブラリっぽくて一部のセグがとりあえず表示されるぐらいだった。

やっぱりこのモジュールに合わせてどのセグがどのアドレスに割り振られているのかを解析する必要がありそう…。

ということでシリアルコンソールからアドレスとデータを送ってどこのセグメントがどのアドレスなのかを調べるためのスケッチを作ってみた。

#define CLOCK 12
#define DATA 13
#define CS 11

#define COMMAND_MODE 0b10000000
#define WRITE_MODE 0b10100000

#define SYS_EN 0b00000010  //LCDバイアス発生機と発振器有効化
#define LCD_OFF 0b00000100 //LCDバイアス発生機無効化
#define LCD_ON 0b00000110  //LCDバイアス発生機有効化
#define RC256K 0b00110000  //内蔵RC発振器使用 (256kHz)

void writeBits(uint8_t data, uint8_t cnt) {
  for (uint8_t i = 0; i < cnt; i++, data <<= 1) {
    digitalWrite(CLOCK, LOW);
    digitalWrite(DATA, data & 0x80 ? HIGH : LOW);
    digitalWrite(CLOCK, HIGH);
  }
}

void write(uint8_t address, uint8_t data) {
  digitalWrite(CS, LOW);
  writeBits(WRITE_MODE, 3);
  writeBits(address << 3, 6);
  writeBits(data, 8);
  digitalWrite(CS, HIGH);
}

void cmd(uint8_t data) {
  digitalWrite(CS, LOW);
  writeBits(COMMAND_MODE, 4);
  writeBits(data, 8);
  digitalWrite(CS, HIGH);
}

void setup() {
  Serial.begin(115200);

  pinMode(CLOCK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);

  cmd(RC256K);
  cmd(0b01010010);// 1/3バイアス 1/4デューティー
  cmd(SYS_EN);
  cmd(LCD_ON);

  for (uint8_t i = 0; i < 16; i++) {
    write(i, 0);
  }
}

void loop() {
  static int i = 0;
  if (Serial.available() > 0) {
    char in = Serial.read();
    if (in == 'c') {
      Serial.println("Clear LCD");
      for (uint8_t i = 0; i < 16; i++) {
        write(i, 0);
      }
    } else if (in == 'a') {
      unsigned int input = Serial.parseInt();
      i = input;
      Serial.print("address=");
      Serial.println(input);
    } else if (in == 'd') {
      unsigned int input = Serial.parseInt();
      Serial.print("data=");
      Serial.println(input);
      write(i, input);
    }
  }
}

これでシリアルコンソールからa0と送ったあとにd255みたいにデータを送って行くとどこかが点灯するはず…
地道に試していくとデータ4と8ビット目しか使ってなかった(d8とd128にしか反応しない)

アドレスを変えながらデータを送ってみるとこんな感じになっていた。左側がアドレス、右側がデータで、結構セグメントによってバラバラ…
なので通常のHT1621ライブラリではうまく表示できないわけ。
規則性もあまりないような気がするのでちょっと使いにくいかも…

SVM343-1

同じアドレスを隣の桁でも使ってたりするので少し面倒だけど、時計用の「:」も付いてるし、小数点も付いてるのでベースのスケッチさえ作ってしまえば使えるかも。

追記:
Arduinoで扱いやすいようにライブラリまではいかないけどスケッチを作ってみた

2022年9月3日土曜日

Raspberry Pi Picoを修理してみた。

 ラズパイPicoで遊んでいたら電源を入れた瞬間は起動するのに、ちょっとすると電源が落ちてしまう用になってしまった。
なんかショートしてしまったかな?とか思って外部の回路を外して単体にしても少しすると止まってしまう。そしてmicroUSBを抜くときにボードを触ったら熱くなっている…
どこが一番熱いのかとおもって触ってみるとDCコンバータ付近が超熱くなっていたのでDCコンバータが壊れたのかなと思って修理してみた。

ラズパイPicoは3.3V駆動なのでUSBから電源を取る際に逆接防止のショットキーダイオード(MBR120VLSFT1G)を介して、DC-DCコンバータ(RT6150B-33GQW)でUSBの5Vから3.3Vを生成している。スイッチングDCコンバータなので小型でも800mAまで出力できる。

このDCコンバータ周辺がめっちゃ熱くなっているようだったのでDCコンバータが壊れたかな?と思ってRT6150B-33GQWと2.2uHのコイルを取り外してみた。そんでもって3.3VとGND間に3.3Vの電源を供給してみると普通に動いている。

Raspberry Pi Pico LDOレギュレータ仕様

ということでDCコンバータ部分をLDOに交換してみた。3.3VのLDOは手持ちでAP7333-33SAGがあったのでこれにしてみた。SOT-23パッケージで300mAまで出力できるっぽいけど、RP2040は消費電力が20mAぐらいっぽいので行けるだろうということで。DCコンバータICは結構剥がすのが大変だった。ミニホットプレートがほしいところ。斜めカットの小手先でハンダを盛って剥がした。

とりあえずこの状態で電源を入れてみると治った感じ。USBチェッカーで測定すると0.04Aってなっていた。ちなみに修理前は1.02AぐらいだったのでやっぱりRT6150B-33GQWが壊れていたんじゃないかな。RP2040が壊れてなくてよかったー。

壊れた原因はよくわからないけど、電源ラインはセラコンなので電源投入時の突入電流で発生する過電圧破壊とかかなぁ?外付け回路側の電源回路も12V入力なんだけど全部セラコンにしていたので電源スイッチの突入電流が怪しいかも。高ESRな電解コンデンサとかを入れておくべきだったか…

Raspberry Pi PicoのADCがノイズの影響を受けるのでDCコンバータをLDOに交換している人も居るらしい。LDOに交換すると3.3Vの出力できる電流が制限されそうだけどそういった効果も期待できそう。ちなみに外付け回路を接続しない状態だと触っても全くあったかくないレベルだった。

2022年8月28日日曜日

メカナムホイールのラジコンをRoverC化してみた

 前回ついにアナログスティックで操作が可能になったメカナムホイールラジコン。メカナムで充電式で2000円ぐらいのラジコンに文句は言えないが、最初からアナログスティックのほうが楽しいと思う…
でも改造楽しいしむしろコントローラなしの開発キットより断然安いのでこれもおもちゃのなせる技。

それはさておきMX1616の調査をするのにPWMの周波数変えたりDuty変えたりいろいろ試してみたけど、データシートをよく読んでみるとPWMモードAとPWMモードBの注意書きが。前回のESP32でのサンプルはPWMモードAで動かしていたんだけど、PWM周波数を高くしたいならPWMモードBのほうが良さそうな。結局データシートで言うモードAがFast DecayでモードBがSlow Decayっぽい。MX1508のライブラリを見てもFast DecayとSlow Decayが切り替えられるようになってたし…

テスト用にESP32にシリアル通信で周波数とDecayモードとDutyを変えられるようなプログラムを作ってみた。これで色々テストしてみたけど20kHzぐらいでもSlow Decayだといい感じにDuty10%ぐらいでも動く。PWM周波数も十分高いのでうるさくないし。とりあえずPWM周波数は14kHzぐらいで行こうと思う。

これでモータの回転数のリニアリティーが高まったので、今度はRaspberry Pi Picoを積んで見ることに。というのもせっかくメカナムのいい感じの車体なのでRaspberry Pi 3Bとかを乗っけてもいいかなと思ったので、ただしPWMを8ch分生成するのはマイコンのほうがいいし。
ということでRaspberry Pi Picoを乗っけて、i2c接続のモータドライバとして動かしてみようかなと。これはM5StackのRoverCも同じ様になっていたので、レジスタやアドレスもRoverC互換にしてみた。GroveコネクタにしてしまえばM5も乗るし…

i2cデバイスをArduinoで作るのは以前作ったものをベースにして、Raspberry Pi PicoからPWMを出力するだけ。Arduino公式のArduino Mbed OS RP2040 Boardsだとレジスタへの書き込みは問題ないから普通に動くんだけど、i2cdumpとか読み出しをするとフリーズしてしまうのでサードパティー製のArduino-Picoを使用した。Mbedとはi2cのポート選択方法が違うのと、pwmのヘッダファイルを手動でインクルードしないといけなかったけど、こっちのほうが快適に動く気がする。動作クロックを125Mhz以外で動かしたいときはclkdiv変更しないとPWM周波数も変わってしまうので注意。

//Raspberry Pi Pico
//Arduino-Pico(C++ SDK)
//CPU Speed 125Mhz

#include <Wire.h>
#include "hardware/pwm.h"

#define SLAVE_ADDRESS 0x38
//MbedI2C i2c_slave(p16, p17); // I2C SDA:GP16, SCL:GP17

#define DEBUG

#define M1p 2
#define M1n 3
#define M2p 4
#define M2n 5
#define M3p 6
#define M3n 7
#define M4p 8
#define M4n 9
#define PWMmax 255
uint SLICE[4];

//使用するレジスタ範囲指定
#define I2C_REG_ROW 1
#define I2C_REG_COL 4
uint8_t I2C_REG[I2C_REG_ROW][I2C_REG_COL];


//読み書きするレジスタアドレス
uint8_t REG_SELECTED;

boolean DATA_RECIEVED = false;

//i2c受信イベント
void receiveEvent(int _length) {
  //1byte目を読み込む(レジスタアドレス指定)
  REG_SELECTED = Wire.read();
  uint8_t startRow = REG_SELECTED >> 4;
  uint8_t startCol = (REG_SELECTED & 0x0F);

#ifdef DEBUG
  Serial.print("REG:");
  Serial.println(REG_SELECTED, HEX);
#endif

  while (Wire.available() > 0) {
    if (startRow < I2C_REG_ROW && startCol < I2C_REG_COL) {
      DATA_RECIEVED = true;
      I2C_REG[startRow][startCol] = Wire.read();
#ifdef DEBUG
      Serial.print("Write:");
      Serial.println(I2C_REG[startRow][startCol], HEX);
#endif
    } else {
      Wire.read();
    }
    ++startCol;
  }
}

//i2c読み込みイベント
void requestEvent() {
  uint8_t startRow = REG_SELECTED >> 4;
  uint8_t startCol = (REG_SELECTED & 0x0F);

  if (startRow < I2C_REG_ROW && startCol < I2C_REG_COL) {
    Wire.write(I2C_REG[startRow][startCol]);
  } else {
    Wire.write(0xff);
  }
}

void setup() {
#ifdef DEBUG
  Serial.begin(115200);
#endif
pinMode(LED_BUILTIN,OUTPUT);
toggle_led();

  //SlaveでWireライブラリを初期化
  Wire.setSDA(16);
  Wire.setSCL(17);
  Wire.begin(SLAVE_ADDRESS);
  //イベント設定
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);

  gpio_set_function(M1p, GPIO_FUNC_PWM);
  gpio_set_function(M1n, GPIO_FUNC_PWM);
  gpio_set_function(M2p, GPIO_FUNC_PWM);
  gpio_set_function(M2n, GPIO_FUNC_PWM);
  gpio_set_function(M3p, GPIO_FUNC_PWM);
  gpio_set_function(M3n, GPIO_FUNC_PWM);
  gpio_set_function(M4p, GPIO_FUNC_PWM);
  gpio_set_function(M4n, GPIO_FUNC_PWM);

  SLICE[0] = pwm_gpio_to_slice_num(M1p);
  SLICE[1] = pwm_gpio_to_slice_num(M2p);
  SLICE[2] = pwm_gpio_to_slice_num(M3p);
  SLICE[3] = pwm_gpio_to_slice_num(M4p);

  // PWM周期を設定
  for (int i = 0; i <= 3; i++) {
    pwm_set_clkdiv(SLICE[i], 35);  // 125,000Khz/(255*14Khz)
    pwm_set_wrap(SLICE[i], PWMmax);
    pwm_set_chan_level(SLICE[i], PWM_CHAN_A, 0);
    pwm_set_chan_level(SLICE[i], PWM_CHAN_B, 0);
    pwm_set_enabled(SLICE[i], true);
  }
}

void loop() {
  if (DATA_RECIEVED == true) {
    setspeed();
    DATA_RECIEVED = false;
  }

}

void setspeed() {
  int8_t pwm[4];
  for (int i = 0; i <= 3; i++) {
    pwm[i] = (int8_t)I2C_REG[0][i];
#ifdef DEBUG
    Serial.print("PWM:");
    Serial.println(pwm[i]);
#endif
    if (pwm[i] >= 0) {
      pwm_set_chan_level(SLICE[i], PWM_CHAN_A, (PWMmax - (pwm[i] * 2)));
      pwm_set_chan_level(SLICE[i], PWM_CHAN_B, PWMmax);
    } else {
      pwm_set_chan_level(SLICE[i], PWM_CHAN_A, PWMmax);
      pwm_set_chan_level(SLICE[i], PWM_CHAN_B, (PWMmax - abs(pwm[i] * 2)));
    }
  }
  toggle_led();
}

void toggle_led() {
  static boolean led_state = false;
  led_state = !led_state;
  digitalWrite(LED_BUILTIN, led_state);
}

とりあえずこれでi2cからモータ制御できるようになった。watchdogとかつけるべきかも…
1秒通信しなかったらタイムアウト的なやつ。
とりあえずRaspberry Pi 3Bからのコマンドではモータが動いてるけど回転のリニアリティー確認用にRoverC用のソフトをESP32に乗せてテストしてみるか…
i2cでホストが色々すげ替えられる様になったのでESP32乗っけてラジコンとして遊んでもいいしラズパイ乗っけてDonkey Carみたいなのを乗っけても面白そう。

次回は車体の上を平らにして色々乗っけられるようにしたい。

2022年8月27日土曜日

メカナムホイールのラジコンを改造してESP32で動かす

 前回分解してみたメカナムホイールのラジコン、制御基板の様子もわかったことだし改造してみた。

モータドライブICのMX1616Hはそのまま使えそうなので、基板はそのままに改造してみることに。電源スイッチや充電ポートもそのまま使えるし。
その前に改造のときに基板を動かしているとケーブルが切れそうだったのでホットボンドでケーブルを補強。
モーターにつながっているケーブルのところにホットボンドを流し込む。多分これをしておかないと振動でも切れそうなんだけど…
そしたらそしたらレシーバのIC(XC2455B)を剥がす。はんだですべての足をショートさせてはんだごて2本で外した。無理をするとパターンが持っていかれそうな基板。
そんでもってMX1616Hの入力に直接線をハンダ。ICのピンに直結したのはパターンにケーブルハンダしたら剥がれそうだったので。
そして先程と同様にホットボンドでケーブルを固定。あとGNDも引き出した。電源はとりあえず別電源で試してみようと思っているので今回は信号線のみ。
基板をもとに戻したらとりあえず準備は完了。
この上にユニバーサルプレートをマウントしたいなぁ。平面がないのでブレッドボードとか置きにくい。

とりあえず動作確認としてESP32で適当なプログラムを作ってみた。ESP32ならPWMも16ch出せるし、Bluetoothでコントローラ直結できるし。
本当はMX1616Hのロジック電圧を切り離したかったけど、基板改造が面倒だったので直結。ESP32からは出力しかないしMX1616HのHighのしきい値まで出てれば認識できるだろうし。

PWMの周波数は高すぎるとDutyが低いところで全く動かないのでとりあえず2kHzで動かしてみている。コントローラはBLEでXboxのコントローラと接続している。(Nimbleライブラリ使用)ESP32の電源は1300mAの小さなモバイルバッテリを積んでる。

とりあえずアナログのジョイスティックになるだけで断然コントロール性が上がった。オンオフしかない純正のプロポには戻れないぞ。このぐらい改造が簡単ならメカナムロボットのベースとしてもいいかも。ロボットキット買ったり、自作するよりも安いかも…
まずはPWMで動くことがわかったのでもうちょっとソフトを煮詰めよう。

しかしPWMにしてもDutyが40%以上じゃないとモータが回らなかったりしているので、もう少しPWMの設定を煮詰める必要はあるかも。
次回はモータドライバのPWM制御を改善してみる。


2022年8月26日金曜日

メカナムホイールのラジコンを分解してみた

 前回購入したメカナムホイールのラジコンを早速分解してみた。やっぱりオンオフ入力だけじゃ全然うまくコントロールできなくてすぐ飽きた…
改造してアナログ入力対応にしたいのでまずは調査。

裏側(スイッチがある方が裏)のプラスネジを6本取るとカバーが外れる。
作りは悪くない。というか思ったより良い作りをしていると思う。(改造ベースとして)
蓋を開けてもギアボックスが取れてきたりしないのでこの状態でも走れそう。
モーターは130モータが4つ。ギアボックスは前後で同じ設計のデュアルタイプのものが2つついてる。
バッテリは14500タイプのリチウムイオンバッテリだった。容量は500mAh。コネクタはPHコネクタっぽい。
JD-00742BBR-2213RX

制御基板の方は結構簡単な構造。モータドライバはMX1616Hが2つ。XC2455BってなってるICにはアンテナ出力がついていたり、モータドライバに直結されていたりしているので、2.4Ghzの無線内蔵のマイコンかな?SOT-23のICはXC2455B用の3.3Vレギュレータ。
分解する前は改造の際にモータドライバとしてDRV8833あたりを載せてもいいかなと思っていたんだけど、データシート見る限りはもともと乗っているMX1616Hがそのまま使えそうだ。MX1616Hの代わりにSA8301Sが2個乗ってるパターンもあるらしい。(VCCとVDD共通のIC)
MX1616HはMX1508とピンコンパチ。スペック的にも電子工作用に出回ってるMX1508やDRV8833に近いし、MX1508の情報がそのまま参考にできそう。MX1616とMX1616Lもあるようだけど何が違うんだろう…

電源スイッチはオフにすると充電端子に切り替わるように接続されていた。オンにすると充電器からは切り離される。充電回路はUSB端子の根本側についていた。

ちなみにモータの接続はM1が右後、M2が左後、M3が右前、M4が左前になってた。

モータドライバそのまま使えそうなので改造としてはXC2455Bを剥がして、各MX1616Hからケーブルを4本ずつ出せばいいのか。8本+GNDでモータ4個制御できそう。
ケーブルたくさん出すのが面倒なのでRoverCみたいにI2C経由でコントロールできるようにしたいなぁ。PWM8ch出せるお手軽なマイコンとかで…
まぁ8本出してきて全部ESP32に突っ込んでも良さそうだけど。

次回はついに基板を改造してみる。