エクセルでステッピングモーター位置決め
ARDUINO CNC-SHILDの使い方とパソコンからARDUINOにシリアル通信でGコードを送信するGRBLの使い方について投稿しました。また、パソコンからエクセルVBAを使って、ARDUINOにシリアル通信する方法についても投稿しました。
これら投稿の内容をベースに、エクセルからARDUINOにGコード送信し、ステッピングモーターの位置決めを行ってみます。
実際にスライドテーブルがあると良いのですが、準備が大変なので、モーターの角度で簡易的に判断したいと思います。
エクセルの準備(関連投稿記事)
既に投稿した下表の記事の通り、配線・設定とエクセルVBAでシリアル通信できるようにAPI設定します。
【関連投稿記事】
番号 | 関連投稿 |
1 | ARDUINOでCNCシールドを使う |
2 | ARDUINOでのGRBLの使い方 |
3 | エクセルVBAでARDUINOにシリアル通信する |
エクセルプログラム概要
次の図は今回作成したプログラムのエクセルシートです。
シート上にコマンドボタンを3つ配置し、①原点復帰,②増量移動,③連続運転(絶対位置指定)の3つの動作を実行します。
基本的には過去の投稿記事に書いた内容をエクセルVBAで連続的に位置決め出来る様にしたものです。
図の通り、増量指定移動では、X軸(3列),Y軸(4列)に現在位置に対する増加量(単位:mm)を指定し移動します。“増量移動”ボタンをクリックすると、Gコード(G91X**Y**)を生成しARDUINO側にシリアル送信します。引き続き、” ? ” コマンドでARDUINO側ステータスを確認し、“Idle” (停止)状態データ受信後、Gコード(G92X0Y0)を送信し動作原点を初期化します。
同様に連続運転では、X軸(3列),Y軸(4列)に 指定した絶対位置に対応する Gコード(G90X**Y**)を生成し、ARDUINO側に送信します。連続運転では最大10ヶ所の位置を登録することが出来、1~10の順番(2列)に位置決めを行います。位置指定が無い場合は処理を中断します。
シート4列には送信したGコード,5列には受信した “Idle” (停止)状態データ を表示します。今回、実際にはスライドテーブルがありませんので、ステッピングモーターの回転角度で適切に処理されていることを確認する為に、指定移動量を40(mm/回転)として回転角度に変換表示しています。
ステッピングモーター位置決め動画
動画内の矢印(↑)が上向き状態を0度として、右回りに回転すると角度が増加します。
動画は次エクセルシートの通り、位置決めをしています。
指定位置に対して、回転方向・量は決まるので、必ずしも動画内の表示角度に対して最短方向・量にはなりません。
プログラム
エクセルVBAのプログラムを掲載します。
Option Explicit Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long) '原点復帰 Private Sub CommandButton3_Click() Dim res Dim msg Dim G_CD As String Dim sht sht = ActiveSheet.Name Worksheets(sht).Range("E1:F1").ClearContents G_CD = "$H" Worksheets(sht).Cells(1, 5).Value = G_CD res = StartSerialComm(G_CD, "COM4") Do Sleep (500) DoEvents res = StartSerialComm("?", "COM4") If InStr(res, "Idle") Then Exit Do End If Loop res = Replace(Replace(Replace(res, "ok", ""), ")", ""), "(", "") Worksheets(sht).Cells(1, 6).Value = res msg = MsgBox("原点復帰を終了しました。" + vbCrLf + vbCrLf + "(" + res + ")", vbOKOnly) End Sub '増量移動 Private Sub CommandButton1_Click() Dim sht Dim res Dim pos_X, pos_Y Dim G_CD As String sht = ActiveSheet.Name Worksheets(sht).Range("E5:F5").ClearContents pos_X = Trim(Worksheets(sht).Cells(5, 3).Value) pos_Y = Trim(Worksheets(sht).Cells(5, 4).Value) If pos_X = "" & pos_Y = "" Then Exit Sub If pos_X = "" Then pos_X = "0" If pos_Y = "" Then pos_Y = "0" G_CD = "G91G0X" & pos_X & "Y" & pos_Y Worksheets(sht).Cells(5, 5).Value = G_CD res = StartSerialComm(G_CD, "COM4") Do Sleep (500) DoEvents res = StartSerialComm("?", "COM4") If InStr(res, "Idle") Then Exit Do End If Loop res = StartSerialComm("G90G92X0Y0", "COM4") Do Sleep (200) DoEvents res = StartSerialComm("?", "COM4") If InStr(res, "Idle") Then Exit Do End If Loop Worksheets(sht).Cells(5, 6).Value = res MsgBox "増量運転完了", vbOKOnly End Sub '連続運転 Private Sub CommandButton2_Click() Dim sht Dim res Dim pos_X, pos_Y Dim G_CD As String Dim ln_CNT sht = ActiveSheet.Name Worksheets(sht).Range("E8:F2000").ClearContents ln_CNT = 0 Do pos_X = Trim(Worksheets(sht).Cells(8 + ln_CNT, 3).Value) pos_Y = Trim(Worksheets(sht).Cells(8 + ln_CNT, 4).Value) If pos_X = "" Or pos_Y = "" Then Exit Do G_CD = "G90G0X" & pos_X & "Y" & pos_Y Worksheets(sht).Cells(8 + ln_CNT, 5).Value = G_CD res = StartSerialComm(G_CD, "COM4") Do Sleep (500) DoEvents res = StartSerialComm("?", "COM4") If InStr(res, "Idle") Then Exit Do End If Loop Worksheets(sht).Cells(8 + ln_CNT, 6).Value = res DoEvents ln_CNT = ln_CNT + 1 If ln_CNT >= 10 Then Exit Do Loop MsgBox "連続運転完了(" & Trim(Str(ln_CNT)) & ")", vbOKOnly End Sub
シリアル送信(RS-232C)API,関数定義部のプログラムです。VBAの標準モジュールに追加します。
Option Explicit Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _ (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, _ ByVal lpSecurityAttributes As Long, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long) As Long Private Declare Sub CloseHandle Lib "kernel32" (ByVal hObject As Long) Private Declare Sub ReadFile Lib "kernel32" _ (ByVal hFile As Long, _ ByVal lpBuffer As String, _ ByVal nNumberOfBytesToRead As Long, _ lpNumberOfBytesRead As Long, _ ByVal lpOverlapped As Long) Private Declare Sub WriteFile Lib "kernel32" _ (ByVal hFile As Long, _ ByVal lpBuffer As String, _ ByVal nNumberOfBytesToWrite As Long, _ lpNumberOfBytesWritten As Long, _ ByVal lpOverlapped As Long) Private Declare Function SetCommState Lib "kernel32" (ByVal hFile As Long, ByRef lpDCB As DCB) As Long Private Declare Sub SetCommTimeouts Lib "kernel32" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) 'SetCommState Private Type DCB DCBlength As Long BaudRate As Long Fields As Long wReserved As Integer XonLim As Integer XoffLim As Integer ByteSize As Byte Parity As Byte StopBits As Byte XonChar As Byte XoffChar As Byte ErrorChar As Byte EofChar As Byte EvtChar As Byte wReserved1 As Integer End Type 'SetCommTimeouts Private Type COMMTIMEOUTS ReadIntervalTimeout As Long ReadTotalTimeoutMultiplier As Long ReadTotalTimeoutConstant As Long WriteTotalTimeoutMultiplier As Long WriteTotalTimeoutConstant As Long End Type 'CreateFileパラメータ用定数 Private Const GENERIC_READ = (&H80000000) Private Const GENERIC_WRITE = (&H40000000) Private Const OPEN_EXISTING = 3 Public Function StartSerialComm(str_TX As String, com_port As String) Dim comPort As String Dim hFile As Long Dim cs As DCB 'CommState Dim ct As COMMTIMEOUTS 'CommTimeouts Dim length As Long Dim buf As String comPort = com_port 'COMポートオープン hFile = CreateFile(comPort, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0) If hFile = -1 Then StartSerialComm = "ERR_COM_OPEN" Exit Function End If 'RS232C通信設定 cs.BaudRate = 9600 cs.ByteSize = 8 cs.Parity = 0 cs.StopBits = 0 cs.Fields = &H3001 SetCommState hFile, cs 'RS232Cタイムアウト設定 ct.ReadIntervalTimeout = 1000 ct.ReadTotalTimeoutMultiplier = 1 ct.ReadTotalTimeoutConstant = 500 ct.WriteTotalTimeoutMultiplier = 1 ct.WriteTotalTimeoutConstant = 500 SetCommTimeouts hFile, ct '送信 buf = str_TX + Chr(10) WriteFile hFile, buf, Len(buf), length, 0 '受信 buf = String(1024, vbNullChar) ReadFile hFile, buf, Len(buf), length, 0 'COMポートクローズ CloseHandle hFile '受信データのパース buf = Replace(buf, vbNullChar, "") buf = Replace(buf, Chr(10), "") buf = Replace(buf, Chr(13), "") StartSerialComm = buf End Function
まとめ
位置決めと計測などを組み合わせて、実際に活用することも検討していきたいと思っています。