編集履歴一覧に戻る
masayasanのアイコン画像

masayasan が 2021年10月16日20時08分20秒 に編集

コメント無し

本文の変更

# 概要 タミヤカムロボットはそれ単体でもよく出来た玩具ですが、後からマイコンボードやサーボモータを追加出来る様な構造になっています。 大分昔にArduino Nanoで改造したのですが、最近覚え始めたPICで改めて改造し直しました。 Arduino Nanoですと時折モーターの影響による電圧降下で暴走したので、Arudinoよりも低電圧で動作可能なPICの方が向いていると思います。 あと、PICの方が省スペースで設置出来るメリットがありますしね。 *備忘録も兼ねてるので、記事の内容は随時更新していきます。  取敢えずMCCの設定とプログラムを書いて、一通り書き終わったら回路図も作成していきたいです。 # DRV8830モータードライバ ## 部品選定 パワーMOSFETでHブリッジ回路組んで、モーター制御も検討しましたが、スペースの問題とI2Cで制御できるドライブがあったので秋月電子で購入したAE-DRV8830を選定。 動作電圧2.75V~なのも魅力。 ## MCC設定 ![I2Cモジュールを選択するとRC3,RC4ピンが自動的にSCL1,SDA1に設定される。](https://camo.elchika.com/64b397aafd347a18ec4c3a59734ea3ac88528765/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f34396139616662322d666261622d346631652d613034632d333863303439656138316332/) ## プログラム I2Cモジュールを選択して設定すると新たに”i2c1_master_example.c"ファイルが作成されるので、その中の”I2C1_Write1ByteRegister(i2c1_address_t address, uint8_t reg, uint8_t data)”関数を使用する。 ![](https://camo.elchika.com/b8215f42459a5f50b572c1955fd16bf5a8bdb707/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f30383632353862372d383731642d343462322d613439312d663365373964623637373831/) #include "mcc_generated_files/examples/i2c1_master_example.h"を宣言しないと、I2Cの関数が使用できないので宣言する。 スピード(電圧)は0x06-0x3F(0.48V-5.06V)まで設定出来るけど、0x06では動かない。 ``` #include "mcc_generated_files/mcc.h" #include "mcc_generated_files/examples/i2c1_master_example.h" void Forward(uint8_t Speed) { Speed=Speed<<2; Speed=Speed+0b10; I2C1_Write1ByteRegister(0x63, 0x00, Speed); I2C1_Write1ByteRegister(0x64, 0x00, Speed); __delay_ms(500); } void Back(uint8_t Speed) { Speed=Speed<<2; Speed=Speed+0b01; I2C1_Write1ByteRegister(0x63, 0x00, Speed); I2C1_Write1ByteRegister(0x64, 0x00, Speed); __delay_ms(500); } void main(void) { SYSTEM_Initialize(); while (1) { //Speed 0x06-0x3F Forward(0x16); __delay_ms(2000); Back(0x2F); __delay_ms(2000); } } ``` ## 動画 左右のモーターは可変出来るので、曲がるスピードを変えたり振り返ることも出来る。 @[youtube](https://youtu.be/CgO6-lgJeao) # 超音波センサ ## HC-SR04 トリガで超音波を発振して、反射した音波を受けるとエコー端子がONする。 詳細はスイッチサイエンスなどからデータシート確認出来るのでそちらを参照して下さい。 計算方法も乗っています。 ## MCC設定 ![キャプションを入力できます](https://camo.elchika.com/25619f0471156e08b20c7d0d6208ca53dfa99264/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f65623263633239362d373764312d343630642d623134612d366262636366626538646438/) ## プログラム 平均化しなくても、それなりに距離が出ていたので速度重視で平均化しなかった。 変数numの値を変更することで平均化回数を設定。 ``` #include "mcc_generated_files/mcc.h" #include "stdio.h" float Distance() { // uint16_t distance; int num=1; float distance1; float distance2; for (int i = 0; i < num; ++i) { RA5 = 0; __delay_us(2); RA5 = 1; __delay_us(10); RA5 = 0; uint16_t Time1 = TMR1_ReadTimer(); while (RC0 == 0 || TMR1_ReadTimer() - Time1 > 65500); Time1 = TMR1_ReadTimer(); while (RC0 == 1 || TMR1_ReadTimer() - Time1 > 65500); Time1 = TMR1_ReadTimer() - Time1; // distance=Time1; distance1 = Time1 / 8 * (331.5 + 0.61 * 20) *100 / 1000000; distance2 = distance2 + distance1; __delay_ms(60); } distance2 = distance2 / num; return (distance2); } void main(void) { SYSTEM_Initialize(); while (1) { printf("Distance_%f\n", Distance()); } } ``` ## 動画 小さくて見にくいですが、障害物を検知してモニタに表示されている数値が変化しています。 @[youtube](https://youtu.be/i4MNTxGRLWM) # 照度センサ 照度センサーと100kΩの抵抗で分圧させた電圧をPICで読み取る。 ## MCC設定 ![キャプションを入力できます](https://camo.elchika.com/ef4f51931b7c8d04bfe5f645464d0da7e10d221d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f39373833383063362d356134622d343133652d623330642d333030643337346534383031/) ## プログラム 暗くなると目が光り、明るくなると消灯する。 ``` #include "mcc_generated_files/mcc.h" void Lighton(void) { RA4 = 1; RA3 = 1; } void Lightoff(void) { RA4 = 0; RA3 = 0; } void main(void) { SYSTEM_Initialize(); while (1) { int Vale=ADCC_GetSingleConversion(channel_ANB3); if(Vale<100){ Lighton(); }else if(Vale>=200){ Lightoff(); } } } ``` ## 動画 @[youtube](https://youtu.be/zx7yeSvwI3A) # サーボモータ ## QKY66 形状はSG90と互換性があります。Amazonで20個/2000円くらいで購入。 カムロボットの両腕に取付けました。 0.5ms~2.5msのパルス信号を送ると0~180°回転します。 ## プログラム

-

PICのサーボ制御はタイマー2とCCPモジュールで可能ですが、貧弱な電源だと電圧降下が起きて複数軸のサーボは制御出来ません。

+

PICのサーボ制御はタイマー2とCCPモジュール(PWM制御)で可能ですが、貧弱な電源だと電圧降下が起きて複数軸のサーボは制御出来ません。

2軸くらいなら単三乾電池4本でもOKかもしれませんが、タンクモーターにも電源取られるので極力省エネで行きます。 今回はタイマー制御で0.5ms~2.5msのパルス信号を送り、両腕の上げ下げを行いました。 ``` #include "mcc_generated_files/mcc.h" int ServoPOSI1 = 58; int ServoPOSI2 = 58; int ServoPOSI3 = 58; int ServoPOSI4 = 58; void ServoQuickMove(int Angle1, int Angle2) { int ServoPOSI1 = Angle1; int ServoPOSI2 = Angle2; for (int i = 0; i < 1; i++) { RA6 = 1; RA3 = 1; for (int j = 0; j < ServoPOSI1; j++) { __delay_us(10); } RA6 = 0; RA3 = 0; for (int k = 0; k < 500 - ServoPOSI1; k++) { __delay_us(10); } } __delay_ms(1); for (int i = 0; i < 1; i++) { RA7 = 1; for (int j = 0; j < ServoPOSI2; j++) { __delay_us(10); } RA7 = 0; for (int k = 0; k < 500 - ServoPOSI2; k++) { __delay_us(10); } } __delay_ms(1); } void ServoMove(int delayTIME, int Angle1, int Angle2) { while (ServoPOSI1 != Angle1 || ServoPOSI2 != Angle2) { for (int i = 0; i < delayTIME; i++) { __delay_us(1); } // 0,5ms:0°_1.45ms:90°_2.4ms:180° // printf("move"); if (ServoPOSI1 < Angle1) { ++ServoPOSI1; } else if (ServoPOSI1 > Angle1) { --ServoPOSI1; } else { ServoPOSI1 = Angle1; } if (ServoPOSI2 < Angle2) { ++ServoPOSI2; } else if (ServoPOSI2 > Angle2) { --ServoPOSI2; } else { ServoPOSI2 = Angle2; } for (int k = 0; k < 5; k++) { for (int i = 0; i < 1; i++) { RA6 = 1; for (int j = 0; j < ServoPOSI1; j++) { __delay_us(10); } RA6 = 0; for (int k = 0; k < 100 - ServoPOSI1; k++) { __delay_us(10); } } __delay_us(1); for (int i = 0; i < 1; i++) { RA7 = 1; for (int j = 0; j < ServoPOSI2; j++) { __delay_us(10); } RA7 = 0; for (int k = 0; k < 100 - ServoPOSI2; k++) { __delay_us(10); } } __delay_us(1); } } } void Banzai(void) { ServoMove(10, 60, 30); __delay_ms(1000); ServoMove(10, 30, 60); __delay_ms(1000); } void main(void) { SYSTEM_Initialize(); while (1) { Banzai(); } } ``` void ServoQuickMove(int Angle1, int Angle2) void ServoMove(int delayTIME, int Angle1, int Angle2) サーボを制御する関数は二通り制作しましたが、今回は速度を遅くするServoMoveを使用しました。 ## 動画 @[youtube] (https://youtu.be/vz9aO5RjBZ4) # フォトリフレクタ ## LBR-127HLD 秋月電子で購入、100~300Ω程度の抵抗を入れて赤外線LEDを点灯。

-

電源に直結させていますが、消費電力の事を考えると、トランジスタ及びPWM制御で点灯たいので

+

電源に直結させていますが、消費電力の事を考えると、トランジスタ及びPWM制御で点灯たいので

何れ回路修正する予定。 ## MMC設定 printf関数を使ってモニタ上に表示させる設定。 ![キャプションを入力できます](https://camo.elchika.com/ba85ca10e5a00f94b5ff567008fb2ff063458df3/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f35623265353932352d336662622d343562392d613638392d616232316265653130633737/) ## プログラム 取敢えずIOチェック用のプログラムを作成。 シリアルモニタで確認出来る様にする。センサー位置の並びをあまり考えずに配線したので、ソフト上で並びを整理しておきます。

+

ロボットの左手側から#1~5番とする。 内部プルアップ抵抗を使用して、どのセンサーにも入力が無ければ"31"。 すべてのセンサーに入力があれば"0"となる。

``` #include "mcc_generated_files/mcc.h" #include "stdio.h" int PhotoRef(void) { int PhotoVal = 0; if (RA1 == 1) { PhotoVal =PhotoVal+ 0b010000; } if (RB7 == 1) { PhotoVal =PhotoVal+ 0b01000; } if (RB5 == 1) { PhotoVal =PhotoVal+ 0b0100; } if (RA0 == 1) { PhotoVal = PhotoVal + 0b10; } if (RB6 == 1) { PhotoVal =PhotoVal+ 0b01; } return PhotoVal; } void main(void) { SYSTEM_Initialize(); while (1) { //0~31の変化 printf("%d\n", PhotoRef()); } } ``` # 赤外線受信センサ ## OSRB38C9AA 秋月電子で購入。2ヶ/100円です。 38kHzの赤外線の波長を受信すると信号線がON→OFFに変化する。(信号が無い時は常時ON)

-

赤外線はTVやエアコンなどに使用されていて、メーカー毎にコード

+

赤外線はTVやエアコンなどに使用されていて、メーカー毎にコード規格がある。 今回は自分で赤外線送信機まで制作したいので、独自規格で制作する事にする。

##MCC設定 赤外線受信モジュール様にタイマー3を使用。

+

![キャプションを入力できます](https://camo.elchika.com/74374810b385304158d927cbf063b04f6ac82518/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f37323432363733382d633835642d343638662d623036322d373466326539333232303430/)

## プログラム

+

赤外線受信モジュール信号をRA2ピンに接続。 まずは単純にON,OFF時間を計測プログラムを制作。その後、信号パターンをコードかするプログラムを制作する。

``` #include "mcc_generated_files/mcc.h" #include "stdio.h" #define Mode 1 int num = 0; unsigned int IRvaltime[100]; unsigned int IRonvaletime[100]; unsigned int IRoffvaletime[100]; int point = 0; unsigned int TMR0vale = 0; unsigned int TMR1vale = 0; unsigned int TMR1onvale = 0; unsigned int TMR1offvale = 0; #if Mode==0 void main(void) { SYSTEM_Initialize(); while (1) { } } #elif Mode==1 //OnOff時間計測 void main(void) { SYSTEM_Initialize(); while (1) { TMR1vale=TMR3_ReadTimer(); while (RA2 == 0 && point == 0) { //信号ON時間計測開始 TMR1onvale = TMR3_ReadTimer() - TMR1vale; } while (RA2 == 0); TMR1onvale = TMR3_ReadTimer() - TMR1vale; while (RA2 == 1 && point == 0) { //信号ON時間登録 IRonvaletime[num] = TMR1onvale; TMR1vale = TMR3_ReadTimer(); point = 1; } while (RA2 == 1 && point == 1) { //信号OFF時間計測 TMR1offvale = TMR3_ReadTimer() - TMR1vale; if (TMR1offvale > 60000) { //信号OFF時間30ms以上の時計測中止 point = 2; } } while (RA2 == 0 && point == 1) { //信号OFF時間登録、point0へ IRoffvaletime[num] = TMR1offvale; TMR1vale = TMR3_ReadTimer(); num = num + 1; point = 0; } while (RA2 == 1 && point == 2) { //計測時間の表示と初期化 for (int i = 0; i < num; i++) { printf("[%don]%u\n", i, IRonvaletime[i]); printf("[%doff]%u\n", i, IRoffvaletime[i]); } num = 0; point = 0; } } } #endif ```

+

TVリモコンの信号は読み込んでいた。 後日、実際の波長とプログラムで表示された数値をオシロスコープで比較する。 良ければこのプログラムを元にコード読み取りのプログラムを制作する。

+

## 三菱TVリモコンの電源ボタン波形写真

+

受信器側で受信したON,OFF時間の結果

+

# 赤外線送信機の制作 送信は8byteのデータで送ることにする。

+

赤外線LEDがON→OFFしてから次に点灯するまで __delay_us(300)としたものを「0」 __delay_us(1000)としたものを「1」とする。 ##回路図 製作中 ##MCC設定 ![キャプションを入力できます](https://camo.elchika.com/03f444edb4261bd5d245e7cf8595fbcf3bd7db53/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f66373334323432302d363534332d343837342d623266392d616265303336616466336635/) ![キャプションを入力できます](https://camo.elchika.com/daea690e3fa53bf6a6cef77889f91be649640b2a/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f32366436383234302d653537302d346437632d393665332d3033656337373035313139352f39336433616435342d663362362d346235622d616464312d373634306265613432626364/) ##プログラム ``` #include "mcc_generated_files/mcc.h" #include <stdio.h> #define Mode 0 uint8_t IRData = 0b00000000; bool IRplsPattern; /* * IR_ * LED_ * LIGHT_GetValue() * FORW_ * RIGHT_ * LEFT_ * BACK_ */ void IR0(void) { for (int i = 0; i < 10; i++) { IR_SetHigh(); // LED_SetHigh(); __delay_us(13); IR_SetLow(); LED_SetLow(); __delay_us(13); } __delay_us(300); } void IR1(void) { for (int i = 0; i < 10; i++) { IR_SetHigh(); // LED_SetHigh(); __delay_us(13); IR_SetLow(); LED_SetLow(); __delay_us(13); } __delay_us(1000); } void IRblink(void) { for (int k = 0; k < 2; k++) { for (int i = 0; i < 8; i++) { IRplsPattern = IRData >> i & 1; if (IRplsPattern == 0) { IR0(); } else { IR1(); } } //STOPbit for (int i = 0; i < 10; i++) { IR_SetHigh(); __delay_us(13); IR_SetLow(); LED_SetLow(); __delay_us(13); } __delay_ms(10); } } void main(void) { SYSTEM_Initialize(); TMR1_WriteTimer(0); while (1) { if (LIGHT_GetValue() == 1 && FORW_GetValue() == 1 && RIGHT_GetValue() == 1 && RC4 == 1 && BACK_GetValue() == 1) { IRData = 0b00000000; } if (LIGHT_GetValue() == 0) { IRData = 0b00000010; LED_SetHigh(); } if (FORW_GetValue() == 0 && RC4 == 1 && RIGHT_GetValue() == 1 && BACK_GetValue() == 1) { IRData = 0b00100000; } if (FORW_GetValue() == 0 && RC4 == 0 && RIGHT_GetValue() == 1 && BACK_GetValue() == 1) { IRData = 0b00101000; } if (FORW_GetValue() == 0 && RC4 == 1 && RIGHT_GetValue() == 0 && BACK_GetValue() == 1) { IRData = 0b00100100; } if (FORW_GetValue() == 1 && RC4 == 1 && RIGHT_GetValue() == 1 && BACK_GetValue() == 0) { IRData = 0b00010000; } if (FORW_GetValue() == 1 && RC4 == 0 && RIGHT_GetValue() == 1 && BACK_GetValue() == 0) { IRData = 0b00011000; } if (FORW_GetValue() == 1 && RC4 == 1 && RIGHT_GetValue() == 0 && BACK_GetValue() == 0) { IRData = 0b00010100; } if (FORW_GetValue() == 1 && RC4 == 0 && RIGHT_GetValue() == 1 && BACK_GetValue() == 1) { IRData = 0b00001000; } if (FORW_GetValue() == 1 && RC4 == 1 && RIGHT_GetValue() == 0 && BACK_GetValue() == 1) { IRData = 0b00000100; } IRblink(); __delay_ms(100); } } ``` ## 送信側と受信器側の波形 送信器側LED波形写真 受信器側モジュールの波形写真

# DFplayer mini

+

製作中

+

## MCC設定 製作中

+

## プログラム 制作中

+