エアシリンダーをサーボ制御する
はじめに
みなさん、ロボット作りたいと思ったことはありますか?
最近はArduinoなどのマイコンでRCサーボモーターも簡単に動かすことができますし、ROSを活用すればセンサリングも簡単に行えます。
しかし、アニメやSF映画に登場するようなロボットと作るには「パワーが足りない。」「高価なモーターは買えない。」と困ったことはないでしょうか?
そこで私は空気圧という動力源を目を向けました。
制御系を考える
ロボットを作るにあたって動きを制御することは欠かせません。
そこでエアシリンダーを使って伸び量の制御を行っていきます。
構成は以下の図のように
制御コンピュータ:Arduino
制御器:バルブ
制御対象:エアシリンダー
位置センサー:可変抵抗
を使っていきます。
ボリュームは指示値の入力に使用しています。
エアシリンダーとバルブ
まずはエアシリンダーとバルブを用意します。
エアシリンダは国産であればSMC,コガネイ,CKDなどのメーカーがあります。
しかし、小型のものでも2,3千円の価格がついています。
今回は3Dプリンタを使用して製作した自作のシリンダーを動かしていきます。
バルブも同様に自作したものを使用します。
こちらのバルブの設計データはGrabCADのサイトにて公開していますので興味があればダウンロードしてみてください。
このバルブはシリンダーのサーボ制御に使用するためサーボバルブと呼んでいきます。
仕組みとしては以下の動画をご覧ください。
サーボモーターを動作させることでバルブのスプールを動かし、空気圧の方向と流量を調整します。
制御プログラム
Arduinoでエアシリンダーをサーボ制御させるためのプログラム(スケッチ)を書いていきます。
制御方法としてはPID制御を使っていきます。
ざっくりと比例制御の部分を考えていきます。
指示値=ボリューム(ポテンショメータ)=pm
現在値=可変抵抗(リニアセンサー)=lm
この2つの値の差を0にしていくプログラムを考えていきます。
差の量をそのままバルブの開度に反映させて調整します。
また、エアシリンダーの伸び量は2つのポートのどちらに空気を送るかによって変化します。
そのため、指示値に対して現在値が届いていないのか、伸びすぎなのかを判断する必要があります。
これは2つの値を引き算した際の正負をそのまま活用します。
#include <Servo.h>
Servo servo0;
int val0 = A0; // コマンド
int val1 = A1; // シリンダー
int pm; // ポテンショメータの定義
int ls; // リニアセンサーの定義
float targetAngle; // 目標角度
float currentAngle; // 現在の角度
float error; // 現在の偏差
float prevError = 0.0; // 前回の偏差
float integral; // 積分項
float derivative; // 微分項
float kp = 0.6; // 比例ゲイン
float ki = 0.6; // 積分ゲイン
float kd = 0.2; // 微分ゲイン
float dt = 0.01; // 固定の周期(例: 0.01秒)
float integralMin = -100.0; // 積分項の下限値
float integralMax = 100.0; // 積分項の上限値
void setup() {
Serial.begin(9600);
servo0.attach(6); // 6番ピンからモーター信号を出力
}
void loop() {
pm = analogRead(val0); // ボリュームセンサーの値を読み取る
ls = analogRead(val1); // リニアセンサーの値を読み取る
Serial.print(1200);//縦軸固定用
Serial.print("\t");
Serial.print(pm);//ボリュームセンサーの値出力
Serial.print("\t");
Serial.print(ls);//リニアセンサーの値出力
Serial.print("\t");
delay(0);
// エアシリンダーの角度を計算
targetAngle = map(pm, 0, 1023, 20, 170); // ボリュームセンサーの範囲を角度の範囲にマッピング
currentAngle = map(ls, 0, 1023, 20, 170); // リニアセンサーの範囲を角度の範囲にマッピング
// 偏差を計算
error = targetAngle - currentAngle;
// PID制御計算
integral += error * dt;
// 積分項の制限
if (integral < integralMin) {
integral = integralMin;
}
else if (integral > integralMax) {
integral = integralMax;
}
derivative = error - prevError;
float output = kp * error + ki * integral + kd * derivative;
// 制御信号をサーボモーターに出力
servo0.write(90+ output);
Serial.print(output);
Serial.print("\n");
delay(10);
prevError = error;
delay(10);
}
動作確認
追従の悪いところやオーバシュート気味のところもありますが、思い通りの動きになりました。
最後に
現在シリンダー単体の動作までですが、これからパラレルリンク機構や4脚ロボットの開発を進めていきます。また、圧力センサーを組み込んだ力制御やバルブ改良による高速化なども研究していきます。
空気圧アクチュエータを使ってみたいという方はぜひ真似をしていってください。
X(twitter)のDMなどでもご相談も承ります!