工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

トラッキングソフトウェアと互換性のあるアンテナローテーターコントローラー

コンポーネントと消耗品

>
Arduino UNO
ArduinoUnoボード
× 1
ロータリーポテンショメータ(汎用)
最大。 1Kオーム(500オームの方が効果的)
× 2
プッシュボタン付きロータリーエンコーダー
× 2
ブレッドボード(汎用)
× 1
リレーモジュール(汎用)
2モジュールx2リレーNO-Com-NC
× 2
パワーMOSFETNチャネル
パワーMOSFETモジュール(最小12V / 3A)
× 2

アプリとオンラインサービス

>
Arduino IDE

このプロジェクトについて

最新のアップデート 11月 2021

このプロジェクトは娯楽として始まり、真剣な設備になりました。

コントローラは、2つのロータリーエンコーダ、方位角と仰角を使用して、アンテナの手動測位を受け入れます。 USBで衛星追跡ソフトウェアを実行しているPCに接続すると、衛星を自動的に追跡できます。

EasyComm2プロトコル/ 9600ボーを使用するすべての追跡ソフトウェアと互換性があります。 PstRotator、WXtrack、HRD、MacDoppler ... WXtoIMGでさえローテーターを制御できます。

http://tripsintech.com/orbitron-dde-azimuth-elevation-to-serial/

のDDEプラグインを使用して、Orbitronと直接連携します。

コントローラは、追跡ソフトウェアが実際のアンテナ位置を画面に表示するために、シリアルで応答を出力します。これまでのところ、PstRotatorだけがそれを行いました。

コードはライブラリ(LCDを除く)を使用せず、下の電気回路図に従ってピンを使用して、そのまま実行されます。方位角エンコーダのボタンを押すと、すべてのアンテナの動きがすぐに停止し、方位角コマンドを10度に設定できます。手順。

ここには2つのバージョンがあります。1つはDCモーター用で、もう1つはACモーター用(リレーのみ)です。後者は、既存の商用アンテナローテーターと接続できます。

DCモーターバージョンには、よりソフトでスムーズなアンテナの動きにPWMを使用するという利点があります。角度誤差に比例した電力応答を出力します(ターゲット<->アンテナ)。したがって、アンテナが動き始めると、アンテナは徐々に加速し、目的の位置に近づくと、完全に停止するまで減速します。これは、ソフトスタート/ソフトストップとして知られています。 。調整可能なデッドゾーンがあり、アンテナはわずかなターゲットオフセットに対して移動しません。

<図>

ベータ版があります Soft-Start / Soft-Stop のバージョン ACモーターの場合、このAC-Dimmerモジュールを利用しますが、現在は方位角に対してのみ機能します。試してみたい場合は、メールでお知らせください。

あなたが180度を持っている場合。標高システム、あなたは良いです、私にメールをください。 0.1度のバージョンもあります。精度は高いですが、非常に堅実なポテンショメータの読み取り値とパラノイアコントローラの構造設計がない限り、お勧めしません。私のウェブページにはもっと多くのバージョンがあります。

建設が完了したら、 キャリブレーション手順を適用する必要があります

  • ポテンショメータのキャリブレーション 必須であり、0〜359度の正しい読み取りを保証します。 / 0〜90度、使用しているポテンショメータの種類に関係なく。
  • モーターキャリブレーション Soft-Start-Stop を調整するためだけのものです 特徴。これは、デフォルト設定が気に入らない場合に必要です。

ビデオのより詳細な説明。コードは時間の経過とともに改善され、ビデオは更新できなくなったため、このコントローラーを使用した最新の情報と個人的な経験については、私のWebページを確認してください。 https://racov.ro/index.php/2020/12/09/arduino-based-antenna-rotator-part3-software-tracking-update/

このプラットフォームは新しいコメントを通知しないので、もっと知りたい場合は私にメールを送ってください。理由はわかりません。小さな問題をできる限り解決しようと思います。 [email protected]

このプロジェクトの信頼性を高めるためにフィードバックを送ってくれたすべての人に感謝します。フィードバックをいただければ幸いです。

コード

  • ant-rot-DC-nov2021
  • ant-rot-AC-aug2021
  • ポテンショメータの校正手順
  • モーターのキャリブレーション手順
ant-rot-DC-nov2021 Arduino
このコードは、ソフトスタートストップPWM出力を備えたDCモーター用です
 / * Arduino用のAZ / ELアンテナローテーターコントローラー-DCモーター* ========================================================*コンピューターにEasyCommプロトコルを使用-追跡ソフトウェア*手動コマンド2つのロータリーエンコーダーの手段AZ-EL * * Viorel Racoviteannu * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https://racov.ro * [email protected] **私は一切の責任を負いませんこのコードの誤用*またはこのコードの使用により発生する可能性のあるあらゆる種類の損傷。 * * 2020年12月v2-シリアル通信の安定性の向上* 2021年1月-アンテナが移動しないターゲット付近のデッドゾーンの改善* 2021年4月-シリアル通信の安定性の向上* 2021年6月-移動を追跡するためのエラー比例電力。 Real Soft-Stop * 2021年8月-より高速なUSBアップデート、Az / El方向のコールドスイッチング、コードの小さな最適化* 2021年11月-Soft-Startの秘密を解き明かしました。難しくはありませんでした。 * / #include  // I2C通信用のライブラリ#include  // LCD用のライブラリ//配線:SDAピンはA4に接続され、SCLピンはA5に接続されます。//接続I2C経由でLCDに、デフォルトアドレス0x27(A0-A2はジャンパされていません)LiquidCrystal_I2C lcd(0x27、16、2); //アドレス、文字、行。//上/下矢印バイトのカスタムシンボルを宣言するDownArrow [8] ={B00000、B00100、B00100、B00100、B10101、B01110、B00100、B00000};バイトUpArrow [8] ={B00000、B00100、B01110、B10101、B00100、B00100、B00100、B00000}; / **************************** **********これはあなたが本当にアンテナの動きを微調整するところです*************** ///アンテナポテンショメータキャリブレーションintAzMin =1; //ポテンショメータの始まりintAzMax =1023; //ポテンショメータの終わりintElMin =1; int ElMax =1023; //アンテナが移動しない許容エラーintAzErr =8; int ElErr =4; //ソフトストップが始まる角度差intAmax =25; // azimuth int Emax =15; // elevation //モーターの最小および最大電力、パーセント; int PwAzMin =30; //モーターが停止せず、負荷がかかった状態で始動する最小電力int PwAzMax =100; //最速のフルパワーintPwElMin =30; int PwElMax =100; int PwAz =0; //モーターに送信される計算された電力(パーセント); int PwEl =0; / ******************************************** ************************************************** ***** ///エンコーダ変数enumAzPinAssignments {AzEncoderPinA =2、// Azエンコーダ右AzEncoderPinB =3、//エンコーダ左AzClearButton =4、//エンコーダプッシュElEncoderPinA =6、// Elエンコーダ右ElEncoderPinB =5 }; //エンコーダー左//割り込みサービスルーチンvarsunsigned int lastReportedPos =1; //変更管理静的ブール回転=false; //管理ブール値をデバウンスしますA_set =false; boolean B_set =false; int aState; int aLastState; //他の変数intAzPotPin =A0; // azimの入力ピンを選択します。ポテンショメータintAzRotPin =12; //回転方向の出力ピンを選択しますintAzPWMPin =11; //方位角PWMコマンドの出力ピンを選択しますintTruAzim =0; //計算された実際の方位角値intComAzim =0; //コマンドされた方位角値intOldTruAzim =0; //以前の方位角値を格納するintOldComAzim =0; char AzDir; // azim rotdisplayのシンボルintAzEncBut =1; //エンコーダプッシュボタンで切り替える変数intElPotPin =A1; //標高の入力ピンを選択します。ポテンショメータintElRotPin =13; //仰角回転方向の出力ピンを選択しますintElPWMPin =10; //仰角回転PWMコマンドの出力ピンを選択しますintTruElev =0; //計算された実際の標高値intComElev =0; //コマンドされた標高値intOldTruElev =0; //以前の標高値を保存するintOldComElev =0; char ElDir; //標高の記号。 rot display // AZ、EL許容値のフラグbool AzStop =false; bool ElStop =false; int ElUp =1; // 1-標高Dn、0-標高STOP、2-標高Up int StaAzim =0; //モーターの方位角を開始しますSoft-Startint PwAzStop =0; //ソフトストップintPwAzStar =0のPWM(パーセント)を計算しました。 //ソフトスタートのPWM(パーセント)を計算int StaElev =0; //モーターの仰角を開始しますSoft-Startint PwElStop =0; //ソフトストップintPwElStar =0のPWM(パーセント)を計算しました。 //ソフトスタートのPWM(パーセント)を計算しました//平均ループconst int numReadings =25; int readIndex =0; //現在の読み取り値のインデックスintazimuth [numReadings]; //アナログ入力からの読み取り値intelevation [numReadings]; int totalAz =0; //現在の合計inttotalEl =0; //シリアル通信の変数StringAzimuth ="";文字列の高さ="";文字列ComputerRead;文字列ComputerWrite; bool AZser =false; bool ELser =false; bool ANTser =false; / ***************変数宣言の終了************ / void setup(){Serial.begin(9600); Serial.setTimeout(50); // USBsataを待機するミリ秒。デフォルト1000 // LCDを開始します://lcd.begin(16,2); //矢印が正しく表示されない場合は、これを選択しますlcd.init(); lcd.backlight(); //表示名とバージョンを書き込むlcd.setCursor(0、0); //カーソルを最初の列の最初の行に設定します。(カウントは0から始まります!)lcd.print( "EasyCom AntRotor"); //「...」を表示しますlcd.setCursor(0、1); //最初の列にカーソルを置き、2番目の行にカーソルを設定しますlcd.print( "* Racov * Nov.2021"); //上向き/下向き矢印のカスタムシンボルを作成しますlcd.createChar(1、DownArrow); lcd.createChar(2、UpArrow); //ピン宣言pinMode(AzRotPin、OUTPUT); // azimを宣言します。回転方向Pinas OUTPUT pinMode(AzPWMPin、OUTPUT); //方位角PWMコマンドPinをOUTPUTとして宣言pinMode(ElRotPin、OUTPUT); //標高を宣言します。回転方向Pinas OUTPUT pinMode(ElPWMPin、OUTPUT); pinMode(AzPotPin、INPUT); pinMode(ElPotPin、INPUT); pinMode(AzEncoderPinA、INPUT); pinMode(AzEncoderPinB、INPUT); pinMode(AzClearButton、INPUT); pinMode(ElEncoderPinA、INPUT); pinMode(ElEncoderPinB、INPUT); //割り込み0のAzEncoderピン(ピンA)attachInterrupt(0、doEncoderA、CHANGE); //割り込み1のAzEncoderピン(ピンB)attachInterrupt(1、doEncoderB、CHANGE); //読み取りElEncoderPinAの初期状態aLastState =digitalRead(ElEncoderPinA); / *平均化ループの初期化* / TruAzim =(map(analogRead(AzPotPin)、AzMin、AzMax、0、359)); //方位角値0-359if(TruAzim <0){TruAzim =0;} if(TruAzim> 359){TruAzim =359;} //制限間の値を保持TruElev =(map(analogRead(ElPotPin)、ElMin、ElMax 、0、90)); // elev value 0-90 if(TruElev <0){TruElev =0;} if(TruElev> 90){TruElev =90;} //(int thisReading =0; thisReading  359){TruAzim =359;} if(TruElev <0){TruElev =0;} if(TruElev> 90){TruElev =90;} //配列内の次の位置に進みます:readIndex =readIndex + 1; //配列の最後にいる場合は、最初に折り返します:if(readIndex> =numReadings){readIndex =0;} //これはエンコーダーからコマンドを読み取ることですReadAzimEncoder(); ReadElevEncoder(); if(Serial.available()){SerComm();} // USBデータを読み取る//値が変更された場合にのみアンテナ位置の表示を更新if((millis()%500)<10){//表示をちらつかない場合(OldTruAzim!=TruAzim){DisplAzim(TruAzim、4,0); OldTruAzim =TruAzim; } if(OldTruElev!=TruElev){DisplElev(TruElev、5,1); OldTruElev =TruElev; }} //値が変更された場合にのみターゲット位置の表示を更新if(OldComAzim!=ComAzim){DisplAzim(ComAzim、12,0); OldComAzim =ComAzim; } if(OldComElev!=ComElev){DisplElev(ComElev、13,1); OldComElev =ComElev; } //これは方位角で回転しますif(TruAzim ==ComAzim){//等しい場合は、移動を停止しますAzStop =true; analogWrite(AzPWMPin、0); // Azモーターパワー=0 StaAzim =TruAzim; //これはソフトスタートの開始方位角になりますlcd.setCursor(8、0); lcd.print( "="); } else if((abs(TruAzim --ComAzim)<=AzErr)&&(AzStop ==false)){//許容範囲内であるが、等しくない場合は、AzimRotate();}を回転しますelse if(abs(TruAzim --ComAzim)> AzErr){//ターゲットが許容範囲外の場合AzStop =false; // AzimRotate();と等しくありません//回転} //これは仰角で回転しますif(TruElev ==ComElev){//等しい場合、移動を停止しますElStop =true; analogWrite(ElPWMPin、0); // Elモーター出力=0 StaElev =TruElev; //これはソフトスタートの開始標高になりますlcd.setCursor(8、1); lcd.print( "="); ElUp =0; //標高STOPのフラグ} else if((abs(TruElev --ComElev)<=ElErr)&&(ElStop ==false)){//許容範囲内であるが、等しくない場合は、ElevRotate();}を回転させますelse if(abs(TruElev --ComElev)> ElErr){//ターゲットが許容範囲外の場合ElStop =false; // ElevRotate();と等しくありません//回転} //これはAzエンコーダーのx10乗算を解釈しますwhile(AzEncBut ==10){// x10に切り替えられている間analogWrite(AzPWMPin、0); //アンテナの回転を停止しますStaAzim =TruAzim; //これはソフトスタートanalogWrite(ElPWMPin、0);の開始方位角になりますlcd.setCursor(8、0); lcd.print( "*"); ReadAzimEncoder(); if(OldComAzim!=ComAzim){//数値が変更された場合にのみ表示を更新DisplAzim(ComAzim、12、0); OldComAzim =ComAzim; }遅延(100); }} // end main LOOP // _____________________________________ // ___________proceduresdefinitions__________________void DisplAzim(int x、int y、int z){char displayString [7] =""; sprintf(displayString、 "%03d"、x); //固定長の数値(3整数)を出力しますlcd.setCursor(y、z); //先行ゼロがない場合 "__7"は "%3d"を使用しますlcd.print(displayString); // **************キャリブレーション目的************** // Serial.print( "Az"); // Serial.println( analogRead(AzPotPin));} void DisplElev(int x、int y、int z){char displayString [7] =""; sprintf(displayString、 "%02d"、x); //固定長の数値(2整数)を出力しますlcd.setCursor(y、z); //先行ゼロがない場合 "_7"は "%2d"を使用lcd.print(displayString); // **************キャリブレーション目的の場合********** **** // Serial.print( "El"); // Serial.println(analogRead(ElPotPin));} void ReadElevEncoder(){aState =digitalRead(ElEncoderPinA); // ElEncoderPinAの「現在の」状態を読み取ります// ElEncoderPinAの前の状態と現在の状態が異なる場合、それはパルスが発生したことを意味しますif(aState!=aLastState){// ElEncoderPinBの状態がElEncoderPinA状態、つまりエンコーダーが時計回りに回転していることを意味しますif(digitalRead(ElEncoderPinB)!=aState){ComElev ++;} else {ComElev-;} if(ComElev <0){ComElev =0;} if(ComElev> 90 ){ComElev =90;}} aLastState =aState; // ElEncoderPinAの以前の状態を現在の状態で更新します} void ReadAzimEncoder(){rotating =true; //デバウンサーをリセットしますif(lastReportedPos!=ComAzim){lastReportedPos =ComAzim; } delay(10); if(digitalRead(AzClearButton)==LOW){//エンコーダスイッチが押された場合遅延(250); //スイッチをデバウンスif(AzEncBut ==1){AzEncBut =10; ComAzim =int(ComAzim / 10)* 10; // 10度のComAzim。ステップ} else {AzEncBut =1; }}} // ReadAzimEncoder()を終了//変化する状態で割り込みvoid doEncoderA(){// if(rotating)delay(1); //バウンスが完了するまで少し待ちます//トランジションをテストしますが、実際に状況は変わりましたか? if(digitalRead(AzEncoderPinA)!=A_set){//もう一度デバウンスA_set =!A_set; //カウンターを調整します+ AがBをリードする場合if(A_set &&!B_set)ComAzim + =AzEncBut; ComAzim =((ComAzim + 360)%360); //エンコーダー位置は0〜359度です。回転=false; // loop()が再びヒットするまでデバウンスしません}} // Bの状態が変化すると割り込みします。これは、上記のAと同じです。voiddoEncoderB(){if(rotating)delay(1); if(digitalRead(AzEncoderPinB)!=B_set){B_set =!B_set; //カウンターを調整します-1BがAをリードする場合if(B_set &&!A_set)ComAzim- =AzEncBut; ComAzim =((ComAzim + 360)%360); //エンコーダー位置は0〜359度です。回転=false; }} void AzimRotate(){if(ComAzim> TruAzim){//これは回転方向を決定します//コールドスイッチング-方向を変える前にモーターを停止します-機械部品と電気部品を保護しますif(AzDir ==char(127)){ //以前に反対方向に回転していた場合analogWrite(AzPWMPin、0); //モーターを停止しますStaAzim =TruAzim; //これはソフトスタートdelay(200);の開始方位角になります。 //プレスイッチ遅延digitalWrite(AzRotPin、LOW); //回転ピンを非アクティブにします-右回転delay(200); //切り替え後の遅延} else {//同じdirectin、停止なし、遅延なしdigitalWrite(AzRotPin、LOW); //回転ピンを非アクティブにします-右に回転します} AzDir =char(126); // "->"} else {if(AzDir ==char(126)){//以前に反対方向に回転した場合analogWrite(AzPWMPin、0); //モーターを停止しますStaAzim =TruAzim; //これはソフトスタートdelay(200);の開始方位角になります。 //プレスイッチ遅延digitalWrite(AzRotPin、HIGH); //回転ピンをアクティブにします-左に回転しますdelay(200); //切り替え後の遅延} else {//同じdirectin、停止なし、遅延なしdigitalWrite(AzRotPin、HIGH); //回転ピンをアクティブにします-左に回転します} AzDir =char(127); // "<-"} lcd.setCursor(8、0); lcd.print(String(AzDir)); //これにより、角度エラーに比例するazim PWMピンがアクティブになります(パーセントで計算)PwAzStop =PwAzMin + round((abs(ComAzim-TruAzim))*(PwAzMax-PwAzMin)/ Amax); //ソフトストップの角度差に比例したパワーを出力する式PwAzStar =PwAzMin + round((abs(StaAzim-TruAzim))*(PwAzMax-PwAzMin)/ Amax); //ソフトスタートの角度差に比例したパワーを出力する式if(PwAzStar> PwAzStop){PwAz =PwAzStop; //最小の値を選択します} else {PwAz =PwAzStar;} if(PwAz> PwAzMax){PwAz =PwAzMax;} ​​analogWrite(AzPWMPin、round(2.55 * PwAz)); // AzimドライブPWMピンをアクティブにします} // end AzimRotate()void ElevRotate(){//これは回転方向を決定しますif(ComElev> TruElev){if(ElUp ==1){//以前に反対側で回転していた場合方向analogWrite(ElPWMPin、0); //モーターを停止しますStaElev =TruElev; //これはソフトスタートdelay(200);の開始標高になります。 //プレスイッチ遅延digitalWrite(ElRotPin、LOW); //回転ピンを非アクティブにします-UPdelay(200);を回転させます。 //切り替え後の遅延} else {//同じdirectin、停止なし、遅延なしdigitalWrite(ElRotPin、LOW); //回転ピンを非アクティブにします-上に回転します} lcd.setCursor(8、1); lcd.write(2); //上向き矢印ElUp =2; //仰角UPのフラグ} else {if(ElUp ==2){//以前に反対方向に回転していた場合analogWrite(ElPWMPin、0); //モーターを停止しますStaElev =TruElev; //これはソフトスタートdelay(200);の開始標高になります。 //プレスイッチ遅延digitalWrite(ElRotPin、HIGH); //回転ピンを非アクティブにします-UPdelay(200);を回転させます。 //切り替え後の遅延} else {//同じdirectin、停止なし、遅延なしdigitalWrite(ElRotPin、HIGH); //回転ピンを非アクティブにします-上に回転します} lcd.setCursor(8、1); lcd.write(1); //下向き矢印ElUp =1; //標高DNのフラグ} //これにより、角度エラーに比例するazim PWMピンがアクティブになります(パーセントで計算)PwElStop =PwElMin + round((abs(ComElev-TruElev))*(PwElMax-PwElMin)/ Emax); //ソフトストップの角度差に比例したパワーを出力する式PwElStar =PwElMin + round((abs(StaElev-TruElev))*(PwElMax-PwElMin)/ Emax); //ソフトスタートの角度差に比例したパワーを出力する式if(PwElStar> PwElStop){PwEl =PwElStop; //最小の値を選択します} else {PwEl =PwElStar;} if(PwEl> PwElMax){PwEl =PwElMax;} ​​analogWrite(ElPWMPin、round(2.55 * PwEl)); // ElevドライブPWMピンをアクティブにします} // end ElevRotate()void SerComm(){//読み取り値を初期化しますComputerRead ="";方位角="";標高=""; while(Serial.available()){ComputerRead =Serial.readString(); //受信データを文字列として読み取ります//Serial.println(ComputerRead); //テスト目的で受信をエコーし​​ます} //コマンドを探しますfor(int i =0; i <=ComputerRead.length(); i ++){if((ComputerRead.charAt(i)==' A ')&&(ComputerRead.charAt(i + 1)==' Z ')){// AZを読み取る場合(int j =i + 2; j <=ComputerRead.length(); j ++){if(isDigit (ComputerRead.charAt(j))){//文字が数値の場合Azimuth =Azimuth + ComputerRead.charAt(j); } else {break;}}}}} //コマンドを探していますfor(int i =0; i <=(ComputerRead.length()-2); i ++){if((ComputerRead.charAt(i )=='E')&&(ComputerRead.charAt(i + 1)=='L')){// ELを読み取った場合if((ComputerRead.charAt(i + 2))=='-'){ComElev =0; //標高が負のブレークの場合; } for(int j =i + 2; j <=ComputerRead.length(); j ++){if(isDigit(ComputerRead.charAt(j))){//文字が数値の場合Elevation =Elevation + ComputerRead.charAt( j); } else {break;}}}}} // を受信した場合if(Azimuth!=""){ComAzim =Azimuth.toInt(); ComAzim =ComAzim%360; //値を制限の間に保持します(360度以上の回転を持つトラッカーの場合)} // を受信した場合if(Elevation!=""){ComElev =Elevation.toInt(); if(ComElev> 180){ComElev =0;} if(ComElev> 90){// 90度を超えて受信した場合。 (高度180度のトラッカーの場合)ComElev =180-ComElev; // 90度未満に保ちます。 ComAzim =(ComAzim + 180)%360; //アンテナを背面で回転させます}} //アンテナ位置の問い合わせを探しますfor(int i =0; i <=(ComputerRead.length()-4); i ++){if((ComputerRead .charAt(i)=='A')&&(ComputerRead.charAt(i + 1)=='Z')&&(ComputerRead.charAt(i + 3)=='E')&&(ComputerRead.charAt(i +4)=='L')){//アンテナ位置を送り返します<+ xxx.x xx.x> ComputerWrite ="+" + String(TruAzim)+ "。0" + String(TruElev)+ "。 0 "; Serial.println(ComputerWrite); }}} //終了SerComm()
ant-rot-AC-aug2021 Arduino
ACモーターの電気回路図を使用してください
ドライ接点(ON / OFF)を提供します。市販の回転子と簡単に接続できます。
 / * Arduino用AZ / ELアンテナ回転子コントローラー-ACモーター* ========================================================*コンピューターにEasyCommプロトコルを使用-追跡ソフトウェア* 2つのロータリーエンコーダーによる手動コマンドAZ-EL **スイッチボックスローター*またはACモーターと互換性があります*左右、上下のドライインターフェース* * Viorel Racoviteannu / * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https: //racov.ro * [email protected] * *このコードの誤用*、またはこのコードの使用により発生する可能性のあるいかなる種類の損害についても、私は責任を負いません。 * * 2020年12月v2-シリアル通信の安定性の向上* 2021年1月-AZ、モーター起動のEL許容値の修正* 2021年4月-シリアル通信の安定性の向上* 2021年8月-USB更新の高速化、Az / El方向のコールドスイッチング、コードの小さな最適化* / #include  // I2C通信用ライブラリ#include  // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c(LCD用ライブラリ)//配線:SDAピンはA4に接続され、SCLピンはA5に接続されます。//I2Cを介してLCDに接続します。デフォルトアドレスは0x27(A0-A2はジャンパされていません)LiquidCrystal_I2C lcd(0x27、16、2); //アドレス、文字、行。//上/下矢印バイトのカスタムシンボルを宣言するDownArrow [8] ={B00000、B00100、B00100、B00100、B10101、B01110、B00100、B00000};バイトUpArrow [8] ={B00000、B00100、B01110、B10101、B00100、B00100、B00100、B00000}; //アンテナポテンショメータキャリブレーションintAzMin =1; //ポテンショメータの始まりintAzMax =1023; //ポテンショメータの終わりintElMin =1; int ElMax =1023; //アンテナが移動しない許容エラーintAzErr =8; int ElErr =4; // Azimエンコーダー変数enumAzPinAssignments {AzEncoderPinA =2、//エンコーダー右AzEncoderPinB =3、//エンコーダー左AzClearButton =4}; //エンコーダーpushunsigned int lastReportedPos =1; //変更管理静的ブール回転=false; //デバウンス管理//割り込みサービスルーチンvarsboolean A_set =false; boolean B_set =false; //エンコーダー変数の列挙型ElPinAssignments {ElEncoderPinA =6、//エンコーダー右ElEncoderPinB =5、//エンコーダー左ElClearButton =7}; //エンコーダーpushint aState; int aLastState; //他の変数intAzPotPin =A0; // azimの入力ピンを選択します。ポテンショメータintAzRotPinR =13; //回転方向の出力ピンを選択しますintAzRotPinL =12; int TruAzim =0; //計算された実際の方位角値intComAzim =0; //コマンドされた方位角値intOldTruAzim =0; //以前の方位角値を格納するintOldComAzim =0; char AzDir; // azim rotdisplayのシンボルintAzEncBut =1; //エンコーダプッシュボタンで切り替える変数intElPotPin =A1; //標高の入力ピンを選択します。ポテンショメータintElRotPinD =11; //仰角回転方向の出力ピンを選択しますintElRotPinU =10; int TruElev =0; //計算された実際の標高値intComElev =0; //コマンドされた標高値intOldTruElev =0; //以前の標高値を保存するintOldComElev =0; char ElDir; //標高の記号。 rot display int ElEncBut =1; //エンコーダプッシュボタンで切り替える変数// AZ、EL許容値のフラグbool AzStop =false; bool ElStop =false; int ElUp =0; // 1 =Elevation Dn、0 =Elevation STOP、2 =Elevation Up //平均化ループconstint numReadings =25; int readIndex =0; //現在の読み取り値のインデックスintazimuth [numReadings]; //アナログ入力からの読み取り値intelevation [numReadings]; int totalAz =0; //現在の合計inttotalEl =0; //シリアル通信の変数StringAzimuth ="";文字列の高さ="";文字列ComputerRead;文字列ComputerWrite; bool AZser =false; bool ELser =false; bool ANTser =false; / ***************変数宣言の終了************ / void setup(){Serial.begin(9600); Serial.setTimeout(50); // USBsataを待機するミリ秒。デフォルト1000 // LCDを開始します://lcd.begin(16,2); //矢印が正しく表示されない場合は、これを選択しますlcd.init(); lcd.backlight(); //表示名とバージョンを書き込むlcd.setCursor(0、0); //カーソルを最初の列の最初の行に設定します。(カウントは0から始まります!)lcd.print( "EasyCom AntRotor"); lcd.setCursor(0、1); //最初の列にカーソルを置き、2番目の行にカーソルを設定しますlcd.print( "* Racov * Aug.2021"); //上向き/下向き矢印のカスタムシンボルを作成しますlcd.createChar(1、DownArrow); lcd.createChar(2、UpArrow); //ピン宣言pinMode(AzRotPinR、OUTPUT); // azimを宣言します。回転方向Pinas OUTPUT pinMode(AzRotPinL、OUTPUT); pinMode(ElRotPinD、OUTPUT); //標高を宣言します。回転方向Pinas OUTPUT pinMode(ElRotPinU、OUTPUT); pinMode(AzPotPin、INPUT); pinMode(ElPotPin、INPUT); pinMode(AzEncoderPinA、INPUT); pinMode(AzEncoderPinB、INPUT); pinMode(AzClearButton、INPUT); pinMode(ElEncoderPinA、INPUT); pinMode(ElEncoderPinB、INPUT); pinMode(ElClearButton、INPUT); //割り込み0のAzEncoderピン(ピンA)attachInterrupt(0、doEncoderA、CHANGE); //割り込み1のAzEncoderピン(ピンB)attachInterrupt(1、doEncoderB、CHANGE); //読み取りElEncoderPinAの初期状態aLastState =digitalRead(ElEncoderPinA); / *平均化ループの初期化* / TruAzim =(map(analogRead(AzPotPin)、AzMin、AzMax、0、359)); //方位角値0-359if(TruAzim <0){TruAzim =0;} if(TruAzim> 359){TruAzim =359;} //制限間の値を保持TruElev =(map(analogRead(ElPotPin)、ElMin、ElMax 、0、90)); // elev value 0-90 if(TruElev <0){TruElev =0;} if(TruElev> 90){TruElev =90;} //(int thisReading =0; thisReading  359){TruAzim =359;} if(TruElev <0){TruElev =0;} if(TruElev> 90){TruElev =90;} //配列内の次の位置に進みます:readIndex =readIndex + 1; //配列の最後にいる場合は、最初に折り返します:if(readIndex> =numReadings){readIndex =0;} //これはエンコーダーからコマンドを読み取ることですReadAzimEncoder(); ReadElevEncoder(); if(Serial.available()){SerComm();} // USBデータを読み取る//値が変更された場合にのみアンテナ位置の表示を更新if((millis()%500)<10){//表示をちらつかない場合(OldTruAzim!=TruAzim){DisplAzim(TruAzim、4,0); OldTruAzim =TruAzim; } if(OldTruElev!=TruElev){DisplElev(TruElev、5,1); OldTruElev =TruElev; }} //値が変更された場合にのみターゲット位置の表示を更新if(OldComAzim!=ComAzim){DisplAzim(ComAzim、12,0); OldComAzim =ComAzim; } if(OldComElev!=ComElev){DisplElev(ComElev、13,1); OldComElev =ComElev; } //これは方位角で回転しますif(TruAzim ==ComAzim){//等しい場合は、移動を停止しますAzStop =true; digitalWrite(AzRotPinL、LOW); //回転ピンを非アクティブ化しますdigitalWrite(AzRotPinR、LOW); lcd.setCursor(8、0); lcd.print( "="); } else if((abs(TruAzim --ComAzim)<=AzErr)&&(AzStop ==false)){//許容範囲内であるが、等しくない場合は、AzimRotate();}を回転しますelse if(abs(TruAzim --ComAzim)> AzErr){//ターゲットが許容範囲外の場合AzStop =false; // AzimRotate();と等しくありません//回転} //これは仰角で回転しますif(TruElev ==ComElev){//等しい場合、移動を停止しますElStop =true; digitalWrite(ElRotPinD、LOW); //エレベータピンを非アクティブ化しますdigitalWrite(ElRotPinU、LOW); lcd.setCursor(8、1); lcd.print( "="); ElUp =0; //標高STOPのフラグ} else if((abs(TruElev --ComElev)<=ElErr)&&(ElStop ==false)){//許容範囲内であるが、等しくない場合は、ElevRotate();}を回転させますelse if(abs(TruElev --ComElev)> ElErr){//ターゲットが許容範囲外の場合ElStop =false; // ElevRotate();と等しくありません//回転} //これはx10AZ ENC乗算を解釈しますwhile(AzEncBut ==10){// x10に切り替えられている間digitalWrite(AzRotPinL、LOW); //回転ピンを非アクティブ化しますdigitalWrite(AzRotPinR、LOW); digitalWrite(ElRotPinD、LOW); //エレベータピンを非アクティブ化しますdigitalWrite(ElRotPinU、LOW); lcd.setCursor(8、0); lcd.print( "*"); ReadAzimEncoder(); if(OldComAzim!=ComAzim){//数値が変更された場合にのみ表示を更新DisplAzim(ComAzim、12、0); OldComAzim =ComAzim; } delay(100); }} // end main LOOP // _____________________________________ // ___________proceduresdefinitions__________________void DisplAzim(int x、int y、int z){char displayString [7] =""; sprintf(displayString、 "%03d"、x); //固定長の数値(3整数)を出力しますlcd.setCursor(y、z); //先行ゼロがない場合 "__7"は "%3d"を使用しますlcd.print(displayString); // **************キャリブレーション目的************** // Serial.print( "Az"); // Serial.println( analogRead(AzPotPin));} void DisplElev(int x、int y、int z){char displayString [7] =""; sprintf(displayString、 "%02d"、x); //固定長の数値(2整数)を出力しますlcd.setCursor(y、z); //先行ゼロがない場合 "_7"は "%2d"を使用lcd.print(displayString); // **************キャリブレーション目的の場合********** **** // Serial.print( "El"); // Serial.println(analogRead(ElPotPin));} void ReadElevEncoder(){aState =digitalRead(ElEncoderPinA); // ElEncoderPinAの「現在の」状態を読み取ります// ElEncoderPinAの前の状態と現在の状態が異なる場合、それはパルスが発生したことを意味しますif(aState!=aLastState){// ElEncoderPinBの状態がElEncoderPinA状態、つまりエンコーダーが時計回りに回転していることを意味しますif(digitalRead(ElEncoderPinB)!=aState){ComElev ++;} else {ComElev-;} if(ComElev <0){ComElev =0;} if(ComElev> 90 ){ComElev =90;}} aLastState =aState; // ElEncoderPinAの以前の状態を現在の状態で更新します} void ReadAzimEncoder(){rotating =true; //デバウンサーをリセットしますif(lastReportedPos!=ComAzim){lastReportedPos =ComAzim; } delay(10); if(digitalRead(AzClearButton)==LOW){//エンコーダスイッチが押された場合遅延(250); //スイッチをデバウンスif(AzEncBut ==1){AzEncBut =10; ComAzim =int(ComAzim / 10)* 10; // 10度のComAzim。ステップ} else {AzEncBut =1; }}} // ReadAzimEncoder()を終了//変化する状態で割り込みvoid doEncoderA(){// if(rotating)delay(1); //バウンスが完了するまで少し待ちます//トランジションをテストしますが、実際に状況は変わりましたか? if(digitalRead(AzEncoderPinA)!=A_set){//もう一度デバウンスA_set =!A_set; //カウンターを調整します+ AがBをリードする場合if(A_set &&!B_set)ComAzim + =AzEncBut; ComAzim =((ComAzim + 360)%360); //エンコーダー位置は0〜359度です。回転=false; // loop()が再びヒットするまでデバウンスしません}} // Bの状態が変化すると割り込みします。これは、上記のAと同じです。voiddoEncoderB(){if(rotating)delay(1); if(digitalRead(AzEncoderPinB)!=B_set){B_set =!B_set; //カウンターを調整します-1BがAをリードする場合if(B_set &&!A_set)ComAzim- =AzEncBut; ComAzim =((ComAzim + 360)%360); //エンコーダー位置は0〜359度です。回転=false; }} void AzimRotate(){if((ComAzim-TruAzim)>(TruAzim-ComAzim)){//これは回転方向を決定する//コールドスイッチング-方向を変える前にモーターを停止する-機械部品と電気部品を保護するdigitalWrite(AzRotPinL 、 低い); //回転ピンを非アクティブ化左if(AzDir ==char(127)){delay(500);} //以前に反対方向に回転していた場合は、0.5秒待ちますdigitalWrite(AzRotPinR、HIGH); //回転ピンをアクティブにしますRightAzDir =char(126); // "->"} else {digitalWrite(AzRotPinR、LOW); if(AzDir ==char(126)){delay(500);} digitalWrite(AzRotPinL、HIGH); AzDir =char(127); // "<-"} lcd.setCursor(8、0); lcd.print(String(AzDir));} void ElevRotate(){//これは回転方向を決定しますif((ComElev-TruElev)>(TruElev-ComElev)){digitalWrite(ElRotPinD、LOW); if(ElUp ==1){delay(500);} digitalWrite(ElRotPinU、HIGH); lcd.setCursor(8、1); lcd.write(2); //上向き矢印ElUp =2; } else {digitalWrite(ElRotPinU、LOW); if(ElUp ==2){delay(500);} digitalWrite(ElRotPinD、HIGH); lcd.setCursor(8、1); lcd.write(1); //下向き矢印ElUp =1; }} void SerComm(){//読み取り値を初期化ComputerRead ="";方位角="";標高=""; while(Serial.available()){ComputerRead =Serial.readString(); //受信データを文字列として読み取りますSerial.println(ComputerRead); //テスト目的で受信をエコーし​​ます} //コマンドを探しますfor(int i =0; i <=ComputerRead.length(); i ++){if((ComputerRead.charAt(i)==' A ')&&(ComputerRead.charAt(i + 1)==' Z ')){// AZを読み取る場合(int j =i + 2; j <=ComputerRead.length(); j ++){if(isDigit (ComputerRead.charAt(j))){//文字が数値の場合Azimuth =Azimuth + ComputerRead.charAt(j); } else {break;}}}}} //コマンドを探していますfor(int i =0; i <=(ComputerRead.length()-2); i ++){if((ComputerRead.charAt(i )=='E')&&(ComputerRead.charAt(i + 1)=='L')){// ELを読み取った場合if((ComputerRead.charAt(i + 2))=='-'){ComElev =0; //標高が負のブレークの場合; } for(int j =i + 2; j <=ComputerRead.length(); j ++){if(isDigit(ComputerRead.charAt(j))){//文字が数値の場合Elevation =Elevation + ComputerRead.charAt( j); } else {break;}}}}} // を受信した場合if(Azimuth!=""){ComAzim =Azimuth.toInt(); ComAzim =ComAzim%360; //値を制限の間に保持します} // if が受信した場合if(Elevation!=""){ComElev =Elevation.toInt(); if(ComElev> 180){ComElev =0;} if(ComElev> 90){// 90度を超えて受信した場合。 (高度180度のトラッカーの場合)ComElev =180-ComElev; // 90度未満に保ちます。 ComAzim =(ComAzim + 180)%360; //アンテナを背面で回転させます}} //アンテナ位置の問い合わせを探しますfor(int i =0; i <=(ComputerRead.length()-4); i ++){if((ComputerRead .charAt(i)=='A')&&(ComputerRead.charAt(i + 1)=='Z')&&(ComputerRead.charAt(i + 3)=='E')&&(ComputerRead.charAt(i +4)=='L')){//アンテナ位置を送り返します<+ xxx.x xx.x> ComputerWrite ="+" + String(TruAzim)+ "。0" + String(TruElev)+ "。 0 "; Serial.println(ComputerWrite); }}} //終了SerComm()
ポテンショメータのキャリブレーション手順 Arduino
AZ / ELポテンショメータは、正しいアンテナ角度と回転制限を表示するための校正手順を制限します(0-359ᴼ/0-90ᴼ)
これはプレーンテキストであり、コードではありません:)
 AZ / ELポテンショメータ制限校正手順(0-359ᴼ/0-90ᴼ)これは複雑に見えるかもしれませんが、一度だけ実行する必要があります。 Arduinoでコードを開き、-void DisplAzim(int x、int y、int z){... // Serial.print( "Az"); // Serial.println(analogRead(AzPotPin));を探します。 -これらの行を削除します。次のようになります。Serial.print( "Az"); Serial.println(analogRead(AzPotPin)); --void DisplElev(int x、int y、int z){... // Serial.print( "El"); // Serial.println(analogRead(ElPotPin));これらの行も削除します。次のようになります。Serial.print( "El"); Serial.println(analogRead(ElPotPin)); 2。 Upload the code and open the Serial Monitor. There you will see a lot of numbers;3. With the help of the encoders, move the antenna to minimum values, 0ᴼ in azimuth and 0ᴼ in elevation.- Write down the values for Azimuth and Elevation. (in my case it was AzMin=90, ElMin=10)- These are the input values read by Arduino, not the real angles;4. Move the antenna again to maximum values, 359ᴼ in azimuth and 90ᴼ in elevation.- Again, write down the values for Azimuth and Elevation. (in my case it was AzMax=1000, ElMax=992);5. Look in the code, at the beginning, for the section// ANTENNA potentiometers CALIBRATION int AzMin =1; int AzMax =1023; int ElMin =1; int ElMax =1023;- Here input the values you wrote down for each situation;6. Now it is no longer necessary to send this on serial, so you have to comment back these lines, like this:// Serial.print ("Az "); // Serial.println (analogRead(AzPotPin));... // Serial.print ("El "); // Serial.println (analogRead(ElPotPin));7. Upload again the code.That's all.Now, in the serial monitor, there should be no more numbers, and the true antenna position is read correctly.
Motor calibration procedureArduino
This procedure sets the parameters for the Antenna Speed-Up / Slow-Down Zone.
This is plain text, not a code :)
Motor Calibration Procedure For Soft-Start / Soft-Stop feature.This procedure sets the parameters for the Antenna Speed-Up / Slow-Down and the Dead-Zone.You basically set how fast and how slow you want the antenna to start and to stop. You also set much the target can move, before the antenna will adjust again.It’s not strictly necessary, only if you don’t like the default settings.Make sure you first apply the Potentiometer Calibration Procedure !!! That one is strictly necessary.Look at the power diagram for a better understanding.***For Azimuth movement***-As the antenna starts to move towards the target, is picking up speed, reaching full power after  degrees difference. -As the antenna closes in to the target, below  degrees difference, it starts to slow down.  should be higher for heavier antennas.-The power starts to decrease from  to  until the angle difference becomes zero.  (in percents %) should be 100 for full speed. If you ever think your antenna rotates too fast, you can set a smaller .  (in percents %) is the minimum power for which your motor doesn’t stall and can start under load. The power output never falls below this value.-Once the antenna reaches the target position (zero degrees error), it stops and doesn’t move again until the target travels more than  degrees. This is a dead zone, to prevent continuously shaking the antenna for the smallest target movement, or potentiometer position jitter. The smaller the , the more precise tracking, the more frequent shacking of the motors.***For Elevation movement***Exactly as for the Azimuth.Look at the beginning of the code for this section. Here you can input your desired values./**************THIS IS WHERE YOU REALY TWEAK THE ANTENNA MOVEMENT************/...// Allowed error for which antennna won't move. int AzErr =8; int ElErr =4;// Angle difference where soft stop begins int Amax =25; //azimuth int Emax =15; // elevation //モーターの最小および最大電力、パーセント; int PwAzMin =30; //minimum power for which the motor doesn't stall and starts under load int PwAzMax =100; //full power for the fastest speed int PwElMin =30; int PwElMax =100;/****************************************************************************/

回路図

Make sure you use this diagram with the code for DC motors.
Connection of all the modules, encoders, LCD, relays, MosFet etc, Make sure you use this diagram with the code for AC motors.
ドライ接点(ON / OFF)を提供します。 It can be easily interfaced with commercial rotators.

製造プロセス

  1. プッシュボタンを使用したPWMによる調光ライト
  2. MPU-6050を搭載したArduinoジャイロスコープゲーム
  3. LEDとピエゾスピーカーを備えたDHT11センサー
  4. Unopad-Abletonを搭載したArduinoMIDIコントローラー
  5. 鉄人
  6. Arduinoを搭載したシンプルな障害物センサー
  7. Find Me
  8. Arduino加湿器制御
  9. ArduinoUnoと1sheeldを備えた4x4x4LEDキューブ
  10. Arduinoジョイスティック
  11. 歩数計(Arduino 101)