ステッピングモーターの制御
ステッピングモーター、あるいは、サーボモーターの制御は、メカコントロールで必ずといって必要になるものです。
制御方法としては、シーケンサー、ステッピングモーターコントローラー、PCIボードモーターコントローラ等を利用して、モーター制御用のクロック信号を作り出し、そのクロック信号によりステッピングモーター、あるいは、サーボーモーターのドライバーでモーターの巻き線に電流を流し、モーターの回転子を回転させる方法があります。
プログラムを組む上では、モーターの回転子を一回転させるのに、何パルス必要なのか、移動させるものがある場合は、単位移動距離の移動に何パルス必要かがわかれば、モーターを回転させるための仕組みはあまり知る必要は有りませんが、モーターで、何かを移動させる場合、必ず負荷が存在し、負荷には、摩擦負荷と、加減速による慣性負荷が存在するので、モーターの出力に対して、負荷が越えないようにする必要があります。
負荷として、摩擦による負荷の発生率が高い場合、摩擦負荷の変動に注意を払う必要があります。特に粘性係数を持つ負荷の場合は、速度によって負荷が大きく変動するので注意しましょう。
慣性モーメントは、計算により求める事が出来るので、メカ設計時に計算をしておきます。
メカの設計を行う場合、摩擦負荷の予測は可なり難しく、摩擦負荷を伴う場合は、安全率を高くしてモーターの選択を行う必要があります。
モーターが正常に回転しない場合、ソフトの問題なのか、負荷に対してモーターの出力が足りないのか判別が難しくなる場合があります、コストを安くするために、特にステッピングモーターのドライバーをクロックで直接モーターの電流を制御するタイプは、衝撃荷重や、共振により脱調し、回転不良が発生する確率が高くなるので、荷重に対して安全率を高く設定する必要があります。
現在は、ステッピングモーターでも、各相に対する流す電流を制御し、磁極が増えたのかのように見せかけて駆動する、マイクロステップ、パルスエンコーダーを持ち、回転を検出して、脱調しないようにしたものがありますが、高価です、又、回転パルスを検出しながら回転させるため、与えたクロックに対して、リアルタイムに動作するのではなくて、数パルスから数十パルス以上遅れて動作するのが普通です。(”パルス溜まり” と呼ばれることもあります)
サーボモーターのドライバーも、ステッピングモーターの様に、クロックを与えることにより、クロックに同期して回転を行うドライバーが一般的になっていますので、同じモーターコントローラーで、どちらでも制御をする事が出来ます。
モータードライバーも、内部にCPUを持ち入力されたクロックにより、モーターの電流をどのように切替えるかを演算し、コントロールするタイプが一般的になっています、特にサーボモーターは、入力されたクロックよりも数倍、あるいは十倍以上の精度のパルスエンコーダーを内蔵しているので、ギヤ比として、入力クロック数と、パルスエンコーダーの比を演算し、モーターのエンコーダークロック数を決めて回転制御を行います。
又、サーボモーターの場合は、静止させる場合、少しでもずれたら位置を戻そうとすると、メカの弾性係数、制御の演算遅れ等により発信する場合があるので、ある程度の誤差は許容するようにします。
脱調レスステッピングモーター、或いは、サーボーモーターのドライバーには、パルス溜まりが発生し、制御遅れが発生するので、位置制御をする場合は注意が必要です、目標位置に達したかを出力する信号を持っているものであれば、必ずその信号を確認する必要があります。
モーターの立ち上げ時の立ち上げカーブとして、直線的に立ち上げるか、加速度を変更する時に、徐々に変更する方式があります。
徐々に変更すると、立ち上げ立ち下げカーブが S 字型になります。
加速度を急激に変更すると、その時に振動が発生したり、脱調現象が発生したりするので、滑らかに変更する為です。
滑らかに変更するためには、浮動小数点の計算、関数計算が必要なため、安価なシーケンサーには用意されていない場合があります。
コントローラーの基準クロック周波数の影響
コントローラーのモータークロックを発生するための基準クロック周波数が仕様として記載されていないものが多く、問題があります。
モーター用のクロックは、基準クロックを分周して作り出す為、モータークロックの周波数が高くなると、目的の周波数に対して、発生できる周波数の誤差が大きくなるます。
必要な周波数を発生させるのに、基準クロックを必要な周波数で割った値が整数とならない場合は、必ず誤差が発生します。
基準クロックが1MHzとして、必要な周波数が1KHz近辺とすると、最大0.1%の誤差となり、10KHz近辺だと1%(100Hz)の誤差となります。
ステッピングモーターは、高速時には、トルクが減少するので、立上げ途中の周波数に計算誤差が大きくなるのは、致命的な問題となります。
ステッピングモーターの連続運転
ステッピングモーターを高速で連続運転すると、鉄損が増大し、発熱が非常に大きくなります。
最近は、サーボモーターの様に回転を検出し、トルクを電流によりコントロールして発熱を抑えたものもあります。
目的にあった駆動回路の選択が必要です。
モーターの回転条件設定
1.初期速度
2.立上がり加速度
3.立下り加速度
4.目標速度
5.加減速カーブ
( 6.ゲイン)
( 7.微積分定数)
( 8.ギヤ比)
括弧内は、ドライバーでの設定、それ以外は、シーケンサー、コントローラーでの設定となります。
オリエンタルモーター EMP402
(株)メレック MPL28 CB23/USB
(株)コスモテックス USPG-48(F)
について
オリエンタルモーターのストアードプログラム型コントローラ EMP402の使用例
このコントローラーは、32種類の動作プログラムを1000ステップまで入力が可能です、又ダイレクトにコマンドの実行も可能です。
プログラムは、Windows標準のハイパーターミナルとなっていますが、WINXP以降はハイパーターミナルはありません、インターネットで検索しインストールする必要があります。
Tera Term が推奨です、使用例も検索できるので参考にして下さい。
Windows XPがある場合は、XPから下記四個のファィルを
1)
C:¥Program Files¥Windows NT¥HYPERTRM.EXE
2) C:¥Windows¥Help¥HYPERTRM.CHM
3) C:¥Windows¥Help¥HYPERTRM.HLP
4) C:¥Windows¥System32¥hypertrm.dll
新しいフォルダーをWIN7、8.1 に作成しその中に全てコピーします。
HYPERTRM.EXEの
プログラムのショートカットを作りますすす
HYPERTRM.EXEを起動すると、規定のプログラムにするかどうかダイアログが出ますが、どちらを選んでも構いません。
その後名前を付けるダイアログが出ますがアイコンが無いので、とにかく名前だけ付けて起動します。
その後は、XPの時と同じ操作です。
*HYPERTRMを起動すると、プログラムメニューに、新しく アクセサリ¥通信¥ハイパーターミナルという名前のホルダーが作成され、その中に設定ファイルが保存されますが、XPの様に起動アイコンは作成されないので、そこからは起動できません。
ファイルの保存を選択し、別のホルダーへ保存すると、ハイパーターミナルのホルダーは空のホルダーになります。
前の条件でHYPERTRMを起動したい場合は、起動後に名前とアイコン選択のダイアログが表示されますが、CANCELを選択し、ファイルを開くで、前に保存した設定ファイル(.ht)を選択して開きます。
*XPのシステムから、抜き出してWIN7、8.1等で使用するのは、著作権の問題があると思います、あくまでも自己責任でお願いします。
ハイパーターミナルの製作は、Hilgraeveとなっており、WIN7、8.1用は有料となっています。
此処での使用例は、ストアードプログラムは全く使用せず、全てパソコンからのコマンドで実行する場合です。
Delphiで動作させるのに、ハイパーターミナルは必要ありませんが、EMP402の条件設定に使用します。
本ホームページでダウンロード出来るRS232C通信プログラムでも、条件設定、プログラムの書き込み、ダイレクトモードでの動作は可能です。
EMP402は、32種類のプログラムを組むことが出来ますが、単純な移動を繰り返すのには良いのですが、パソコンで細かい動作をさせるのにはあまり向いていません。
しかし、オリエンタルの電動スライダーを動作させるのに、接続ケーブル類が充実しているので、配線の手間を可なり省くことが出来ます。
パソコンで、細かい制御をするのには、多少コマンドが不足しているので、INポートを利用して、不足分を補います。
使用説明書は、オリエンタルモーターのホームページからダウンロードして下さい。(ユーザー登録が必要です)
次の図はEMP402に二種類の電動スライダーを接続した場合の接続例です。
スライダーの駆動には、ステッピングモーターが使用されています。
オリエンタルモーターの接続例に対して、出力READY、E-STOP、ALMを、IN1、IN2、IN3にそれぞれ接続しています、これは通信で、動作完了、緊急停止、アラームを検出する為です。
二つのスライダーに対し、一つの状態出力しか無い為、マルチに動作させるのには向いていません。
本例の場合は、逆に同時に動作させると問題が発生するので、マルチに動作しないほうが良い場合の使用例です。
二軸の補間移動、直線の二軸補間はありますが、プログラムモードでしか使用出来ませんので、細かい動作は出来ません、円弧の補間動作が必要な場合は、他社のコントローラーが必要です。
COMポートの設定
通信コマンドにより動作する場合は、普通は通信エラーチェックの為チェックサムコード、ブロックチェックキャラクタ等で通信エラーを確認するのですが、ハイパーターミナルの仕様となっているのでエコーバックにより確認をします。
更に最後に送られてくる文字コードが ">" greater-than sign #62 となっているので、これを受信割り込みに設定します。
XZ軸コントロールコマンド送信処理
XZControl; (モーターコントロール XZ)のルーチンをタイマーで一定間隔で呼び出すことにより、処理を行います。
STOPコマンド以外は、フラグをたて、そのフラグにより XZControl ルーチンで処理されます。
スライダーの移動処理コマンドがが無い場合は、ポートの入力状態を常時チェックします。
コマンドを送信した場合の受信確認エラーチェックは、エコーバックで確認していますが、送信したコマンドの内容全てではなく、コマンド文字だけでコマンドに続くデーターの確認はしていませんが、実使用で問題が出た事は有りません。
又、エコーバック受信確認後、次のコマンド送信の間に、必ず一定間隔以上のあき時間を設けています。これは、受信確認と、送信用タイマーのタイミングによっては、コントローラーの実行遅れにより次のコマンドが正しく実行されなくなるのを防止するためです。(受信処理後タイマーの呼び出しを1回パスする)
EMP402には、位置情報だけを取得するコマンドがありません、全体状態を読み出すコマンドがあるので、それを利用して位置情報を取得しますが、通信データー量が多いため、読み出すのに時間が掛かります。
次のプログラム例は、全てではなく、通信部分だけを取り出しています。
移動の制御は別のルーチンで行いますが、同じタイマーで呼び出すことにより、順次実行されます。
{ *************************************************************************************** オリエンタル 402 コントローラー設定値 Z軸 ID1 = 06103100001000 (ID1,06103100001000) ACTL1 = 0,0,0,1,1 X軸 ID2 = 05103100001000 (ID2,05103100001000) ACTL2 = 0,0,0,1,1 *************************************************************************************** } var // ------------- XZ 電動スライダー --------------- XZTimeOutCount : Cardinal; // 送信エコータイムアウトカウンター XZTimeOutFL : Boolean; // タイムアウトFlag XZReset : Boolean; // リセット送信済みフラグ XZReady : Boolean; // XZ軸レディフラグ XZALM : Boolean; // XZ軸アラーム XALM : Boolean; // X軸アラーム ZALM : Boolean; // Z軸アラーム XZEstop : Boolean; // 緊急停止 XHomeReady : Boolean; // X軸ホーム完了 ZHomeReady : Boolean; // Z軸ホーム完了 XFreeFl : Boolean; // X軸フリーにしたフラグ XPLM : Boolean; // X軸+リミット XMLM : Boolean; // X軸-リミット ZPLM : Boolean; // Z軸+リミット ZMLM : Boolean; // Z軸-リミット XVPosition : Double; // Xデーターセット ZVPosition : Double; // Zデーターセット XVSpeed : Cardinal; // X軸速度 ZVSpeed : Cardinal; // Z軸速度 OutXZSTR : String; // OutPortString XPosition : Double; // X軸位置データー確認用 ZPosition : Double; // Z軸位置データー確認用 XZCOMMOPENFL : Boolean; // 通信ポートオープンフラグ XZSendF : DWord; // 送信フラグ ZXCOTWait : Boolean; // True でone wait; ZVSSpeed : integer; // Z軸起動速度 ZTSpeed : Double; // Z軸加速度 ZRAMPTime : Double; // Z軸ランプタイム 0.1 刻み // $8000 $4000 $2000 $1000 $800 $400 $200 $100 $80 $40 $20 $10 $8 $4 $2 $1 // Bit15 14 13 12 11 10, 9, 8, 7, 6 5, 4, 3, 2, 1, 0, // Ranp T R XHomerz X=0Z=1 Out VS D SendF ResetHome V ABS H,- D,+ MHome In const ZLowConst = 1000; // Z軸低速 ZXHighConst = 10000; // Z軸高速 ZVMeasureConst = 3000; // Z軸測定時速度 ZVHiDownConst = 4000; // Z軸高速低下速度 ZVSLowSpeed = 20; // Z軸起動速度 ZVSBase = 600; // Z軸初期速度 ZTLowSpeedConst = 200; // Z軸測定時加速度 時間長 ZTbase = 50; // Z軸加速度初期値 時間単 ArMax = 50000; // Ar軸最高速度 ZLanpLongConst = 200; // Lamp時間長 ZLanpShort = 50; // Lamp時間短 XLowConst = 1000; // X軸低速 XVSSPEED = 500; // X軸起動速度 ShortWait = 10; // STOP送信待ち合わせ時間 // ****************************** ディレー タイマー ***************************************** procedure TOrientalF.Delay(dtime: Cardinal); // 遅延タイマー var starttime: Cardinal; endtime: Cardinal; BreakTime: Cardinal; begin BreakTime := 0; // BreakTime初期化 starttime := TimeGetTime; while BreakTime < dtime do // 設定時間以下ならループする begin Application.ProcessMessages; EndTime := TimeGetTime; if EndTime >= StartTime then // スタート時間と取得時間により経過時間計算法選択 BreakTime := EndTime - StartTime // ブレーク時間計算 else BreakTime := not StartTime + EndTime + 1; // スタート時間より取得時間が小さい場合 end; // タイマーカウンターが一周している end; // ********************** IOF.LoopTimer *************************** // タイマーにより16㍉秒~20㍉秒程度の間隔で実行する。 procedure TOrientalF.Controltimersub; //タイマーサブルーチン begin XZControl; // モーターコントロール XZ *********; // モーターコントロール以外も同じタイマー呼び出し動作の制御を行います。 | *********; end; //----------------------- 電動スライダーコントローラ 通信処理 ------ // RS232C Commポートオープン function TOrientalF.XZSLDCOMMOPEN:Boolean; begin Result := True; try COMM4.Port := 4; // ポート番号 4 COMM4.BaudRated := User_BaudRate; // ユーザーボーレート COMM4.BaudRate := 9600; // 9600 ボー COMM4.FlowControls := []; // フローコントロール無し COMM4.EventMask := [evRxflag]; // 受信割り込みフラグ使用 COMM4.RxflagReceive := eventOn; // 割り込み使用 COMM4.EventFlag := UserIn; // ユーザー指定フラグ使用 COMM4.EventFlagin := #62; // フラグ文字 '>' // COMM4.EventMask := [evRxchar]; // COMM4.RxflagReceive := eventOff; COMM4.ByteSize := cbs8; // データー 8 ビット COMM4.StopBits := csb1; // ストップビット 1 ビット COMM4.ParityBits := cpbNone; // パリティ無し COMM4.Open; except Application.MessageBox('電動スライダー通信ポート(COMM4) オープンエラーです。','確認',MB_OK); Result := False; end; end; procedure TOrientalF.XZSLDCommClose; // Comm4 ポートクローズ begin COMM4.Close; // Comm4 close XZCOMMOPENFL := False; // ポートオープンフラグリセット end; // ===================== XZ軸コントロールコマンド送信処理 ==================== procedure TOrientalF.XZControl; // モーターコントロール XZ label Axis2,Common; const AllFlag = $02 + $04 + $08 + $10 + $20 + $100 + $200 + $800 +$1000 + $2000 + $4000 + $8000; // 全コマンド IN OUT RESET 除く var TempStr : string; begin if not XZCOMMOPENFL then exit; // 通信ポートがOPENされていなければ終了 if XZTimeOutCount < MTimeOutP1 then inc(XZTimeOutCount) // タイムアウトカウンターインクリメント else exit; if XZTimeOutCount = PreTimeout then XZSendF := XZSendF and (MAXDWORD - $81); // PreTimeoutになったら一度送信フラグ解除し通信再開ここみる if (XZTimeOutCount > MTimeOut) or XZEstop or XALM or ZALM then // タイムアウトになったら begin XZTimeOutFL := True; // タイムアウトフラグセット XZReady := False; // レディフラグリセット XZReset := False; // XZリセット済みフラグリセット exit; // 此処まで end; if ZXCOTWait then // One wait Trueだったら一回パスする begin ZXCOTWait := False; exit; end; if XZSendF and $80 > 0 then exit; // 未受信なら此処まで if XZSendF and $40 > 0 then // リセット送信 begin XZSendF := XZSendF or $1000; // X軸ホーム予約 送信フラグセット XZSendF := XZSendF or $80; // 送信フラグセット Comm4.SendString('RESET' + #13#10); // リセット実行送信 XHomeReady := False; // Xホームフラグリセット ZHomeReady := False; // Zホームフラグリセット XZReset := False; // リセットフラグリセット if not MXZResetFL then MXZResetIn := 3; // MXZResetIn 0 以外順次中フラグ exit; // 此処まで end; if not XZReSet then exit; // リセットされていなかったら此処まで if XZSendF and AllFlag = 0 then goto Common; // コマンドフラグ無かったらI/0 Commomへ if XZSendF and $800 = 0 then goto Axis2; // Axis1 Z軸でなかったら Axis2 X軸へ // --------------- Z軸コントロール ------------------------- if XZSendF and $02 = $02 then // MHome1 送信 begin XZSendF := XZSendF or $80; // 送信済みフラグセット Comm4.SendString('MHOME1' + #13#10); // MHOME1 ホーム位置初期化送信 if not MXZResetFL then MXZResetIn := 7; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $08 = $08 then // Z H1,- 送信 begin XZSendF := XZSendF or $80; Comm4.SendString('H1,-' + #13#10); if not MXZResetFL then MXZResetIn := 5; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $04 = $04 then // D1,DATA 送信 begin XZSendF := XZSendF or $80; TempStr := floatTostr(SimpleRoundTo(ZVPosition, -2)); // 小数点以下2桁に丸める TempStr := Copy(TempStr,1,8); Comm4.SendString(AnsiString('D1,+' + TempStr + #13#10)); if MZMOVEFL then MZMOVEin := 2; // Z軸順次制御フラグ exit; end; if XZSendF and $10 = $10 then // ABS1, アブソリュート移動送信 begin XZSendF := XZSendF or $80; Comm4.SendString('ABS1' + #13#10); if MZMOVEFL then MZMOVEin := 4; // Z軸順次制御フラグ exit; end; if XZSendF and $20 = $20 then // V1,移動速度送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString(('V1,' + intTostr(ZVSpeed) + #13#10))); exit; end; if XZSendF and $100 = $100 then // D1, 設定位置読み出し送信 begin XZSendF := XZSendF or $80; Comm4.SendString('D1' + #13#10); if not MXZResetFL then MXZResetIn := 10; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $200 = $200 then // VS1, 起動速度送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('VS1,' + intTostr(ZVSSpeed) +#13#10)); exit; end; if XZSendF and $2000 = $2000 then // R1, データーリクエスト送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('R1' + #13#10)); exit; end; if XZSendF and $4000 = $4000 then // Z軸加速度送信 begin XZSendF := XZSendF or $80; TempStr := floatTostr(SimpleRoundTo(ZTSpeed, -1)); // 小数点以下1桁に丸める TempStr := Copy(TempStr,1,6); Comm4.SendString(AnsiString('T1,' + TempStr + #13#10)); exit; end; if XZSendF and $8000 = $8000 then // RAMP1送信 begin XZSendF := XZSendF or $80; TempStr := floatTostr(SimpleRoundTo(ZRAMPTime, -1)); // 小数点以下1桁に丸める TempStr := Copy(TempStr,1,7); Comm4.SendString(AnsiString('RAMP1,1,' + TempStr + #13#10)); // Ramp exit; end; // ---------------- X軸コントロール ----------------- Axis2: if XZSendF and $02 = $02 then // MHome2 送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString(('MHOME2' + #13#10))); if not MXZResetFL then MXZResetIn := 14; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $08 = $08 then // X H2,- 送信 begin XZSendF := XZSendF or $80; Comm4.SendString('H2,-' + #13#10); if not MXZResetFL then MXZResetIn := 12; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $04 = $04 then // D2,DATA 送信 begin XZSendF := XZSendF or $80; TempStr := floatTostr(SimpleRoundTo(XVPosition, -2)); // 小数点以下2桁に丸める TempStr := Copy(TempStr,1,8); Comm4.SendString(AnsiString('D2,+' + TempStr + #13#10)); if MXMOVEFL then MXMOVEin := 2; // X軸順次制御フラグ exit; end; if XZSendF and $10 = $10 then // ABS2, アブソリュート移動送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('ABS2' + #13#10)); if MXMOVEFL then MXMOVEin := 4; // X軸順次制御フラグ exit; end; if XZSendF and $20 = $20 then // V2,送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('V2,' + intTostr(XVSpeed) + #13#10)); exit; end; if XZSendF and $100 = $100 then // D2, 送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('D2' + #13#10)); if not MXZResetFL then MXZResetIn := 17; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $200 = $200 then // VS2, 起動速度送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('VS2,' + intTostr(XVSSpeed) + #13#10)); exit; end; if XZSendF and $2000 = $2000 then // R2, 送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('R2' + #13#10)); exit; end; // ---------------------------- 共通 IN OUT ------------------------------- Common: // I/O out if XZSendF and $400 > 0 then // OUT 送信 begin XZSendF := XZSendF or $80; Comm4.SendString(AnsiString('OUT,' + OutXZSTR + #13#10)); // OutXZSTR = 'XXXXXX' X='0' or X='1' exit; end; // I/O in if XZSendF and (MAXDWORD - $1000 - $800) = 0 then // $1000 は X軸Home 予約 begin XZSendF := XZSendF or $81; BufS := ''; // 受信バッファクリア Comm4.SendString(AnsiString('IN' + #13#10)); end; end; // =============== 電動スライダーコントローラ 通信受信処理 ==================== procedure TOrientalF.Comm4CommReceive(Sender: TObject; Size: Cardinal); label Axis2; var Buf: Pansichar; I,Leng,ILeng: integer; checkStr: string; inBufstr: string; const AllFlag = $02 + $04 + $08 + $10 + $20 + $40 + $100 + $200 + $2000 + $4000 + $8000 + $80; // 全コマンド IN OUT RESET 除く begin XZTimeOutCount := 0; // タイムアウトタイマーリセット Buf := AllocMEM(Size + 1); // バッファメモリー取得 Comm4.Read(Buf,Size); // データー読み込み inBufstr := string(Buf); // checkStrにコピー FreeMem(Buf,Size + 1); // バッファメモリー開放 BufS := BufS + inBufstr; // 読み込み文字加算処理 Leng := Length(BufS) - 1; // 文字長さ取得1小さくする inBufstr := ''; // 文字クリア checkStr := ''; // 文字クリア if Leng > 0 then // 受信文字があったら for I := Leng downto 1 do // '0>' 位置確認 begin checkStr := copy(BufS,I,2); // 二文字取得 if checkStr = '0>' then // '0>' だったら begin if I < Leng then // 二文字数以上小さい場合 begin inBufstr := copy(BufS,1,I + 1); // バッファより先頭からI+1文字数コピー BufS := copy(BufS,I + 2,Leng - I); // バッファより残りの文字数コピー end else begin // 文字長さとIが等しい場合 inBufstr := BufS; // バッファをコピー BufS := ''; // ブッファクリア end; Break; // for 終了 end; end; if checkStr <> '0>' then exit; // '0>'がなかったら終了 if OrientalF.Visible then // フォームが表示されていたら受信内容表示 begin Comm4Memo.Clear; // Memo クリア Comm4Memo.Lines.Add(inBufstr); // inBufstr 表示 end; if (Leng > 35) and (Leng < 300) then // 文字長さが 30~ 300 なら begin checkStr := copy(inBufstr,5,28); // 5番目から28文字取り出し if checkStr = ' * E-STOP switch active.' then // E-STOPなら begin XZEstop := True; // EStop フラグセット BufS := ''; XZSendF := 0; // 送信フラグリセット ZXCOTWait := True; // True でone wait; exit; end; if checkStr = ' * S-STOP switch active.' then // S-STOPなら begin BufS := ''; XZSendF := 0; // 送信フラグリセット ZXCOTWait := True; // True でone wait; exit; end; checkStr := copy(inBufstr,5,30); if checkStr = ' * CW limit switch active.' then // CW limit begin if XZSendF and $800 = $800 then ZPLM := True // Z軸 +リミットフラグセット else XPLM := True; // X軸 +リミットフラグセット BufS := ''; XZSendF := 0; // 送信フラグリセット ZXCOTWait := True; exit; end; if checkStr = ' * CCW limit switch active' then // CCW limit begin if XZSendF and $800 = $800 then ZMLM := True // Z軸 -リミットフラグセット else XMLM := True; // X軸 -リミットフラグセット BufS := ''; XZSendF := 0; // 送信フラグリセット ZXCOTWait := True; exit; end; if checkStr = ' * Driver alarm. ->axis1 ' then begin ZALM := True; // Z軸 アラームフラグセット XZSendF := 0; // 送信フラグリセット BufS := ''; ZXCOTWait := True; exit; end; if checkStr = ' * Driver alarm. ->axis2 ' then begin XALM := True; // X軸 アラームフラグセット XZSendF := 0; // 送信フラグリセット BufS := ''; ZXCOTWait := True; exit; end; end; // ------ INポート処理 データーによりフラグセット ------ if XZSendF and $81 = $81 then // IN begin checkStr := copy(inBufstr,1,2); // 先頭二文字 if checkStr <> 'IN' then // 'IN'でないなら終了 begin BufS := ''; // バッファ文字クリア ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $81); // フラグ解除 exit; end; if inBufstr[22] = '1' then // Ready チェック IN1 begin if XZSendF and $800 = $800 then begin // Z軸フラグだったら if not ZHomeReady then begin XZSendF := XZSendF or $100; // D1,問い合わせフラグセット続いてXMOHOEを行う if not MXZResetFL then MXZResetIn := 9; // MXZResetIn 0 以外順次中フラグ end; end else begin // X軸なら if not XHomeReady then begin XZSendF := XZSendF or $100; // D2問い合わせ if not MXZResetFL then MXZResetIn := 16; // MXZResetIn 0 以外順次中フラグ end; end; if (MZMOVEin = 5) then MZMOVEin := 6; // Z軸順次制御フラグ if (MXMOVEin = 5) then MXMOVEin := 6; // X軸順次制御フラグ XZReady := True; // XZ 402 レディフラグセット end else XZReady := False; // XZ 402 NOTレディフラグセット if inBufstr[21] = '0' then XZEstop := True // EStop IN2 else XZEstop := False; if inBufstr[20] = '0' then XZALM := True // ALM IN3 else XZALM := False; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $81); // 'IN'フラグ解除 exit; end; if XZSendF and $C0 = $C0 then // Reset begin checkStr := copy(inBufstr,1,5); if checkStr <> 'RESET' then exit; // 通信確認用 XZReady := False; // XZ軸レディリセット XHomeReady := False; // X軸ホームセット済みフラグ ZHomeReady := False; // Z軸ホームセット済みフラグ XZReset := True; // リセットフラグセット ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $C0); // リセット送信フラグ解除 XZSendF := XZSendF or ($800 + $08); // H1,-送信フラグセット if not MXZResetFL then MXZResetIn := 4; // MXZResetIn 0 以外順次中フラグ exit; end; // out if XZSendF and $480 = $480 then // Out begin checkStr := copy(inBufstr,1,3); if checkStr <> 'OUT' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $480); exit; end; if XZSendF and AllFlag = 0 then exit; // コマンドが無かったら終了 if XZSendF and AllFlag = $80 then // S1 $80 はすべてに含まれる begin checkStr := copy(inBufstr,1,2); if checkStr = 'S1' then MZStopin := False; if checkStr = 'S2' then MXStopin := False; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $80); exit; end; if XZSendF and $800 = 0 then goto Axis2; // Axis1 でなかったら Axis2 // ------------------------ Z軸モード -------------------------------- if XZSendF and $82 = $82 then // Mhome1 begin checkStr := copy(inBufstr,1,6); if checkStr <> 'MHOME1' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $82); if not MXZResetFL then MXZResetIn := 8; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $88 = $88 then // H1,- begin checkStr := copy(inBufstr,1,3); if checkStr <> 'H1,' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $88); XZSendF := XZSendF or $02; // Mhome1送信フラグセット if not MXZResetFL then MXZResetIn := 6; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $84 = $84 then // D1,+ begin checkStr := copy(inBufstr,1,3); if checkStr <> 'D1,' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $84); XZSendF := XZSendF or $10; // ABS1送信送信フラグセット if MZMOVEFL then MZMOVEin := 3; // Z軸順次制御フラグ exit; end; if XZSendF and $90 = $90 then // ABS1 begin checkStr := copy(inBufstr,1,4); if checkStr <> 'ABS1' then exit; // 通信確認用 XZReady := False; // Reday = False ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $90); if MZMOVEFL then MZMOVEin := 5; // Z軸順次制御フラグ exit; end; if XZSendF and $A0 = $A0 then // V1, begin checkStr := copy(inBufstr,1,3); if checkStr <> 'V1,' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $A0); XZSendF := XZSendF or ($800 + $200); // Vs1 送信設定 exit; end; if XZSendF and $280 = $280 then // VS1 begin checkStr := copy(inBufstr,1,3); if checkStr <> 'VS1' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $280); MZSpeedFL := False; // Z速度設定完了フラグ MZSpeedin := False; // Z速度設定完了フラグ exit; end; if XZSendF and $180 = $180 then // Position D1 begin checkStr := copy(inBufstr,1,2); if checkStr <> 'D1' then exit; // 通信確認用 I := LastDelimiter(#13,inBufstr); // 最後の'CR' 位置検出 inBufstr := Copy(inBufstr,15,I - 15); // 受信文字15文字目からI文字までコピー Val(inBufstr,ZPosition,Leng); // 数値変換 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $180); if XZSendF and $1000 = $1000 then // X軸リセットホーム指定だったら begin XZSendF := XZSendF and (MAXDWORD - $1000 - $800); // X軸リセットZ軸フラグ解除 XZSendF := XZSendF or $08; // 'H2,-'送信フラグセット end; // 'H2,-'フラグをセットすると ZHomeReady := True; // Z軸 MHOME済みフラグ if not MXZResetFL then MXZResetIn := 11; // MXZResetIn 0 以外順次中フラグ exit; // 続いてXMHOMEを実行する end; if XZSendF and $2080 = $2080 then // 'R1' X軸状態問い合わせ begin checkStr := copy(inBufstr,1,2); if checkStr <> 'R1' then exit; Leng := length(inBufstr); // 文字長さ取得 checkStr := copy(inBufstr,1,Leng - 4); // 最後の4文字を除き取得 '$0D0A'0>' ILeng := LastDelimiter(char(#10),checkStr); // 最後の$0Aの文字位置取得 Leng := length(checkStr); // 文字長さ取得 inBufstr := copy(checkStr,ILeng + 1,Leng - ILeng); // 最後の$0Aの次の文字から後の文字取得 ILeng := LastDelimiter('=',inBufstr); // '=' の位置取得 Leng := length(inBufstr); // 文字長さ取得 checkStr := copy(inBufstr,ILeng + 1,Leng - ILeng); // '='の後ろの文字取得 val(checkStr,ZPosition,Ileng);; // 文字を数値に変換Z軸現在位置取得データー ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $2080); // コマンドフラグ解除 MZPosiGetFL := False; // Z軸位置取得フラグ MZPosiGetin := False; // Z軸位置取得フラグ exit; end; if XZSendF and $4080 = $4080 then // 'R1' X軸状態問い合わせ begin checkStr := copy(inBufstr,1,3); if checkStr <> 'T1,' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $4080); MZTSpeedin := False; // Z軸加速度中フラグ MZTSpeedFL := False; // Z軸加速度設定フラグ exit; end; if XZSendF and $8080 = $8080 then // RAMP1 begin checkStr := copy(inBufstr,1,5); if checkStr <> 'RAMP1' then exit; // 通信確認用 ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $8080); MZRAMPin := False; // Z軸加速度中フラグ MZRAMPFL := False; // Z軸加速度設定フラグ exit; end; if XZSendF and $800 = $800 then exit; // AXis1 ここまで // ------------- X 軸モード 処理 ------------------------------- Axis2: if XZSendF and $88 = $88 then // H2,- begin checkStr := copy(inBufstr,1,3); if checkStr <> 'H2,' then exit; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $88); XZSendF := XZSendF or $02; // Mhome2送信フラグセット if not MXZResetFL then MXZResetIn := 13; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $82 = $82 then // Mhome2 begin checkStr := copy(inBufstr,1,6); if checkStr <> 'MHOME2' then exit; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $82); if not MXZResetFL then MXZResetIn := 15; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $84 = $84 then // D2,+ begin checkStr := copy(inBufstr,1,3); if checkStr <> 'D2,' then exit; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $84); XZSendF := XZSendF or $10; // ABS2送信フラグセット if MXMOVEFL then MXMOVEin := 3; // X軸順次制御フラグ exit; end; if XZSendF and $90 = $90 then // ABS2 begin checkStr := copy(inBufstr,1,4); if checkStr <> 'ABS2' then exit; XZReady := False; // Reday = False ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $90); if MXMOVEFL then MXMOVEin := 5; // X軸順次制御フラグ exit; end; if XZSendF and $A0 = $A0 then // V2, begin checkStr := copy(inBufstr,1,3); if checkStr <> 'V2,' then exit; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $A0); XZSendF := XZSendF or $200; exit; end; if XZSendF and $280 = $280 then // VS2 begin checkStr := copy(inBufstr,1,3); if checkStr <> 'VS2' then exit; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $280); MXSpeedFL := False; // X速度設定完了フラグ MXSpeedin := False; // X速度設定完了フラグ exit; end; if XZSendF and $180 = $180 then // Position D2 begin checkStr := copy(inBufstr,1,2); if checkStr <> 'D2' then exit; ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $180); I := LastDelimiter(#13,inBufstr); // 改行文字位置取得 inBufstr := Copy(inBufstr,15,I - 15); // 受信文字15文字目からI文字までコピー Val(inBufstr,XPosition,Leng); // 数値変換 XHomeReady := True; // X軸 MHOME済みフラグ if not MXZResetFL then MXZResetIn := 18; // MXZResetIn 0 以外順次中フラグ exit; end; if XZSendF and $2080 = $2080 then // R2 begin checkStr := copy(inBufstr,1,2); if checkStr <> 'R2' then exit; Leng := length(inBufstr); // 文字長さ取得 checkStr := copy(inBufstr,1,Leng - 4); // 最後の4文字を除き取得 '$0D0A'0>' ILeng := LastDelimiter(char(#10),checkStr); // 最後の$0Aの文字位置取得 Leng := length(checkStr); // 文字長さ取得 inBufstr := copy(checkStr,ILeng + 1,Leng - ILeng); // 最後の$0Aの次の文字から後の文字取得 ILeng := LastDelimiter('=',inBufstr); // '=' の位置取得 Leng := length(inBufstr); // 文字長さ取得 checkStr := copy(inBufstr,ILeng + 1,Leng - ILeng); // '='の後ろの文字取得 val(checkStr,XPosition,Ileng);; // 文字を数値に変換X軸現在位置取得データー ZXCOTWait := True; // True でone wait; XZSendF := XZSendF and (MAXDWORD - $2080); MXPosiGetFL := False; // X位置取得フラグ解除 MXPosiGetin := False; // X位置取得中フラグ解除 exit; end; end; //============================= X軸Z軸移動処理 ====================== procedure TOrientalF.ZMHome; // Z軸ホームへ戻し begin MZMHOMEIn := True; // MHome 送信中フラグセット ZHomeReady := False; // ホームセットフラグリセット XZTimeOutCount := 0; // タイムアウトカウンタークリア ZPLM := False; // Z軸+リミットフラグリセット ZMLM := False; // Z軸-リミットフラグリセット while XZSendF and (MAXDWORD - $800) > 0 do Application.ProcessMessages; // 前のコマンド実行待ち XZSendF := $800 + $08; // ZMHome 送信フラグセット end; procedure TOrientalF.XMHome; // X軸ホームへ戻し begin MXMHOMEIn := True; // MHome 送信中フラグセット XHomeReady := False; // ホームセットフラグリセット XZTimeOutCount := 0; // タイムアウトカウンタークリア XPLM := False; // X軸+リミットフラグリセット XMLM := False; // X軸-リミットフラグリセット while XZSendF and (MAXDWORD - $800) > 0 do Application.ProcessMessages; // 前のコマンド実行待ち XZSendF := $08; // XMHome 送信フラグセット end; procedure TOrientalF.ResetHome; // XZ軸軸ホーム戻し begin XPLM := False; // X軸+リミットフラグリセット XMLM := False; // X軸-リミットフラグリセット ZPLM := False; // Z軸+リミットフラグリセット ZMLM := False; // Z軸-リミットフラグリセット XZReset := False; // リセット送信済みフラグ ZHomeReady := False; // リセット済みフラグリセット XHomeReady := False; // リセット済みフラグリセット XZSendF := $80; // リセットフラグセット XZTimeOutCount := 0; // タイムアウトカウンタークリア XZTimeOutFL := False; // タイムアウトフラグリセット if not XZCOMMOPENFL then XZCOMMOPENFL := XZSLDCOMMOPEN; // スライダー通信ポートオープンフラグ if not XZCOMMOPENFL then // 通信オープンできなかったら begin MainF.EndBtn.Enabled := True; // 終了ボタン表示 exit; end; ZXCOTWait := False; // 送信1ウェイト if IOF.Oriental402EstpSet then // USB IO により、ESTOP 解除出来たら begin MZMHOMEin := True; // Zホーム実行中フラグセット MXMHOMEin := True; // Xホーム実行中フラグセット XZSendF := $800 + $40; // ResetToHomeフラグセット if not MXZResetFL then MXZResetIn := 2; // MXZResetIn 0 以外順次中フラグ end else // EStop 解除できない場合 begin Errorstr := 'モーターの駆動ロック解除できませんでした。' + #13#10 + 'USBの接続、配線確認後再起動して下さい。'; application.MessageBox(Pchar(Errorstr),'注意'); end; end; procedure TOrientalF.ZMoveTo; // Z軸移動 begin if MZMOVEFL then MZMOVEin := 1; // Z軸順次制御フラグ while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF or ($800 + $04); // 指定位置移動フラグセット end; procedure TOrientalF.ZSpeedSet; // Z軸速度指定 begin MZSpeedin := True; // Z速度設定中フラグ while (XZSendF and (MAXDWORD - $800) > 0) do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF or ($800 + $20); // 速度設定フラグセット end; procedure TOrientalF.ZMoveStop; // Z軸移動停止 begin if MZStopin then exit; // 既に停止モードなら終了 MZStopin := True; IOF.OutBitNoOnNonErr(XZSstopbit); // XZモーター SStop ON IOによる停止 while (XZSendF and (MAXDWORD - $800) > 0) do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then begin IOF.OutBitNoOff(XZSstopbit); // XZモーター SStop Off exit; // EStop なら 抜ける end; end; XZSendF := XZSendF or ($800 + $80); // 送信フラグセット MainF.Delay(ShortWait); // 遅延タイマー10mmsec 通常 IOF.OutBitNoOffNonErr(XZSstopbit); // XZモーター SStop Off Comm4.SendString('S1' + #13#10); // 停止フラグ'S1'送信 end; // 停止コマンドは移動中いつでも受け付ける procedure TOrientalF.ZTpeedSet; // Z軸加速度指定 begin if MZTSpeedin then exit; MZTSpeedin := True; // コマンド送信中ラグセット while (XZSendF and (MAXDWORD - $800) > 0) do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF or ($800 + $4000); // 加速度設定フラグセット end; procedure TOrientalF.XSpeedSet; // X軸速度指定 begin MXSpeedin := True; // X速度設定中フラグ while (XZSendF and (MAXDWORD - $800) > 0) do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF and (MAXDWORD - $800); // X軸フラグ消去 XZSendF := XZSendF or $20; // 速度設定フラグセット end; procedure TOrientalF.XMoveTo; // X軸移動 begin if MXMOVEFL then MXMOVEin := 1; // X軸順次制御フラグ while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF and (MAXDWORD - $800); // X軸指定フラグセット XZSendF := XZSendF or $04; // 指定位置移動フラグセット end; procedure TOrientalF.XMoveStop; // X軸移動停止 begin if MXStopin then exit; // 既に停止モードにら終了 MXStopin := True; IOF.OutBitNoOnNonErr(XZSstopbit); // XZモーター SStop ON IOによる停止 while (XZSendF and (MAXDWORD - $800) > 0) do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then begin IOF.OutBitNoOffNonErr(XZSstopbit); // XZモーター SStop Off exit; // EStop なら 抜ける end; end; XZSendF := XZSendF and (MAXDWORD - $800); // X軸指定フラグセット XZSendF := XZSendF or $80; // 送信フラグセット Delay(ShortWait); // 遅延タイマー10mmsec 通常 IOF.OutBitNoOffNonErr(XZSstopbit); // XZモーター SStop Off Comm4.SendString('S2' + #13#10); // 停止コード送信 end; procedure TOrientalF.ZR1send; // R1送信Position取得 begin MZPosiGetin := True; // Z軸位置取得フラグ while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF or $2800; // Z軸R1 送信フラグセット end; procedure TOrientalF.XR2send; // X軸R2送信Position取得 begin MXPosiGetin := True; // X軸位置取得フラグ while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF and (MAXDWORD - $800); // X軸指定フラグセット XZSendF := XZSendF or $2000; // R2 送信フラグセット end; procedure TOrientalF.ZRAMPSet; // Z軸Rampset; begin MZRampin := True; // Z軸Rampフラグ while (XZSendF and (MAXDWORD - $800) > 0) do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF or $8800; // ZRamp 送信フラグセット end; //------------------------ XZ OUTData Make ------------------------------- procedure TOrientalF.XZOutDataMake(PortNo:integer;OnOffFl:boolean); // Outdata作成 OnOffFl True = 0n False = Off begin if (PortNo < 1) or (PortNo > 6) then exit; if OnOffFl then OutXZSTR[7-PortNo] := '1' // OutXZSTR : OutPortString else OutXZSTR[7-PortNo] := '0'; end; procedure TOrientalF.XZportOut; // Portout begin while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; XZSendF := XZSendF or $400; // Portoutフラグセット end; //------------------------ XZアラームクリア ------------------------------ procedure TOrientalF.XZAlmClear; // XZアラームクリア begin if XFreeFl then exit; // フリーだったら実行しない while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; OutXZSTR[6] := '1'; // ポートon設定 OutXZSTR[5] := '1'; // ポートon設定 XZSendF := XZSendF or $400; // Portoutフラグセット while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do // 前のコマンド実行待ち begin Application.ProcessMessages; if XZEStop then exit; // EStop なら 抜ける end; OutXZSTR[6] := '0'; // ポートoff設定 OutXZSTR[5] := '0'; // ポートoff設定 XZSendF := XZSendF or $400; // Portoutフラグセット end; // -----------------------XZ軸 ボタンクリック処理 -------------------------- procedure TOrientalF.ResetBtnClick(Sender: TObject); begin MXZResetFL := False; // XZ軸軸ホーム戻し end; procedure TOrientalF.XMHOMEBtnClick(Sender: TObject); begin application.MessageBox('位置データーを0(ゼロ)として戻して下さい','注意',0); // if MXZResetFL then MXMHOMEFL := False; // Mhome済み end; procedure TOrientalF.ZMHomeBTnClick(Sender: TObject); begin if MXZResetFL then MZMHOMEFL := False; // Mhome済み end; procedure TOrientalF.XMoveToBtnClick(Sender: TObject); begin MXMOVEFL := True; // X軸移動 end; procedure TOrientalF.ZMovetoBtnClick(Sender: TObject); begin MZMOVEFL := True; // Z軸移動 end; procedure TOrientalF.ZSpeedClick(Sender: TObject); var check: integer; inspeed: Cardinal; begin val(ZSpeedEdit.Text,inspeed,Check); if Check <> 0 then exit; ZVSpeed := inspeed; // 速度セット MZSpeedFL := True; // 速度設定フラグ end; procedure TOrientalF.XSpeedClick(Sender: TObject); var check: integer; inspeed: Cardinal; begin val(XSpeedEdit.Text,inspeed,Check); if Check <> 0 then exit; XVSpeed := inspeed; // 速度セット MXSpeedFL := True; // 速度設定フラグ end; procedure TOrientalF.XstopBtnClick(Sender: TObject); begin if not MXStopin then XMoveStop; // X軸移動停止 フラグ使用しない end; procedure TOrientalF.ZStopBtnClick(Sender: TObject); begin if not MZStopin then ZMoveStop; // Z軸移動停止 フラグ使用しない end; procedure TOrientalF.XFreeTgrBtnClick(Sender: TObject); begin if OutXZSTR[4] = '0' then begin XZOutDataMake(3,True); XFreeTgrBtn.Caption := 'Free Off'; XFreeFl := True; // X軸フリーにしたフラグ end else begin XZOutDataMake(3,False); XFreeTgrBtn.Caption := 'Free On'; XFreeFl := False; // X軸フリー解除したフラグ end; XZportOut; end; procedure TOrientalF.ZFreeTgrBtnClick(Sender: TObject); begin Application.MessageBox('Z軸をフリーにしてはいけません。','禁止事項'); end; procedure TOrientalF.XR2btnClick(Sender: TObject); begin MZPosiGetFL := True; // X軸R2送信Position取得 end; procedure TOrientalF.ZR1BtnClick(Sender: TObject); begin MZPosiGetFL := True; // R1送信Position取得 end; procedure TOrientalF.AlmClearBtnClick(Sender: TObject); begin XZAlmClear; end; procedure TOrientalF.ZPosisetBtnClick(Sender: TObject); var check :integer; begin val(ZpositionEdit.Text,ZVPosition,Check); // 送信用位置データー変換 ZpositionCheck; ZpositionEdit.Text := FloatTostr(ZVPosition); end; procedure TOrientalF.XPosisetBtnClick(Sender: TObject); var check :integer; begin val(XpositionEdit.Text,XVPosition,Check); // 送信用位置データー変換 XpositionCheck; XpositionEdit.Text:= FloatTostr(XVPosition); end;
(株)メレック MPL28 CB23/USB
これは、USBをRS485に変換して複数のユニットの制御が可能にしたものです。(ステッピングモーターコントローラー、IOユニット)
最初のバージョンには、Delphi用のサンプルプログラムが添付されてきたのですが、新しいバージョンには、Dlephi用のものは添付されてこないようです。
C#,VC.NET用のヘッダファイル、或いはVB用のDLL関数呼び出し定義ファイルがダウンロード出来れば、Delphi用に変換可能なのですが、製品にCDとして添付されてくるだけで、公開されていません。
メーカーの方針のようなので、ソフトの此処での公開は控えさせて頂きます。
最初のバージョンに付いてきたサンプルソフトの起動画面を下図に示します。
Delphiは、最近少し盛り返してきましたが、仕様の変更が結構有った事、サンプルプログラムの少なさ、マイクロソフトのツールの無料公開等で、若い年代層のユーザー数が減少した為に、メーカー側で、Delphi用のサンプルソフトを用意するところが少なくなりました。
(株)コスモテックス USPG-48(F)
これは、USB通信四軸ステッピングモーターコントローラーです。(直線、円弧補間可能)
ここの会社のホームページからは、ユーザー登録さえ行えば、マニュアル、ドライバー等必要なものは全てダウンロードできます。
必要であれば、メーカーホームページよりダウンロードして下さい。
ここの会社にも Delphi用のサンプルプログラムはありません。
Delphi用に変換したプログラムリストを紹介します。
WinXp(32bit)用のものを変換したので、最近は、64ビットバージョンも出ており、多少違うところがあるかもしれません。
実行画面
サンプルプログラムは、ホームポジションセンサーを一個だけ取り付けて動作させた場合の例です。
unit USPGTEST; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, CTD20DLL, ExtCtrls, IniFileS; type TUSPG48TESTF = class(TForm) Edit1: TEdit; DllVerGetBtn: TButton; DrvVerGetBtn: TButton; AxisIniBtn: TButton; Edit2: TEdit; Timer1: TTimer; OriginBtn: TButton; CwIndexBtn: TButton; CCwIndexBtn: TButton; ZeroRtnBtn: TButton; SlowStopBtn: TButton; InternalCouterBtn: TButton; SModesetbtn: TButton; DMODbtn: TButton; UDESmodebtn: TButton; HiSpeedBtn: TButton; LowSpeedBtn: TButton; CwScanBtn: TButton; CCwScanBtn: TButton; RangeReadbtn: TButton; Ready1Edit: TEdit; OpenBtn: TButton; AxisNoEdit: TEdit; ObjectspeedBtn: TButton; Ready2Edit: TEdit; Ready3Edit: TEdit; Ready4Edit: TEdit; IndexEdit: TEdit; IndexLabel: TLabel; AbsLabel: TLabel; AbsEdit: TEdit; AbsBtn: TButton; LowSpeedEdit: TEdit; LowSpeedLabel: TLabel; HiSpeedEdit: TEdit; HiSpeedLabel: TLabel; RiseEdit: TEdit; RiseLabel: TLabel; DownEdit: TEdit; DownLabel: TLabel; SRatioEdit: TEdit; SRaitLabel: TLabel; AxisLabel: TLabel; MinimumEdit: TEdit; MinimumLabel: TLabel; MinimumBtn: TButton; procedure DllVerGetBtnClick(Sender: TObject); procedure DrvVerGetBtnClick(Sender: TObject); procedure AxisIniBtnClick(Sender: TObject); procedure OriginBtnClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure CwIndexBtnClick(Sender: TObject); procedure CCwIndexBtnClick(Sender: TObject); procedure ZeroRtnBtnClick(Sender: TObject); procedure SlowStopBtnClick(Sender: TObject); procedure InternalCouterBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure SModesetbtnClick(Sender: TObject); procedure DMODbtnClick(Sender: TObject); procedure UDESmodebtnClick(Sender: TObject); procedure HiSpeedBtnClick(Sender: TObject); procedure LowSpeedBtnClick(Sender: TObject); procedure CwScanBtnClick(Sender: TObject); procedure CCwScanBtnClick(Sender: TObject); procedure RangeReadbtnClick(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure OpenBtnClick(Sender: TObject); procedure ObjectspeedBtnClick(Sender: TObject); procedure AbsBtnClick(Sender: TObject); procedure MinimumBtnClick(Sender: TObject); private { Private 宣言 } function InitAxis(wBsn, wAxis: Word): LongBool; // 軸初期化 function LeftSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sUpTime, sDownTime: Word; SRate: Double): Word; // 残パルス指定速度設定 function StraightSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sUpDownTime: Word): Word; // 直線加速指定速度設定 procedure BtnFalseSet; procedure DeviceOpen; function MinimumPulses(var UpTime, DownTime, dHighSpeed: double; dLowSpeed, Funit: Double): Cardinal; function NESModeset: boolean; public { Public 宣言 } procedure Orgmove(wAxis: Word); // 原点復帰 function SpeedDataInput: Boolean; // 速度データー入力 end; var USPG48TESTF : TUSPG48TESTF; Ack : LongBool; STATE : integer; STATE_SUB : integer; wBsn : Word; wAxis : Word; chk : Smallint; SLD_P_DATA : DWord; Err : Dword; RANGE_DATA : Word; Bdata : byte; // ドライブステータス ReadyF : array[1..4] of Boolean; // 軸ReadyF LowSpeed : Double; HiSpeed : Double; RiseTime : Word; DownTime : Word; SRate : Double; SHModeF : Boolean; // S時非対称モードフラグ const CRatebase = 4.096E6; clockbase = 8.191E6; // 基本は8.192E6 計算上 8.191E6に設定 implementation {$R *.dfm} var check : integer; IndexData : Cardinal; function TUSPG48TESTF.SpeedDataInput: Boolean; // 速度データー入力 begin Result := False; val(LowSpeedEdit.Text, LowSpeed, check); if (check <> 0) or (LowSpeed < 0) then begin Application.MessageBox('起動速度に誤りがあります。','注意',MB_OK); exit; end; val(HiSpeedEdit.Text, HiSpeed, check); if (check <> 0) or (HiSpeed <= 0) then begin Application.MessageBox('指定速度に誤りがあります。','注意',MB_OK); exit; end; if HiSpeed < LowSpeed then begin Application.MessageBox('指定速度より起動速度が大きいです。','注意',MB_OK); exit; end; val(RiseEdit.Text, RiseTime, check); if check <> 0 then begin Application.MessageBox('起動時間に誤りがあります。','注意',MB_OK); exit; end; val(DownEdit.Text, DownTime, check); if check <> 0 then begin Application.MessageBox('停止時間に誤りがあります。','注意',MB_OK); exit; end; val(SRatioEdit.Text, SRate, check); if (check <> 0) or (SRate < 0) then begin Application.MessageBox('Sカーブ比率に誤りがあります。','注意',MB_OK); exit; end; Result := True; end; // ------------------ S 字 非対称時 指定パルス数による 立ち上げたち下げ時間補正 function TUSPG48TESTF.MinimumPulses(var UpTime, DownTime, dHighSpeed: double; dLowSpeed, Funit: Double): Cardinal; var DownTimePulses,UpTimePulses : Cardinal; DT : double; SUpPulse: double; Nuptime, Ndowntime: double; begin DownTimePulses := Round((DownTime) * (dHighSpeed + dLowSpeed - Funit) / 2); UpTimePulses := Round((UpTime) * (dHighSpeed + dLowSpeed - Funit) / 2); Result := DownTimePulses + UpTimePulses; if indexData >= Result then exit; SUpPulse := indexData * (UpTimePulses / (UpTimePulses + DownTimePulses)); DT := (dHighSpeed - dLowSpeed) / UpTime; Nuptime := sqrt(sqr(2 * dLowSpeed - Funit) - 4 * DT * (-2 * SUppulse)); Nuptime := (-(2 * dLowSpeed - Funit) + Nuptime) / 2 / DT; Ndowntime := Nuptime / UpTime * DownTime; UpTime := Nuptime; DownTime := Ndowntime; dHighSpeed := Nuptime * DT + dLowSpeed; // Result := indexData; Edit1.Text := floatTostr(Nuptime); Edit2.Text := floatTostr(Ndowntime); end; function TUSPG48TESTF.LeftSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sUpTime, sDownTime: Word; SRate: Double): Word; // 残パルス指定速度設定 var SS_SPEED_DATA : Word; OB_SPEED_DATA : Word; RATE_1_DATA : Word; RATE_2_DATA : Word; SW1_DATA : Word; SW2_DATA : Word; Funit : double; sr : double; UpTime, DownTime : double; Utsw,Utud : double; Dtsw,Dtud : double; begin Result := 0; //*--------------------------------------------------------------- // データ設定 // sr := SRate / 100; // パーセント -> 係数 UpTime := sUpTime * 0.001; // Up mmsec -> sec DownTime := sDownTime * 0.001; // down mmsec -> sec // Rang 固定 8.191E6 ÷ 最高周波数(81920 PPS) // RANGE DATA RANGE_DATA := round(int(clockbase / dHighSpeed)); Funit := 1000 / RANGE_DATA; // 周波数設定単位 //------------------- 速度調整 ------------------------------------------- MinimumEdit.Text := intTostr(MinimumPulses(UpTime, DownTime, dHighSpeed, dLowSpeed, Funit)); // // START/STOP SPEED DATA 開始停止周波数設定単位 SS_SPEED_DATA := Round(Int(dLowSpeed / Funit)); // OBJECT SPEED DATA 目的周波数設定単位 OB_SPEED_DATA := Round(Int(dHighSpeed / Funit)); // RATE-1 DATA 加速時間設定単位 Utsw := UpTime * sr / 2; // Up Sカーブ部時間 Utud := UpTime * (1 - sr); // Up 直線部時間 Dtsw := DownTime * sr / 2; // down Sカーブ部時間 Dtud := DownTime * (1 - sr); // down 直線部時間 RATE_1_DATA := Round(Int((Utsw + Utud) / (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase)); // RATE-2 DATA 減速時間設定単位 RATE_2_DATA := Round(Int((Dtsw + Dtud) / (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase)); // 残パルス数 SLD_P_DATA := Round(Int((DownTime) * (dHighSpeed + dLowSpeed - Funit) / 2)); //SW1_DATA SW1_DATA := Round(Int(CRatebase * Utsw / 2 / RATE_1_DATA)); // S時加速区間スピードデーター if SW1_DATA < 1 then SW1_DATA := 1; // SW1_DATA が 0 ではいけない //SW2_DATA SW2_DATA := Round(Int(CRatebase * Dtsw / 2 / RATE_2_DATA)); // S時減速区間スピードデーター if SW2_DATA < 1 then SW2_DATA := 1; // SW2_DATA が 0 ではいけない // RATE-3 DATA デフォルト値 8191(1FFFh) // RATE CHANGE POINT 1-2 デフォルト値 8191(1FFFh) // RATE CHANGE POINT 2-3 デフォルト値 8191(1FFFh) // //*--------------------------------------------------------------- // MODE1 SET // // 減速開始ポイント検出方式 残パルス数指定 // パルス出力方式 2パルス方式 // DIR 出力端子 CWパルス アクティブ Hi // PULSE 出力端子 CCWパルス アクティブ Hi //--------------------------------------------------------------*/ // if False = CTDMode1Write(wBsn, wAxis, $C0) then Exit; if False = CTDMode1Write(wBsn, wAxis, $E0) then Exit; //*--------------------------------------------------------------- if False = CTDCommandWrite(wBsn, wAxis, CTD_US_S_CURVE_ACCELERATE_MODE_SET) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RANGE_WRITE, RANGE_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_WRITE, SS_SPEED_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_WRITE, OB_SPEED_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE1_DATA_WRITE, RATE_1_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE2_DATA_WRITE, RATE_2_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_SW1_DATA_WRITE, SW1_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_SW2_DATA_WRITE, SW2_DATA) then Exit; if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, SLD_P_DATA) then Exit; Result := 1; end; function TUSPG48TESTF.StraightSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double;sUpDownTime: Word): Word; // 直線加速指定速度設定 var SS_SPEED_DATA : Word; OB_SPEED_DATA : Word; RATE_1_DATA : Word; Funit : double; UpDownTime :double; begin Result := 0; //*--------------------------------------------------------------- // MODE1 SET // // 減速開始ポイント検出方式 自動 // パルス出力方式 2パルス方式 // DIR 出力端子 CWパルス アクティブ Hi // PULSE 出力端子 CCWパルス アクティブ Hi //--------------------------------------------------------------*/ // if False = CTDMode1Write(wBsn, wAxis, $40) then Exit; // $40 $60 は、回転方向 if False = CTDMode1Write(wBsn, wAxis, $60) then Exit; // CCWPuls CWPuls 切り替え //*--------------------------------------------------------------- // データ設定 // UpDownTime := sUpDownTime * 0.001; // Up mmsec -> sec // RANGE DATA RANGE_DATA := round(int(clockbase / dHighSpeed)); // Rang 固定 8.191E6 ÷ 最高周波数(dHighSpeed) // Funit 出力周波数設定単位 Funit := 1000 / RANGE_DATA; // Funit = 1000÷RANGE // START/STOP SPEED DATA 開始停止設定単位 SS_SPEED_DATA = dLowSpeed ÷ Funit SS_SPEED_DATA := Round(Int(dLowSpeed / Funit)); // OBJECT SPEED DATA 目的周波数設定単位 OB_SPEED_DATA = dHighSpeed ÷ Funit; OB_SPEED_DATA := Round(Int(dHighSpeed / Funit)); // RATE-1 DATA 加減時間設定単位 // RATE_1_DATA = UpDownTime ÷ (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase RATE_1_DATA := Round(Int((UpDownTime) / (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase)); // RATE-2 DATA デフォルト値 8191(1FFFh) // RATE-3 DATA デフォルト値 8191(1FFFh) // RATE CHANGE POINT 1-2 デフォルト値 8191(1FFFh) // RATE CHANGE POINT 2-3 デフォルト値 8191(1FFFh) // //--------------------------------------------------------------*/ if False = CTDCommandWrite(wBsn, wAxis, CTD_STRAIGHT_ACCELERATE_MODE_SET) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RANGE_WRITE, RANGE_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_WRITE, SS_SPEED_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_WRITE, OB_SPEED_DATA) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE1_DATA_WRITE, RATE_1_DATA) then Exit; // 残パルス数を 0 にしないと、減速後 残パルス数移動する if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, 0) then Exit; Result := 1; end; function TUSPG48TESTF.InitAxis(wBsn, wAxis: Word): LongBool; // 軸初期化 begin // 返り値 False 既設定 Result := False; //*--------------------------------------------------------------- // MODE1 SET // // 減速開始ポイント検出方式 自動 // パルス出力方式 2パルス方式 // DIR 出力端子 CWパルス アクティブ Hi // PULSE 出力端子 CCWパルス アクティブ Hi //--------------------------------------------------------------*/ // if False = CTDMode1Write(wBsn, wAxis, $40) then Exit; if False = CTDMode1Write(wBsn, wAxis, $60) then Exit; // 減速開始ポイント検出方式 残パルス数 // if False = CTDMode1Write(wBsn, wAxis, $C0) then Exit; //*--------------------------------------------------------------- // MODE2 SET // // EXTERNAL COUNTER 入力仕様 None // DEND 入力信号アクティブレベル High // DERR 入力信号アクティブレベル High // -SLM 入力信号アクティブレベル High // +SLM 入力信号アクティブレベル High // -ELM 入力信号アクティブレベル High // +ELM 入力信号アクティブレベル High //--------------------------------------------------------------*/ if False = CTDMode2Write(wBsn, wAxis, $3F) then Exit; //*--------------------------------------------------------------- // モード設定 // // STRAIGHT ACCELERATE MODE // INPOSITION WAIT MODE RESET // ALARM STOP ENABLE MODE SET //--------------------------------------------------------------*/ if False = CTDCommandWrite(wBsn, wAxis, CTD_STRAIGHT_ACCELERATE_MODE_SET) then Exit; if False = CTDCommandWrite(wBsn, wAxis, CTD_INPOSITION_WAIT_MODE_RESET) then Exit; if False = CTDCommandWrite(wBsn, wAxis, CTD_ALARM_STOP_ENABLE_MODE_SET) then Exit; //*--------------------------------------------------------------- // データ設定 // RANGE DATA 100 8.191E6 ÷ 最高周波数(PPS) // Funit 10 出力周波数設定単位 1000÷100=10PPS // START/STOP SPEED DATA 50 開始停止周波数 50× 10PPS=500PPS // OBJECT SPEED DATA 400 目的周波数 400× 10PPS=4000PPS // RATE-1 DATA 2048 加速時間設定単位 2048÷(4.096×10^6)= 0.5mSec // 加速減時間 (400-50)×0.5mSec = 0.175Sec // RATE-2 DATA デフォルト値 8191(1FFFh) // RATE-3 DATA デフォルト値 8191(1FFFh) // RATE CHANGE POINT 1-2 デフォルト値 8191(1FFFh) // RATE CHANGE POINT 2-3 デフォルト値 8191(1FFFh) // // この設定により RATE-1 DATA による直線加減速となります //--------------------------------------------------------------*/ if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RANGE_WRITE, 100) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_WRITE, 50) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_WRITE, 200) then Exit; if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE1_DATA_WRITE, 2048) then Exit; // 残パルス数を 0 にしないと、減速後 残パルス数移動する if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, 0) then Exit; //*--------------------------------------------------------------- // アドレス設定 // // INTERNAL COUNTER 及び EXTERNAL COUNTER に 0h を書き込みます //--------------------------------------------------------------*/ if False = CTDDataFullWrite(wBsn, wAxis, CTD_INTERNAL_COUNTER_WRITE, 0) then Exit; if False = CTDDataFullWrite(wBsn, wAxis, CTD_EXTERNAL_COUNTER_WRITE, 0) then Exit; // 返り値 True設定 Result := True; end; procedure TUSPG48TESTF.Orgmove(wAxis: Word); //原点復帰 label Rewhile; var b : byte; begin OriginBtn.Enabled := False; // 原点復帰開始イベントで STATE = 11 を設定する。 // STATE の初期値は0 から3 と11 以外とする。 // STATE := 10; while (STATE <> 10) or (STATE_SUB <> 10) do // 原点復帰したらループを抜ける begin case STATE of 0:begin // STATE=0 原点復帰開始 ステート Ack := CTDGetMechanicalSignal(wBsn,wAxis, b); // メカ二ルシグナル読み込み if b and $A = 0 then // -ELM or .SLM がOFF の時。 // 開始位置-リミットにない。ORG↑-シグナルサーチ1 開始 STATE := 1 // 開始位置-リミットにない else // 開始位置-リミット。 ORG↓+シグナルサーチ1 開始 STATE := 2; // 開始位置-リミット goto Rewhile; end; 1:begin // STATE=1・・・開始位置-リミットにない ステート case STATE_SUB of // STATE_DUB はSTATE 内の内部STATE 0:begin // Ack := CTDMode1Write(wBsn, wAxis, $4C); // IN0-n(ORG-n)立ち上がりエッジ Ack := CTDMode1Write(wBsn, wAxis, $6C); // IN0-n(ORG-n)立ち上がりエッジ Ack := CTDCommandWrite(wBsn, wAxis, $25); // -SignalSearchDrive-1 ReadyF[wAxis] := False; // ReadyF 解除 STATE_SUB := 1; // STATE=1 のSTATE_SUB=0 のDrive 終了待ちSTATE へ移行 goto Rewhile; end; 2:begin Ack := CTDGetMechanicalSignal(wBsn,wAxis, b); // メカニカルシグナル読み込み if b and $A = 0 then // -ELM or .SLM がOFF の時、開始位置 ORG-n より+側にある。 // 開始位置 ORG-n より+側にある。ORG↓+シグナルサーチ2 開始 STATE_SUB := 3 // STATE=1 のSTATE_SUB=2 のDrive 終了待ちSTATE へ移行 else begin STATE := 2; // 開始位置がORG-n より-側にある STATE=2 はSTATE=1 からの派生STATE。 STATE_SUB := 0; // STATE=2 の内部STATE を初期化。(STATE_SUB) end; goto Rewhile; end; end; goto Rewhile; end; 2:begin // STATE=2 ・・STATE=1 からの派生STATE。 開始位置がORG-n より-側にある ステート case STATE_SUB of // STATE=3 ・・開始位置-リミットにある ステート 0:begin // 開始位置 ORG-n より-側にある。ORG↓+シグナルサーチ1 開始 // Ack := CTDMode1Write(wBsn, wAxis, $44); // IN0-n(ORG-n)立下りエッジ Ack := CTDMode1Write(wBsn, wAxis, $64); // IN0-n(ORG-n)立下りエッジ Ack := CTDCommandWrite(wBsn, wAxis, $24); // +SignalSearchDrive-1 ReadyF[wAxis] := False; // ReadyF 解除 STATE_SUB := 1; // STATE=2,3 のSTATE_SUB=0 のDrive 終了待ちSTATE へ移行 goto Rewhile; end; 2:begin // ORG↑-シグナルサーチ2 開始 // Ack := CTDMode1Write(wBsn, wAxis, $4C); // IN0-n(ORG-n)立上がりエッジ Ack := CTDMode1Write(wBsn, wAxis, $6C); // IN0-n(ORG-n)立上がりエッジ Ack := CTDCommandWrite(wBsn, wAxis, $27); // -SignalSearchDrive-2 ReadyF[wAxis] := False; // ReadyF 解除 STATE_SUB := 3; // STATE=2,3 のSTATE_SUB=2 のDrive 終了待ちSTATE へ移行 goto Rewhile; end; 4:begin // ORG↓+シグナルサーチ2 開始 // Ack := CTDMode1Write(wBsn, wAxis, $44); // IN0-n(ORG-n)立下りエッジ Ack := CTDMode1Write(wBsn, wAxis, $64); // IN0-n(ORG-n)立下りエッジ Ack := CTDCommandWrite(wBsn, wAxis, $26); // +SignalSearchDrive-2 ReadyF[wAxis] := False; // ReadyF 解除 STATE_SUB := 5; // STATE=2,3 のSTATE_SUB=4 のDrive 終了待ちSTATE へ移行 goto Rewhile; end; 6:begin // カウンタークリア Ack := CTDDataFullWrite(wBsn,wAxis,CTD_INTERNAL_COUNTER_WRITE,0); Ack := CTDDataFullWrite(wBsn,wAxis,CTD_EXTERNAL_COUNTER_WRITE,0); // "原点復帰終了"; STATE_SUB := 10; STATE := 10; goto Rewhile; end; end; goto Rewhile; end; 11:begin // 開始 ステート STATE := 0; STATE_SUB := 0; end; end; Rewhile: application.ProcessMessages; if ReadyF[wAxis] then // Ready case STATE of 1,2:begin // STATE=1・・・開始位置-リミットにない ステート case STATE_SUB of 1: STATE_SUB := 2; // ドライブ終了 STATE=1,2,3 のSTATE_SUB=2 へ移行 3: begin STATE_SUB := 4; STATE := 2; end; // ドライブ終了 STATE= 2,3 のSTATE_SUB=4 へ移行 5: STATE_SUB := 6; // ドライブ終了 STATE= 2,3 のSTATE_SUB=6 へ移行 end; end; end; end; OriginBtn.Enabled := True; end; procedure TUSPG48TESTF.DllVerGetBtnClick(Sender: TObject); begin Edit2.Text := ''; Ack := CTDGetLibVersion(Versionchar); if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); end; Edit1.Text := string(Versionchar); end; procedure TUSPG48TESTF.DrvVerGetBtnClick(Sender: TObject); begin Edit2.Text := ''; Ack := CTDGetDrvVersion(Versionchar); if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); end; Edit1.Text := String(Versionchar); end; procedure TUSPG48TESTF.AxisIniBtnClick(Sender: TObject); var inAxis,check: integer; begin Edit1.Text := ''; Edit2.Text := ''; val(AxisNoEdit.Text, inAxis, check); if check <> 0 then begin application.MessageBox('数値以外が入力されています。','注意',MB_OK); exit; end; case inAxis of 1 : wAxis := CTD_AXIS_1; // 第一軸 2 : wAxis := CTD_AXIS_2; // 第二軸 3 : wAxis := CTD_AXIS_3; // 第三軸 4 : wAxis := CTD_AXIS_4; // 第四軸 else begin application.MessageBox('軸Noの範囲は1~4です。','注意',MB_OK); exit; end; end; Ack:= InitAxis(wBsn,wAxis); // 軸初期化 if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; Chk:= CTDSpeedWrite(wBsn,wAxis,100); // 速度100% OriginBtn.Enabled := True; CwIndexBtn.Enabled := True; CCwIndexBtn.Enabled := True; ZeroRtnBtn.Enabled := True; SlowStopBtn.Enabled := True; InternalCouterBtn.Enabled := True; SModesetbtn.Enabled := True; DMODbtn.Enabled := True; UDESmodebtn.Enabled := True; CwScanBtn.Enabled := True; CCwScanBtn.Enabled := True; RangeReadbtn.Enabled := True; AbsBtn.Enabled := True; ObjectspeedBtn.Enabled := True; AxisIniBtn.Enabled := False; Edit2.Text := 'Open 成功'; end; procedure TUSPG48TESTF.OriginBtnClick(Sender: TObject); // 原点復帰 begin Edit2.Text := ''; STATE := 11; Ack:= InitAxis(wBsn, wAxis); // wAxis軸初期化 if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; Orgmove(wAxis); // 原点復帰 end; procedure TUSPG48TESTF.CwIndexBtnClick(Sender: TObject); begin val(IndexEdit.Text,indexData,check); if check <> 0 then exit; if SHModeF then if not NESModeset then exit; CTDDataFullWrite(wBsn, wAxis, CTD_PLUS_PRESET_PULSE_DRIVE, indexData); end; procedure TUSPG48TESTF.CCwIndexBtnClick(Sender: TObject); begin val(IndexEdit.Text,indexData,check); if check <> 0 then exit; if SHModeF then if not NESModeset then exit; CTDDataFullWrite(wBsn, wAxis, CTD_MINUS_PRESET_PULSE_DRIVE, indexData); end; procedure TUSPG48TESTF.ZeroRtnBtnClick(Sender: TObject); // ゼロ位置移動 var ITCounter: DWord; begin Edit2.Text := ''; Ack := CTDDataFUllRead(wBsn, wAxis, CTD_INTERNAL_COUNTER_READ,ITCounter); if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; if integer(ITCounter) > 0 then Ack := CTDDataFullWrite(wBsn, wAxis, CTD_MINUS_PRESET_PULSE_DRIVE, ITCounter) else begin ITCounter := 0 - integer(ITCounter); Ack := CTDDataFullWrite(wBsn, wAxis, CTD_PLUS_PRESET_PULSE_DRIVE, ITCounter) end; if not ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; end; procedure TUSPG48TESTF.SlowStopBtnClick(Sender: TObject); begin Edit2.Text := ''; Ack := CTDCommandWrite(wBsn, wAxis, CTD_SLOW_DOWN_STOP); if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); end; end; procedure TUSPG48TESTF.InternalCouterBtnClick(Sender: TObject); var EXTCounter: Dword; begin Edit1.Text := ''; Edit2.Text := ''; // Ack := CTDGetExternalCounter(wBsn, wAxis, EXTCounter); Ack := CTDGetInternalCounter(wBsn, wAxis, EXTCounter); if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; Edit1.Text := intTostr(integer(EXTCounter)); end; procedure TUSPG48TESTF.DeviceOpen; begin wBsn := CTD_USPG48_ID or 0; // USPG48_ID + USB ADDr chk := CTDCreate(wBsn); if chk < 0 then begin Err := CTDGetLastError(wBsn); Edit1.Text := CTDGetErrorStr(Err); AxisIniBtn.Enabled := False; end else begin OpenBtn.Enabled := False; Edit2.Text := '軸初期化してください。'; end; end; procedure TUSPG48TESTF.BtnFalseSet; begin OriginBtn.Enabled := False; CwIndexBtn.Enabled := False; CCwIndexBtn.Enabled := False; ZeroRtnBtn.Enabled := False; SlowStopBtn.Enabled := False; InternalCouterBtn.Enabled := False; SModesetbtn.Enabled := False; DMODbtn.Enabled := False; UDESmodebtn.Enabled := False; CwScanBtn.Enabled := False; CCwScanBtn.Enabled := False; RangeReadbtn.Enabled := False; AbsBtn.Enabled := False; ObjectspeedBtn.Enabled := False; LowSpeedBtn.Enabled := False; HiSpeedBtn.Enabled := False; end; procedure TUSPG48TESTF.FormCreate(Sender: TObject); var Ini: TIniFile; begin Edit1.Text := ''; Edit2.Text := ''; Ready1Edit.Text := ''; Ready2Edit.Text := ''; Ready3Edit.Text := ''; Ready4Edit.Text := ''; AxisNoEdit.Text := '1'; BtnFalseSet; DeviceOpen; Ini :=TIniFile.Create(ChangeFileExt(Application.ExeName,'.INI' )); try Top := Ini.ReadInteger('Form','Top',100 ); Left := Ini.ReadInteger('Form','Left',100 ); LowSpeedEdit.Text := Ini.ReadString('CtdSpeed','LowSpeed','200'); HiSpeedEdit.Text := Ini.ReadString('CtdSpeed','HiSpeed','6000'); RiseEdit.Text := Ini.ReadString('CtdSpeed','RiseTime','200'); DownEdit.Text := Ini.ReadString('CtdSpeed','DownTime','500'); SRatioEdit.Text := Ini.ReadString('CtdSpeed','SRatio%','100'); AxisNoEdit.Text := Ini.ReadString('AxisNo','Axis','1'); AbsEdit.Text := Ini.ReadString('AbsPulses','AbsNo','0'); IndexEdit.Text := Ini.ReadString('IndexPulses','Index','1000'); if Ini.ReadBool('Form', 'InitMax', false) then WindowState := wsMaximized else WindowState := wsNormal; finally Ini.Free; end; end; procedure TUSPG48TESTF.FormClose(Sender: TObject; var Action: TCloseAction); var Ini: TIniFile; begin CTDClose(wBsn); Ini :=TIniFile.Create(ChangeFileExt(Application.ExeName,'.INI' )); try Ini.WriteInteger('Form','Top',Top); Ini.WriteInteger('Form','Left',Left); Ini.WriteString('CtdSpeed','LowSpeed',LowSpeedEdit.Text); Ini.WriteString('CtdSpeed','HiSpeed',HiSpeedEdit.Text); Ini.WriteString('CtdSpeed','RiseTime',RiseEdit.Text); Ini.WriteString('CtdSpeed','DownTime',DownEdit.Text); Ini.WriteString('CtdSpeed','SRatio%',SRatioEdit.Text); Ini.WriteString('AxisNo','Axis',AxisNoEdit.Text); Ini.WriteString('AbsPulses','AbsNo',AbsEdit.Text); Ini.WriteString('IndexPulses','Index',IndexEdit.Text); Ini.WriteBool('Form', 'InitMax', WindowState = wsMaximized); finally Ini.Free; end; end; function TUSPG48TESTF.NESModeset: boolean; var b : byte; begin Result := False; Ack := CTDGetDriveStatus(wBsn, wAxis, b); //ドライブステータス 読み込み if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; if (b and $01 = $01) then begin Edit2.Text := 'Busy'; exit; // Busy だったら終了 end; val(IndexEdit.Text, indexData, check); if check <> 0 then exit; chk := LeftSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, DownTime, SRate); // S 残パルス指定速度設定 起動速度pps, 目標速度pps, 起動時間msec, 減速時間mse S時間% if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; Result := true; end; procedure TUSPG48TESTF.SModesetbtnClick(Sender: TObject); begin Edit2.Text := ''; if not SpeedDataInput then exit; Chk:= CTDSpeedWrite(wBsn, wAxis, 100); // 速度100% CTDSpeedParameterWriteの時のみ有効 if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end else begin SHModeF := True; LowSpeedBtn.Enabled := False; HiSpeedBtn.Enabled := False; end; val(IndexEdit.Text, indexData, check); if check <> 0 then exit; LeftSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, DownTime, SRate); // 残パルス指定速度設定 end; procedure TUSPG48TESTF.DMODbtnClick(Sender: TObject); // UpDown時間等しい直線加速設定 begin if not SpeedDataInput then exit; Chk:= CTDSpeedWrite(wBsn, wAxis, 100); // 速度100% CTDSpeedParameterWriteの時のみ有効 if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; Edit2.Text := ''; chk := StraightSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime); // 直線起動設定 起動速度pps 目標速度pps 起動減速時間msec if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; SHModeF := False; LowSpeedBtn.Enabled := False; HiSpeedBtn.Enabled := False; end; procedure TUSPG48TESTF.UDESmodebtnClick(Sender: TObject); // UpDown時間等しいS時モード設定 begin if not SpeedDataInput then exit; Edit2.Text := ''; Chk:= CTDSpeedWrite(wBsn, wAxis, 100); // 速度100% CTDSpeedParameterWriteの時のみ有効 if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; // if False = CTDMode1Write(wBsn, wAxis, $40) then Exit; // CTDSpeedParameterWrite 使用時は if False = CTDMode1Write(wBsn, wAxis, $60) then Exit; // 減速自動計算モードに切り替え if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, 0) then // 残パル数0に設定 begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); Exit; end; chk := CTDSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, SRate); // 起動速度pps 目標速度pps 起動減速時間msec S時間 % if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; SHModeF := False; LowSpeedBtn.Enabled := True; HiSpeedBtn.Enabled := True; end; procedure TUSPG48TESTF.HiSpeedBtnClick(Sender: TObject); begin Chk:= CTDSpeedWrite(wBsn, wAxis, 100); // 速度100% CTDSpeedParameterWriteの時のみ有効 if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); end; end; procedure TUSPG48TESTF.LowSpeedBtnClick(Sender: TObject); begin Chk:= CTDSpeedWrite(wBsn, wAxis, 50); // 速度50% CTDSpeedParameterWriteの時のみ有効 if chk = 0 then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); end; end; procedure TUSPG48TESTF.CwScanBtnClick(Sender: TObject); begin Ack := CTDCommandWrite(wBsn, wAxis, CTD_PLUS_CONTINUOUS_DRIVE); if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); end; end; procedure TUSPG48TESTF.CCwScanBtnClick(Sender: TObject); begin Ack := CTDCommandWrite(wBsn, wAxis, CTD_MINUS_CONTINUOUS_DRIVE); if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); end; end; procedure TUSPG48TESTF.RangeReadbtnClick(Sender: TObject); // Range 読み出し begin if False = CTDDataHalfRead(wBsn, wAxis, CTD_RANGE_READ, RANGE_DATA) then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); Exit; end; Edit2.Text := intTostr(RANGE_DATA); end; procedure TUSPG48TESTF.Timer1Timer(Sender: TObject); var Loopd: word; // Axis begin for Loopd := 0 to 3 do begin if not CTDGetDriveStatus(wBsn, Loopd, Bdata) then begin Err := CTDGetLastError(wBsn); if Err = CTD_ERR_USB_REMOVE then begin Timer1.Enabled := False; Edit2.Text := 'デバイスが取り外されました。'; CTDClose(wBsn); BtnFalseSet; end; if Err = CTD_ERR_TRANS then begin Timer1.Enabled := False; Edit2.Text := '通信エラーです。'; CTDClose(wBsn); BtnFalseSet; end; exit; //ドライブステータス 読み込み end; if Bdata and $01 = 0 then begin // Drive 終了 ReadyF[Loopd] := True; case Loopd of 0: Ready1Edit.Text := 'Reay'; 1: Ready2Edit.Text := 'Reay'; 2: Ready3Edit.Text := 'Reay'; 3: Ready4Edit.Text := 'Reay'; end; end else begin ReadyF[Loopd] := False; case Loopd of 0: Ready1Edit.Text := 'Not Reay'; 1: Ready2Edit.Text := 'Not Reay'; 2: Ready3Edit.Text := 'Not Reay'; 3: Ready4Edit.Text := 'Not Reay'; end; end; end; end; procedure TUSPG48TESTF.OpenBtnClick(Sender: TObject); begin DeviceOpen; end; procedure TUSPG48TESTF.ObjectspeedBtnClick(Sender: TObject); // 速度データー読み出し var SPEeD_DATA :word; LSPeD_Data :word; begin if False = CTDDataHalfRead(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_READ, SPEeD_DATA) then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); Exit; end; if False = CTDDataHalfRead(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_READ, LSPeD_Data) then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); Exit; end; Edit1.Text := intTostr(SPEeD_DATA); Edit2.Text := intTostr(LSPeD_Data); end; procedure TUSPG48TESTF.AbsBtnClick(Sender: TObject); // 指定位置移動 var ITCounter : Dword; AbsData : integer; begin val(AbsEdit.Text, absData, check); if check <> 0 then exit; Ack := CTDDataFUllRead(wBsn, wAxis, CTD_INTERNAL_COUNTER_READ,ITCounter); // 現在位置取得 if not Ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; ITCounter := integer(ITCounter) - AbsData; // 移動量計算 if integer(ITCounter) > 0 then Ack := CTDDataFullWrite(wBsn, wAxis, CTD_MINUS_PRESET_PULSE_DRIVE, ITCounter) else begin ITCounter := 0 - integer(ITCounter); Ack := CTDDataFullWrite(wBsn, wAxis, CTD_PLUS_PRESET_PULSE_DRIVE, ITCounter) end; if not ack then begin Err := CTDGetLastError(wBsn); Edit2.Text := CTDGetErrorStr(Err); exit; end; end; procedure TUSPG48TESTF.MinimumBtnClick(Sender: TObject); begin val(IndexEdit. Text,indexData, check); if check <> 0 then exit; if not SpeedDataInput then exit; LeftSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, DownTime, SRate); // 残パルス指定速度設定 end; initialization RANGE_DATA := 100; end.
unit CTD20DLL; interface uses Types; //----------------------------------------------------------------- // Error code //----------------------------------------------------------------- const CTD_SUCCESS = 0; // 異状なし(正常終了) CTD_ERR_NO_DEVICE = 2; // 使用可能なデバイスがありません CTD_ERR_IN_USE = 3; // 指定のデバイスは使用中です CTD_ERR_INVALID_BSN = 4; // 無効なボードセレクトナンバーです // デバイスがバス上にないか // 使用宣言されていません CTD_ERR_INVALID_PORT = 6; // 不正なポートを要求した CTD_ERR_PARAMETER = 7; // 引数の値が範囲外です CTD_ERR_INVALID_AXIS = 50; // 無効な制御軸を要求した CTD_ERR_TRANS = 60; // 送信時の通信エラーです CTD_ERR_RECEIVE = 61; // 受信時の通信エラーです CTD_ERR_USB_REMOVE = 62; // デバイスが取り外されました CTD_ERR_WRAPDLL = $FFFFFFFF; // ラッパー関数内エラー DWord - 1 //----------------------------------------------------------------- // Axis //----------------------------------------------------------------- CTD_AXIS_1 = 0; CTD_AXIS_2 = 1; CTD_AXIS_3 = 2; CTD_AXIS_4 = 3; //----------------------------------------------------------------- // I/O Map //----------------------------------------------------------------- CTD_PORT_DATA1 = 0; CTD_PORT_DATA2 = 1; CTD_PORT_DATA3 = 2; CTD_PORT_DATA4 = 3; CTD_PORT_COMMAND = 4; CTD_PORT_MODE1 = 5; CTD_PORT_MODE2 = 6; CTD_PORT_UNIVERSAL_SIGNAL = 7; CTD_PORT_DRIVE_STATUS = 4; CTD_PORT_END_STATUS = 5; CTD_PORT_MECHANICAL_SIGNAL = 6; //----------------------------------------------------------------- // command //----------------------------------------------------------------- CTD_RANGE_WRITE = $00; CTD_RANGE_READ = $01; CTD_START_STOP_SPEED_DATA_WRITE = $02; CTD_START_STOP_SPEED_DATA_READ = $03; CTD_OBJECT_SPEED_DATA_WRITE = $04; CTD_OBJECT_SPEED_DATA_READ = $05; CTD_RATE1_DATA_WRITE = $06; CTD_RATE1_DATA_READ = $07; CTD_RATE2_DATA_WRITE = $08; CTD_RATE2_DATA_READ = $09; CTD_RATE3_DATA_WRITE = $0A; CTD_RATE3_DATA_READ = $0B; CTD_RATE_CHANGE_POINT_1_2_WRITE = $0C; CTD_RATE_CHANGE_POINT_1_2_READ = $0D; CTD_RATE_CHANGE_POINT_2_3_WRITE = $0E; CTD_RATE_CHANGE_POINT_2_3_READ = $0F; CTD_SLOW_DOWN_REAR_PULSE_WRITE = $10; CTD_SLOW_DOWN_REAR_PULSE_READ = $11; CTD_NOW_SPEED_DATA_READ = $12; CTD_DRIVE_PULSE_COUNTER_READ = $13; CTD_PRESET_PULSE_DATA_OVERRIDE = $14; CTD_PRESET_PULSE_DATA_READ = $15; CTD_DEVIATION_DATA_READ = $16; CTD_INPOSITION_WAIT_MODE1_SET = $17; CTD_INPOSITION_WAIT_MODE2_SET = $18; CTD_INPOSITION_WAIT_MODE_RESET = $19; CTD_ALARM_STOP_ENABLE_MODE_SET = $1A; CTD_ALARM_STOP_ENABLE_MODE_RESET = $1B; CTD_SLOW_DOWN_STOP = $1E; CTD_EMERGENCY_STOP = $1F; CTD_PLUS_PRESET_PULSE_DRIVE = $20; CTD_MINUS_PRESET_PULSE_DRIVE = $21; CTD_PLUS_CONTINUOUS_DRIVE = $22; CTD_MINUS_CONTINUOUS_DRIVE = $23; CTD_PLUS_SIGNAL_SEARCH1_DRIVE = $24; CTD_MINUS_SIGNAL_SEARCH1_DRIVE = $25; CTD_PLUS_SIGNAL_SEARCH2_DRIVE = $26; CTD_MINUS_SIGNAL_SEARCH2_DRIVE = $27; CTD_INTERNAL_COUNTER_WRITE = $28; CTD_INTERNAL_COUNTER_READ = $29; CTD_INTERNAL_COMPARATE_DATA_WRITE = $2A; CTD_INTERNAL_COMPARATE_DATA_READ = $2B; CTD_EXTERNAL_COUNTER_WRITE = $2C; CTD_EXTERNAL_COUNTER_READ = $2D; CTD_EXTERNAL_COMPARATE_DATA_WRITE = $2E; CTD_EXTERNAL_COMPARATE_DATA_READ = $2F; CTD_INTERNAL_PRE_SCALE_DATA_WRITE = $30; CTD_INTERNAL_PRE_SCALE_DATA_READ = $31; CTD_EXTERNAL_PRE_SCALE_DATA_WRITE = $32; CTD_EXTERNAL_PRE_SCALE_DATA_READ = $33; CTD_CLEAR_SIGNAL_SELECT = $34; CTD_ONE_TIME_CLEAR_REQUEST = $35; CTD_FULL_TIME_CLEAR_REQUEST = $36; CTD_CLEAR_REQUEST_RESET = $37; CTD_REVERSE_COUNT_MODE_SET = $38; CTD_REVERSE_COUNT_MODE_RESET = $39; CTD_NO_OPERATION = $3A; CTD_STRAIGHT_ACCELERATE_MODE_SET = $84; CTD_US_STRAIGHT_ACCELERATE_MODE_SET = $85; CTD_S_CURVE_ACCELERATE_MODE_SET = $86; CTD_US_S_CURVE_ACCELERATE_MODE_SET = $87; CTD_SW1_DATA_WRITE = $88; CTD_SW1_DATA_READ = $89; CTD_SW2_DATA_WRITE = $8A; CTD_SW2_DATA_READ = $8B; CTD_SLOW_DOWN_LIMIT_ENABLE_MODE_SET = $8C; CTD_SLOW_DOWN_LIMIT_ENABLE_MODE_RESET = $8D; CTD_EMERGENCY_LIMIT_ENABLE_MODE_SET = $8E; CTD_EMERGENCY_LIMIT_ENABLE_MODE_RESET = $8F; CTD_INITIAL_CLEAR = $90; CTD_USPG48_ID : Word = $0000; // 上位バイトが機種ID //----------------------------------------------------------------- // Misc //----------------------------------------------------------------- CTD_MAX_SLOTS = 16; //----------------------------------------------------------------- // Additional 定数 //----------------------------------------------------------------- FCLK = 32768000; // 32.768MHz //----------------------------------------------------------------- // 補間パラメーター //----------------------------------------------------------------- type CTIPDRIVEPARAMETER = record bIpAxis : array[0..3] of Byte; // 補間軸 bIpKind : array[0..0] of Byte; // 補間種類 bMovekind : array[0..0] of Byte; // 0=相対座標 1=絶対座標 lObjPoint : array[0..1] of Longint; // 目標位置 [0]=X軸 [1]=Y軸 lCenterPoint : array[0..1] of Longint; // 中心位置 [0]=X軸 [1]=Y軸 lN2Data1 : array[0..0] of Longint; // lN2Data2 : array[0..0] of Longint; // lN2Data3 : array[0..0] of Longint; // bIpconsin : array[0..0] of Byte; // 1=連続補間 0=補間 bEndkind : array[0..0] of Byte; // 0=減速停止 1=急停止 bDrawIn : array[0..0] of Byte; // 引き込み制御 0=無効 1=有効 end; //-------------------------------------------------------------------- // バージョン読み出し用 //-------------------------------------------------------------------- Verchar = array[0..32] of Ansichar; // バージョン読み出し用文字配列型 var Versionchar: verchar; //----------------------------------------------------------------- // API Functions //----------------------------------------------------------------- function CTDCreate(wBsn: Word): Smallint; stdcall external 'CTD20.Dll'; function CTDClose(wBsn: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDWrite(wBsn: Word; var str: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDReadData(wBsn: Word; var str: Byte; Status, kind, cmd, asxis: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDRead(wBsn: Word; var str: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDwrData(wBsn: Word; var str: Byte): LongBool; stdcall external 'CTD20.Dll'; //----------ダイレクト制御専用 関数---------------------------------------------------- function CTDGetLibVersion(var pbLibVersion: verchar): LongBool; stdcall external 'CTD20.Dll'; function CTDGetDrvVersion(var pbDrvVersion: verchar): LongBool; stdcall external 'CTD20.Dll'; function CTDGetRomVersion(wBsn: Word; var pbRomVersion: verchar): LongBool; stdcall external 'CTD20.Dll'; function CTDGetLastError(wBsn: Word): DWord; stdcall external 'CTD20.Dll'; function CTDDeviceStatus(wBsn: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDInPort(wBsn, wAxis, wPort: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDOutPort(wBsn, wAxis, wPort: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDGetDriveStatus(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDGetEndStatus(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDGetMechanicalSignal(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDGetUniversalSignal(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDGetInternalCounter(wBsn, wAxis: Word; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDGetExternalCounter(wBsn, wAxis: Word; var pdwData: Dword): LongBool; stdcall external 'CTD20.Dll'; function CTDGetNowSpeedData(wBsn, wAxis: Word; var pwData: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDGetDrivePulseCounter(wBsn, wAxis: Word; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDMode1Write(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDMode2Write(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDUniversalSignalWrite(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDDataHalfRead(wBsn, wAxis: Word; bCmd: Byte; var pwData: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDDataFullRead(wBsn, wAxis: Word; bCmd: Byte; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDCommandWrite(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDDataHalfWrite(wBsn, wAxis: Word; bdata: Byte; wdata: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDDataFullWrite(wBsn, wAxis: Word; bdata: Byte; dwdata: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDLineFallOut(wBsn, wAxis, wdata: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDStartSignalWrite(wBsn: Word; dwdata: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDGetAxisStatus(wBsn: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDGetAxisAllPort(wBsn, wAxis: Word; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDSetIpParameter(wBsn: Word; var pDriveParameter: CTIPDRIVEPARAMETER; wIndex: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDIpExe(wBsn, wcmd: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDIpExeSub(wBsn, wcmd: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDIpReset(wBsn: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDIpSpeedPush(wBsn: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDIpSpeedPop(wBsn: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDIpStraight(wBsn: Word; var blpAxis: Ansichar; l0bjx,l0bjy: integer; var IN2, integer; bDrawin, bspd:Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDIpStraightE(wBsn: Word; var blpAxis: Ansichar; l0bjx,l0bjy: integer; var IN2, integer; bDrawin, bspd:Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDGetIpPulse(wBsn, wAxis: Word; var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDSetIpPulse(wBsn, wAxis: Word; dwDara: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDGetIpIoRead(wBsn, wAxis: Word; var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDSetIpIoWrite(wBsn, wAxis: Word; dwDara: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDGetIoRead(wBsn, wAxis: Word; var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDSetIoWrite(wBsn, wAxis: Word;var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDGetIpStepNo(wBsn, wAxis: Word;var pdwStepNo: DWord): LongBool; stdcall external 'CTD20.Dll'; function CTDlpParaSet(bMoveKind, blpconsin, bDrawln: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDlpAxisSet(blpAxis1, blpAxis2, blpAxis3, blpAxis4: Byte): LongBool; stdcall external 'CTD20.Dll'; function CTDlpDataSet(wBsn: Word; blpkind: Byte; l0bjx, l0BJy, lCenterX, lCenterY, lN2D2, lN2D3,lN2D4: integer; wStepNo: Word): LongBool; stdcall external 'CTD20.Dll'; function CTDSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sAccTime: Word; dSRate: Double): Word; stdcall external 'CTD20.Dll'; function CTDSpeedParameterRead(wBsn, wAxis: Word; var pdLowSpeed, pdHighSpeed: Double; var psAccTime: Word; var pdSRate: Double): WordBool; stdcall external 'CTD20.Dll'; function CTDSpeedWrite(wBsn, wAxis: Word; dObjSpeed: Double): Word; stdcall external 'CTD20.Dll'; function CTDSpeedRead(wBsn, wAxis: Word; var pdObjSpeed: Double): LongBool; stdcall external 'CTD20.Dll'; //----------------- エラー内容取得用 ----------------------------------------------- function CTDGetErrorStr(ErrorCoad: Dword): string; implementation function CTDGetErrorStr(ErrorCoad: Dword): string; begin case ErrorCoad of CTD_SUCCESS : Result := '異状なし(正常終了)。'; CTD_ERR_NO_DEVICE : Result := '使用可能なデバイスがありません。'; CTD_ERR_IN_USE : Result := '指定のデバイスは使用中です。'; CTD_ERR_INVALID_BSN : Result := '無効なボードセレクトナンバーです' + #13#10 + 'デバイスがバス上にないか' + #13#10 + '使用宣言されていません。'; CTD_ERR_INVALID_PORT : Result := '不正なポートを要求した。'; CTD_ERR_PARAMETER : Result := '引数の値が範囲外です。'; CTD_ERR_INVALID_AXIS : Result := '無効な制御軸を要求した。'; CTD_ERR_TRANS : Result := '送信時の通信エラーです。'; CTD_ERR_RECEIVE : Result := '受信時の通信エラーです。'; CTD_ERR_USB_REMOVE : Result := 'デバイスが取り外されました。'; CTD_ERR_WRAPDLL : Result := 'ラッパー関数内エラー。;' else Result := 'その他のエラー'; end; end; end.