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

位置フィードバックを備えた高精度リニア サーボ アクチュエータの構築 – ステップバイステップ ガイド

このチュートリアルでは、リニア サーボ アクチュエータの作成方法を学びます。電圧が印加されると特定の方向に動く通常のリニア アクチュエータとは異なり、このカスタム構築のリニア サーボ アクチュエータは、簡単に制御できる正確で再現性のある動きを実現します。

これは、アクチュエータの出力動作を正確に制御できるフィードバック ループ システムを備えているため、サーボ アクチュエータと呼ばれます。

次のビデオを見るか、以下のチュートリアルを読むことができます。

概要

このリニア サーボ アクチュエータを制御するための入力は、アナログまたはデジタルのいずれかです。アナログ入力の場合は、ここに示すような任意のタイプのポテンショメータを使用できます。リニア ポテンショメータ、一般的な回転ポテンショメータ、またはたとえば回転ポテンショメータであるジョイスティックなど。

デジタル入力の場合、RC送信機でアクチュエーターを制御できます。もちろん、このセットアップには、アクチュエーターへの入力として使用される RC 受信機も必要です。

これらのアナログ入力モードとデジタル入力モードの両方で、接続に必要なワイヤは 3 本だけです。そのうち 2 本は入力デバイスへの電力供給用で、3 本目は入力信号用です。

このカスタム構築のリニア サーボ アクチュエータの優れた機能は、出力ロッドの開始位置と終了位置をカスタム設定できること、また感度やアクチュエータが入力に応答する速度を調整できることです。 

ただし、私のお気に入りの機能は、シリアル ポート通信を通じて PC またはラップトップからこのアクチュエータを制御できることです。 Arduino IDE シリアル モニターからミリメートル単位で値を入力すると、アクチュエーターがその位置に移動します。

さらに素晴らしいのは、シリアル モニターで必要な各位置で「save」と入力することで、反復可能な動きを作成したり、その位置を保存したりできます。その後、シリアル モニターで「run」と入力すると、ループ内で動きを繰り返すようにアクチュエーターに指示できます。

ここで、このカスタムビルドのリニアサーボアクチュエーターについて知っておくべきこと、それがどのように機能するか、そして私がどのように設計したかについて説明します。そうすれば、あなたも自分でリニアサーボアクチュエーターを組み立てることができます。 

仕組み

したがって、閉ループ制御システムは、AS5600 磁気回転位置センサーと、DC モーターを駆動するために実装された PID 制御に基づいています。

実際、私は前のビデオで作成したのと同じカスタム サーボ モーター コントローラー ボードを使用しています。このボードには、独自のマイクロコントローラーとその他すべてのものが含まれており、あらゆる DC モーターをスタンドアロン サーボ モーターに簡単に変えることができます。

サーボ モーターと閉ループ制御システムがどのように動作するかについての詳細な説明については、そのチュートリアルを参照してください。  

早速ですが、サーボ モーターは閉ループ制御システムであり、入力信号または目的の位置が、位置フィードバック センサーから得られるモーターの実際の位置と比較されます。

発生した差は誤差と呼ばれ、コントローラーで処理され、モーターが目的の位置に到達するまで移動するように命令されます。 

つまり、このリニア サーボ アクチュエータの動作原理はサーボ モーターと同じですが、親ネジ機構を利用してモーターの回転運動を直線運動に変換するステップが 1 つ追加されています。

リニア サーボ アクチュエータの設計

これはこのリニア サーボ アクチュエータの 3D モデルで、すべてがどのように動作するかを確認できます。

AS5600 磁気回転位置センサーはアクチュエーターの背面に配置されており、親ネジの回転を追跡します。私が使用している親ネジのピッチは 8 mm です。つまり、親ネジ ナットが 1 回転するごとに 8 mm の直線運動を行います。

AS5600 は 12 ビット エンコーダで、1 ターンあたり 4096 の位置を出力できます。 8 を 4096 で割ると、解像度は 0.001953mm になります。これは、AS5600 エンコーダが検出できる位置の最小変化です。それはとても印象深いことだと思います。 

私が使用している DC モーターは、480 RPM を出力する付属の減速ギアボックスを備えた 12V モーターです。 480 を 60 で割ると 1 秒あたり 8 回転という値が得られ、その数値を 8 で乗算すると、親ネジのピッチが 8 mm であるため、アクチュエーターの線速度は 64 mm/s になります。

このアクチュエータロッドの最大移動量は 150mm なので、開始位置から終了位置まで最高速度で約 2.5 秒、加減速を含めると約 3 秒かかります。したがって、リードスクリューの駆動には 1:1 のギアセット比を使用しました。 

リニア アクチュエータ全体の設計は、カスタム ビルドのサーボ モーター コントローラー PCB、親ネジ、親ネジ ナットのサイズに基づいています。 PCB の寸法は 40x40mm だったので、これがシリンダー ブロックの最小サイズでした。

8mmリードスクリューナットの外寸が22mmでしたので、それに合わせてロッドを設計しました。ナットとロッドは 4 本の M3 ボルトとねじインサートで接続されています。ロッドの先端にはシリンダーブロックと摺動するベアリングがあり、ロッドのガイドと回り止めの役割を果たしています。 

出力シリンダー キャップには、シリンダー ブロックからロッドを導く 4 つの小さなベアリングがあります。

全体として、使用されているすべてのコンポーネントを考慮すると、リニア アクチュエーターは十分にコンパクトになったと思います。

また、アクチュエータの原点復帰と開始位置の設定に使用されるマイクロ リミット スイッチをシリンダ ブロック内に取り付けることに成功しました。

3D モデルのダウンロード

Onshape を使用すると、このカスタム構築リニア サーボ アクチュエータの 3D モデルを Web ブラウザ上で直接表示および探索できます。 (そのためには Onshape アカウントが必要です。自宅で使用するために無料のアカウントを作成できます)

3D プリントに必要な STL ファイルと、この 3D モデルの STEP ファイルは Cults3D から入手できます。

さらにここで言及すべきことは、このリニア アクチュエータの最大移動長は、シリンダ ブロックとロッドの長さを増やすだけで簡単に増やすことができるということです。これらの寸法を選択したのは、すべてのパーツを 220x220mm の小さなプリント ベッドを備えた 3D プリンターに適合させたかったからです。ここで最大のパーツはロッドで、長さは 215mm です。

3D プリント

私の新しい Creality Ender-3 V3 SE は、Y 軸に沿って水平方向に印刷するという素晴らしい仕事をしました。少し送る必要がありますが、この向きでロッドを印刷することで、よりスムーズな操作とより強いロッドに貢献します。

3D プリントの場合、フィラメントの膨張を補正し、より寸法的に正確なパーツを得るために、スライシング ソフトウェアの水平拡張機能を使用することが重要です。

ここでは –0.1mm の値を使用しましたが、テスト印刷を行って、どの値が 3D プリンタに適しているかを確認する必要があります。 

大量のサポート材料の印刷を避けるために、シリンダー ブロックを Z 軸に沿って印刷しました。 Creality Ender-3 V3 SE は、このプリントでも素晴らしい仕事をしてくれました。

この 3D プリンターがその価格を考慮して提供する印刷品質には嬉しい驚きを感じました。 3D プリンターのセットアップは非常に簡単で、自動ベッドレベリング、直接押出機、優れた印刷品質、最大 250mm/s まで高速化された印刷速度を備えています。これらすべてを 200 ドル弱で提供できるため、予算が限られている人にとっては最高の 3D プリンターの 1 つとなります。

Creality ストアでこの 3D プリンターをチェックしてください。 またはアマゾン 。私のウェブサイトでの詳細なレビューもご覧ください。

組み立て

とにかく、ここに 3D プリントされたすべての部品があるので、リニア アクチュエーターの組み立てから始めることができます。

パーツリスト

このリニア サーボ アクチュエータ プロジェクトに必要なコンポーネントは、以下のリンクから入手できます。

機械的:

エレクトロニクス:

開示:これらはアフィリエイト リンクです。 Amazon アソシエイトとして、 私は対象商品を購入することで収入を得ています

親ネジ機構の組み立て

まず、リードスクリューをシリンダーベースブロックの所定の位置に取り付ける必要があります。そのためには、まず、親ネジと同じネジ山を持つこの 3D プリントされたナットを挿入する必要があります。

ナットが親ねじにしっかりとフィットするため、ねじ込むのが少し難しいですが、ここではそれが必要です。このナットはロッドが押し込まれたときの力全体を保持するため、はめ込みがきつくなるほど、より多くの力を保持することができます。それに加えて、ナットには、イモネジでシャフトに固定するためのネジ付きインサートを挿入するための穴もあります。

リードスクリューは、外径 22 mm の 2 つのボール ベアリングの助けを借りて、シリンダー ベース ブロック内の所定の位置に保持されます。

裏側にはリードスクリューを駆動するギアがあります。このギアには、適合するネジ山と、グラブ ネジで親ネジに固定するためのネジ山付きインサート用の 2 つの穴もあります。

この接続は、モーターのトルク全体を親ネジに伝達するため、滑らないようにするためにも重要です。 

このサブアセンブリを作成するには、まずネジ付きインサートをギアとナットの所定の位置に取り付ける必要があり、さらにシリンダー ブロックの一部を取り付ける必要があります。

ギアとナットを反対方向にねじ込みますが、ベアリングに軸方向の力が加わるため、きつく締めすぎないようにしてください。次に、イモネジを使用して、ナットとギアを親ネジに固定します。

固定すると、親ネジがまだ所定の位置に固定されていないことがわかります。ベアリングがシリンダー ブロック内の所定の位置に留まるように、このプレートをシリンダー ブロックに追加する必要があります。

これでこのサブアセンブリは完了です。親ネジは所定の位置にしっかりと固定され、自由に回転できます。 

次にロッドを準備します。ロッドは全長に渡って中空であり、リードスクリューを収容します。親ネジナットとロッドを接続するには、まずネジ付きインサートをいくつか取り付ける必要があります。 

ロッドの上側に、外径 13mm、内径 6mm のガイド ベアリングを取り付ける必要があります。

3D プリントした 6 mm 中空シャフトにベアリングを配置し、長さ 10 mm の M3 皿ネジでロッドに固定します。これでロッドの準備が整い、シリンダーのガイド レール内でロッドがどのようにスライドするかを確認できます。

次に、シリンダーをシリンダーベースブロックに取り付ける必要があります。ただし、その前に、マイクロ リミット スイッチを所定の位置に取り付ける必要があります。

まず、NC 接続にワイヤをはんだ付けする必要があります。ワイヤーの長さは約15cm程度にしてください。ワイヤーをシリンダー上部の穴に通し、長さ 8 mm の 2 本の M2 ボルトを使用してマイクロ リミット スイッチをシリンダーに固定します。

ガイド ベアリングが他のものにぶつからずに適切なタイミングでスイッチをトリガーするには、特にこのマイクロ リミット スイッチが必要になります。

もちろん、正確なリミット スイッチ モデルが見つからない場合は、穴と機構を変更できます。 

シリンダーをベースブロックに取り付けるには、ここにネジ付きインサートを取り付ける必要があります。次に、長さ 25 mm の M4 ボルト 2 本を使用して所定の位置に固定します。この時点では、上の 2 つのボルトだけを挿入する必要があります。

下の 2 つは、カバーの固定に同じ穴が使用されるため、ギアボックスと PCB カバーを取り付けるときに少し遅れます。 

次に、ロッドを親ネジにねじ込みます。ガイド ベアリングはシリンダーのガイド レールの間に配置する必要があります。

奥のギアを回転させるとロッドがマイクロリミットスイッチに達するまで後退します。 

次に、シリンダーキャップを所定の位置に取り付けます。シリンダー キャップには、外径 9 mm の小さなベアリングが 4 つ収容されます。これらのベアリングのシャフトは 3D プリントできます。

この軸が通っている部分は非常に小さく折れやすいので、差し込む際には注意が必要です。私も何度かそんなことがありましたので、簡単にフィットするかどうかを確認してください。これらのベアリングはロッドをサポートおよびガイドし、スムーズな操作を実現します。

シリンダー キャップは 4 本の M4 ボルトで所定の位置に固定されています。

DC モーターの取り付け

さて、次は DC モーターを所定の位置に挿入します。 DCモーターをM3ボルト6本で固定します。次に、ギアをモーター シャフトに取り付けます。

ギアを所定の位置に固定するために、2 つのネジ付きインサートとグラブネジを使用します。 

ギアが適切にペアリングされたら、リニア アクチュエーターの背面にギアと PCB カバーを取り付ける作業に進むことができます。そのためには、まずシリンダー ベース ブロックにさらにいくつかのネジ付きインサートを取り付ける必要があります。

次に、ワイヤーを DC モーターに接続します。私の場合は、DC モーターに直接はんだ付けしました。

ワイヤーの長さは20cm程度が目安です。シリンダー ベース ブロックには穴があり、そこに DC モーターとリミット スイッチの両方のワイヤーを通す必要があります。

次に、カバー上の 2 つのホルダーにもそれらを通す必要があります。そうすることで、ギアがギアから遠ざかることを確認します。 

この時点で、カバーをベース ブロックに固定できます。このためには、まず下側に 2 本の M4 ボルトを挿入する必要がありますが、完全に挿入する必要はありません。

カバーホルダーを挟むように2mmか3mmくらい残して、そのボルトをカバーと一緒に締めます。

この操作全体は少し面倒ですが、カバーをできるだけ小さく、単一のプリントにしたかったのと、PCB ホルダーがボルトの邪魔をしていたので、このようにする必要がありました。

カスタム サーボ コントローラー PCB の取り付け

とにかく、カバーの取り付けが完了したら、カスタム サーボ モーター コントローラー ボードを所定の位置に取り付けることができます。先ほども言いましたが、これは、DC モーターをサーボ モーターに変える方法を説明した前のビデオと同じコントローラーです。

ここでの主なコンポーネントは AS5600 磁気回転位置エンコーダで、出力シャフトに取り付けられた磁石の角度位置を追跡します。この場合、リードスクリューの出力ギアに磁石を取り付けます。 PCB を所定の位置に取り付けると、磁石は AS5600 センサーと完全に位置合わせされます。

PCB を固定するには、最初に M2 ナットをホルダーのスロットに挿入し、次に 4 本の M2 ボルトで PCB を締める必要があります。

あとは配線を所定の位置に接続するだけです。 DC モーターのワイヤはモーターの端子台に接続されており、コントローラー プログラムと一致するように極性をさらに確認する必要があります。

実際には、モーターを PCB に接続する前に、モーターに電圧を印加して、リード スクリュー機構が適切に動作するかどうかを確認できます。

リミット スイッチ ワイヤに関しては、この目的のための専用ピンがないため、グランド ワイヤを電解コンデンサのグランド パッドにはんだ付けし、NC 接続ワイヤを SCK ピン (ATMEGA328 マイクロ コントローラのデジタル ピン番号 13) にはんだ付けしました。

電源用の端子台はカバーの側面のすぐ横にあるので、5.5 mm 電源コネクタを接続する穴があります。

DCモータードライバーにもヒートシンクを追加しました。最後に、スナップフィットの蓋を裏側に取り付けることができ、これでこのプロジェクトは完了です。 

これで、任意のタイプのポテンショメータまたは RC 受信機を適切な入力ピンに接続できるようになり、それを使用してリニア アクチュエータの位置を制御できるようになります。

すでに述べたように、前のビデオでは、このコントローラーがどのように機能するか、回路図、および PCB をどのように作成したかについて詳しく説明しました。

したがって、このコントローラー ボードを作成したい場合は、そのチュートリアルを確認する必要があります。 

回路図

早速ですが、主なコンポーネントは AS5600 磁気センサーで、アクチュエーター出力の位置を追跡します。センサー データは、このサーボ コントローラー ボードの頭脳である Atmega328 マイクロコントローラーに入力され、そこで計算が行われ、DRV8871 DC モーター ドライバーに DC モーターの駆動方法が指示されます。

DRV8871 DC モーター ドライバーは、最大 3.6A のピーク電流を処理できます。ボードに電力を供給するには、12V を使用し、Atmega328 および他の 5V コンポーネント用の ASM1117 電圧レギュレータを使用して 5V に降圧します。 2 チャンネルの DIP スイッチがあり、アクチュエータの入力モード (アナログまたはデジタル、またはシリアル ポート通信経由) を選択します。

トリマー ポテンショメータの 1 つはアクチュエータの感度の調整に使用され、SDM プッシュ ボタンは開始位置と終了位置の設定に使用されます。

PCBWay に PCB を注文しました。ここでは、ガーバー ファイルをアップロードし、PCB のプロパティを選択して、手頃な価格で注文するだけです。

PCBを4層になるように設計し、真ん中の層はGND用であるため、価格が少し高くなります。 PCB の色を白に選択したことを除いて、デフォルトのプロパティは何も変更しませんでした。また、追加料金なしで、該当する場合は表面仕上げをイマージョン ゴールドに変更することを受け入れることにチェックを入れます。

PCBWay プロジェクト共有コミュニティからガーバーを見つけてダウンロードでき、そこから PCB を直接注文することもできます。

とにかく、もちろん、このカスタムビルドのサーボ コントローラーがなくても、このリニア アクチュエーター プロジェクトを作成することもできます。

DC モーターを制御するために、ブレークアウト ボード上の AS5600 センサーを Arduino ボードと組み合わせて使用できます。

コード

次に、このリニア サーボアクチュエーターのコードを見てみましょう。

/*
 Linear Servo Actuator - Arduino Code
 by Dejan, www.HowToMechatronics.com
 Libraries:
 AS5600 encoder: https://github.com/RobTillaart/AS5600
 PID conroller: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
*/
#include "AS5600.h"
#include "Wire.h"
#include <PID_v1.h>
AS5600 as5600; // use default Wire
double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Pk1, Ik1, Dk1, DIRECT);
#define motor_IN1 5
#define motor_IN2 6
#define ch1 2
#define setButton 7
#define inputSwitch 3
#define modeSwitch 4
#define limitSwitch 13
int ch1Value;
long encoderValue, desiredValue, pwmValue;
String serialInput = ""; // string to hold input
int serialIntInput;
double totalDistance = 0;
long startPosition = 358;
long endPosition = 6750;
long rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
float angleValue = 0;
float rodPosition;
float positionsArray[100];
int positionsCounter = 0;
long quadrantNumber = 2;
long previousQuadrantNumber = 3;
long numberOfTurns = 0;
float totalAngle = 0;
char incomingByte = 0;
int intInput = 0;
void setup() {
 Serial.begin(115200);
 Serial.println(__FILE__);
 Serial.print("AS5600_LIB_VERSION: ");
 Serial.println(AS5600_LIB_VERSION);
 Wire.begin();
 pinMode(motor_IN1, OUTPUT);
 pinMode(motor_IN2, OUTPUT);
 // Activate the Arduino internal pull-up resistors
 pinMode(setButton, INPUT_PULLUP);
 pinMode(inputSwitch, INPUT_PULLUP);
 pinMode(modeSwitch, INPUT_PULLUP);
 pinMode(limitSwitch, INPUT_PULLUP);
 // PID Setup
 myPID.SetMode(AUTOMATIC);
 myPID.SetOutputLimits(-255, 255);
 myPID.SetSampleTime(20);
 // --- HOMING ----
 // Move backward until you ...
 while (digitalRead(limitSwitch) != 1) {
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, 70);
 encoderValue = as5600.readAngle();
 }
 while (digitalRead(limitSwitch) != 0) {
 analogWrite(motor_IN1, 50);
 digitalWrite(motor_IN2, LOW);
 }
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 startPosition = as5600.readAngle() * 0.087890625;
 endPosition = 6000;
 Setpoint = startPosition;
 // --- HOMING End ---
}
void loop() {
 // Read encoder value - current position
 rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
 // Serial communication mode - Read data from the serial monitor
 if (digitalRead(modeSwitch) == 0) {
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 // If "save" string is sent through the serial monitor, save the current rodPosition into the array
 if (serialInput == "save") {
 positionsArray[positionsCounter] = totalDistance;
 delay(1000);
 positionsCounter++;
 }
 // Clear the saved positions
 if (serialInput == "clear") {
 // Clear the array data to 0
 memset(positionsArray, 0, sizeof(positionsArray));
 positionsCounter = 0;
 }
 // Convert the String to Integer and use it as a Setpoint for the PID control
 serialIntInput = serialInput.toInt();
 if (serialIntInput != 0) {
 if (serialIntInput < 0) {
 serialIntInput = 0;
 }
 if (serialIntInput > 150) {
 serialIntInput = 150;
 }
 Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
 }
 }
 
 // Run stored positions
 if (serialInput == "run") {
 while (serialInput != "stop") {
 for (int i = 0; i <= positionsCounter - 1; i++) {
 if (serialInput == "stop") {
 break;
 }
 while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
 // Desired position / setpoint for the PID contorller
 Setpoint = positionsArray[i];
 // Read encoder - use that value as an Input for the PID control
 readEncoder();
 // Run motor - PID controller inside
 runMotor();
 
 }
 delay(2000); // Delay between steps 
 // Check the serial monitor for a stop command
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 }
 }
 }
 }
 }
 // Potentiometer and RC Receiver control mode
 else if (digitalRead(modeSwitch) == 1) {
 if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 desiredValue = analogRead(A0);
 if (desiredValue < 15) {
 desiredValue = 15;
 }
 if (desiredValue > 1008) {
 desiredValue = 1008;
 }
 Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
 
 } else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 if (desiredValue < 1000 || desiredValue > 2000) {
 desiredValue = 1000;
 }
 Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
 }
 }
 
 // Confine the minimum and maximum values of the setpoint
 if (Setpoint > endPosition) {
 Setpoint = endPosition;
 }
 if (Setpoint < startPosition) {
 Setpoint = startPosition;
 }
 // Adjusting sensitivity
 //Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term 
 //myPID.SetTunings(Pk1, Ik1, Dk1);
 // Read encoder - use that value as an input for the PID control
 readEncoder();
 // Run motor
 runMotor();
 // Set start and end positions by pressing the "set" button
 if (digitalRead(setButton) == LOW) {
 delay(3000);
 if (digitalRead(setButton) == LOW) {
 endPosition = totalDistance;
 while (digitalRead(setButton) != HIGH)
 ;
 } else {
 startPosition = totalDistance;
 }
 }
}
void readEncoder() {
 // Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
 encoderValue = as5600.readAngle() * 0.087890625;
 // Quadrant 1
 if (encoderValue >= 0 && encoderValue <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (encoderValue >= 90 && encoderValue <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (encoderValue >= 180 && encoderValue <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (encoderValue >= 270 && encoderValue <= 360) {
 quadrantNumber = 4;
 }
 if (quadrantNumber != previousQuadrantNumber) {
 // Transition from 4th to 1st quadrant
 if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
 numberOfTurns++;
 }
 // Transition from 1st to 4th quadrant
 if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
 numberOfTurns--;
 }
 previousQuadrantNumber = quadrantNumber;
 }
 if (totalDistance >= 0) {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 } else {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 }
 // Establish Input value for PID
 Input = totalDistance; // current value of the position
}
void runMotor() {
 // Run PID process to get Output value
 myPID.Compute();
 // Move right
 if (Output > 1) {
 pwmValue = Output;
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 analogWrite(motor_IN1, pwmValue);
 digitalWrite(motor_IN2, LOW);
 }
 // Move left
 else if (Output < 1) {
 pwmValue = abs(Output);
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }
 // Do not move
 else if (Output > -1 && Output < 1) {
 pwmValue = 0;
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 }
}
Code language: PHP (php)

コードの説明

したがって、エンコーダー値またはアクチュエーターの現在位置を読み取り、それをミリメートルに変換することでループを開始します。

// Read encoder value - current position
 rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
Code language: PHP (php)

次に、「シリアル通信モード」にいる場合は、シリアル モニターに入力した受信データを読み取ります。入力が「保存」の場合はアクチュエータの現在位置を保存し、「クリア」の場合はすでに保存されている位置をすべてクリアします。

// Serial communication mode - Read data from the serial monitor
 if (digitalRead(modeSwitch) == 0) {
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 // If "save" string is sent through the serial monitor, save the current rodPosition into the array
 if (serialInput == "save") {
 positionsArray[positionsCounter] = totalDistance;
 delay(1000);
 positionsCounter++;
 }
 // Clear the saved positions
 if (serialInput == "clear") {
 // Clear the array data to 0
 memset(positionsArray, 0, sizeof(positionsArray));
 positionsCounter = 0;
 }Code language: JavaScript (javascript)

入力が 0 ~ 150 の整数または数値の場合、その値を設定値として使用します。

// Convert the String to Integer and use it as a Setpoint for the PID control
 serialIntInput = serialInput.toInt();
 if (serialIntInput != 0) {
 if (serialIntInput < 0) {
 serialIntInput = 0;
 }
 if (serialIntInput > 150) {
 serialIntInput = 150;
 }
 Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
 }
 }Code language: JavaScript (javascript)

値はミリメートルで入力しますが、回転シャフトを追跡するために度を使用しているため、ミリメートルの値に 45 を掛けて度の値に変換します。これは、1 mm の直線運動の場合、リード スクリューは 45 度回転する必要があるためです。親ネジのピッチが異なる場合、この数値も異なるはずです。 

「run」と入力すると、while ループと for ループを使用して、プログラムは保存された位置を繰り返し実行します。

// Run stored positions
 if (serialInput == "run") {
 while (serialInput != "stop") {
 for (int i = 0; i <= positionsCounter - 1; i++) {
 if (serialInput == "stop") {
 break;
 }
 while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
 // Desired position / setpoint for the PID contorller
 Setpoint = positionsArray[i];
 // Read encoder - use that value as an Input for the PID control
 readEncoder();
 // Run motor - PID controller inside
 runMotor();
 
 }
 delay(2000); // Delay between steps 
 // Check the serial monitor for a stop command
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 }
 }
 }
 }Code language: JavaScript (javascript)

一方、ポテンショメータおよび RC 受信機制御モードの場合は、アナログ入力があるかデジタル入力があるかを確認します。

// Potentiometer and RC Receiver control mode
 else if (digitalRead(modeSwitch) == 1) {
 if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 desiredValue = analogRead(A0);
 if (desiredValue < 15) {
 desiredValue = 15;
 }
 if (desiredValue > 1008) {
 desiredValue = 1008;
 }
 Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
 
 } else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 if (desiredValue < 1000 || desiredValue > 2000) {
 desiredValue = 1000;
 }
 Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
 }
 }Code language: JavaScript (javascript)

アナログの場合、ポテンショメータからアナログ入力を読み取り、その値をセットポイント、つまりアクチュエータが移動する望ましい位置として使用します。同様に、入力がデジタルの場合、RC 受信機から受信データを読み取り、その値を設定値として使用します。 

次に、readEncoder() および runMotor() カスタム関数を呼び出して、アクチュエータの現在位置を読み取り、PID 制御を実行します。 readEncoder() 関数を使用して、センサーの現在値を角度値で読み取り、これらの if ステートメントを使用して、シャフトの現在位置がどの象限にあるかを追跡します。

void readEncoder() {
 // Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
 encoderValue = as5600.readAngle() * 0.087890625;
 // Quadrant 1
 if (encoderValue >= 0 && encoderValue <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (encoderValue >= 90 && encoderValue <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (encoderValue >= 180 && encoderValue <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (encoderValue >= 270 && encoderValue <= 360) {
 quadrantNumber = 4;
 }
 if (quadrantNumber != previousQuadrantNumber) {
 // Transition from 4th to 1st quadrant
 if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
 numberOfTurns++;
 }
 // Transition from 1st to 4th quadrant
 if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
 numberOfTurns--;
 }
 previousQuadrantNumber = quadrantNumber;
 }
 if (totalDistance >= 0) {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 } else {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 }
 // Establish Input value for PID
 Input = totalDistance; // current value of the position
}Code language: HTML, XML (xml)

この情報により、シャフトがどのように回転するか、いつ完全に回転するかを追跡できます。合計角度は、PID コントローラーの入力値です。 

トリマー ポテンショメータからのアナログ入力を使用して、PID コントローラーの比例ゲインを調整し、最後に PID プロセスを実行して出力値を取得します。

// Adjusting sensitivity
 //Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term 
 //myPID.SetTunings(Pk1, Ik1, Dk1);Code language: JSON / JSON with Comments (json)
void runMotor() {
 // Run PID process to get Output value
 myPID.Compute();
 // Move right
 if (Output > 1) {
 pwmValue = Output;
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 analogWrite(motor_IN1, pwmValue);
 digitalWrite(motor_IN2, LOW);
 }
 // Move left
 else if (Output < 1) {
 pwmValue = abs(Output);
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }
 // Do not move
 else if (Output > -1 && Output < 1) {
 pwmValue = 0;
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 }
}Code language: JavaScript (javascript)

その出力値は、PID コントローラーからの出力値に応じて、またはエンコーダーが読み取る望ましい位置と実際の位置との間の誤差に応じて、PWM 信号で DC モーターを左または右、または静止位置で駆動するために使用されます。

PID コントローラーの 3 つの項、比例、積分、微分が上部で定義されており、これらを調整することでさまざまな出力応答を得ることができます。

double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;Code language: JavaScript (javascript)

品質、アクチュエータがどの程度うまく動作するか、または入力に応答するかは、これらの値に直接依存します。

テスト

ここではアクチュエーターの精度をテストしています。きちんと元の位置に戻ります。それからaさんはロッドを1ミリずつ動かし始めました。最初の動きは1mmではなく0.8mmのようでしたが、次の4つは1mmに十分近かったです。  すると4mmの動きは0.15mmほどずれていました。 

ロッドには約0.25mmのバックラッシュがあることに注意してください。このバックラッシュは、親ねじと親ねじナットの間にあります。それに加えて、おそらく 3D プリントされたギアや DC モーター自体のギアにも多少のバックラッシュがあると思われます。  

もちろん、ロッドに力を加えて精度をテストすると、さらに大きな誤差が生じますが、これは PID コントローラーを微調整することで改善できます。 

ただし、このチュートリアルはこれですべてです。楽しんでいただき、何か新しいことを学んでいただければ幸いです。


製造プロセス

  1. 温度センサー
  2. Dodge The Defs!
  3. BrickPi Bookreader
  4. 高炉プロセスの自動化、測定、および制御システム
  5. SMSでボードをローカライズする
  6. RFIDパススルーでの従業員の非接触温度制御
  7. インベストメント鋳造と他の金属鋳造法との比較
  8. プロトタイプ射出成形金型と生産射出成形金型
  9. Arduinoポケットゲームコンソール+ A-Maze-Maze Game
  10. 最新の化学物質回収システム:紙パルプの効率と持続可能性を強化
  11. 自動車に使われるバッテリーを理解する