Dobot Magician UART 2020/03/12

■Dobot Magician UART 接続のDelphi サンプル(残骸)です。
 Dobot 本体のインターフェイスコネクタ (MIL 10P)に UART 信号があります。
 Windows の場合、これを使用しなくても、USB 経由の仮想 COM ポートを接続先として使用できまます。
 ※仮想 COM ポートは、Dobot Studio をインストールすると作成されます。

 バイト列で送信、受信を行います。DobotDLL が無くても動きます。
 Arduino でも同じ感じで通信が行えます。Wi-Fi アダプタを使った UDP 通信も同じ内容になります。
 
 シリアル通信は、APDComport コンポーネントを使っています。受信がイベント取得になるので、分かりにくいコードになっています。
 実装では、シンプルな Uni232C コンポーネントを使用しています。Windows 64bit 環境、Android 環境でも使用できます。

 以下、残骸ですが、とっかかりの参考にはなると思います。


unit Unit4;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, OoMisc, AdPort, Vcl.StdCtrls;

type
  TIOFunction = (
    IOFunctionDummy, //Do not config function
    IOFunctionPWM,   //PWM Output
    IOFunctionDO,    //IO Output
    IOFunctionDI,    //IO Output
    IOFunctionADC    //AD Input
    );

type
  TForm4 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    ApdComPort1: TApdComPort;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Button8: TButton;
    Button9: TButton;
    Button10: TButton;
    Button11: TButton;
    Button12: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure ApdComPort1TriggerAvail(CP: TObject; Count: Word);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure Button8Click(Sender: TObject);
    procedure Button9Click(Sender: TObject);
    procedure Button10Click(Sender: TObject);
    procedure Button11Click(Sender: TObject);
    procedure Button12Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    resBuf : TBytes;
    resEnd : boolean;
    resBegin : boolean;
    resIndex : integer;
    resCount : integer;
    procedure initResParams;
    function WaitResEnd(timeOut: Cardinal): boolean;
    function GetQueuedCmdCurrentIndex(var queuedCmdCurrentIndex: Uint64):boolean;
    function GetPose(var x, y, z, r: single; var a0, a1, a2, a3: single): boolean;
    function SetEndEffectorSuctionCup(ctrl, suck: Byte):boolean;
    function GetEndEffectorSuctionCup(var isCtrlEnable: Byte; var isSucked: Byte): boolean;
    function ClearAllAlarmsState: boolean;
    function SetIOMultiplexing(ioAddress: Byte; ioFunction: TIOFunction): boolean;
    function SetIODO(ioAddress: Byte; ioLevel: Byte): boolean;
    function GetIODO(ioAddress: Byte; var ioLevel: Byte): boolean;
    function GetIODI(ioAddress: Byte; var ioValue: Byte):boolean;
    function SetQueuedCmdForceStopExec: boolean;

  end;
var
  Form4: TForm4;

implementation

{$R *.dfm}

// 強制出力停止
// 通信は出来なくなる。
// Dobot本体のリセット処理が必要。その後、再接続処理が必要。
// 使わないほうが良い
function TForm4.SetQueuedCmdForceStopExec: boolean;
var
  B : TBytes;
begin
  result := false;
  if ApdComport1.Open then begin
    SetLength(B, 6);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 0; // len= 2 + Payload Len;
    B[3] := 242;   // id;
    B[4] := 1;     // ctrl r/w($01) = W, isQueued($02) = false;
    // チェックサム
    B[5] := $0D;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 6);
    waitResEnd(500);
    result := (Length(resBuf) = 6) and (resBuf[3] = 242);
  end;
end;

function TForm4.GetIODI(ioAddress: Byte; var ioValue: Byte):boolean;
// GetIODI 入力状態を取得
var
  checkSum : Byte;
  i : integer;
  B : TBytes;
begin
  result := False;
  if ApdComport1.Open then begin
    SetLength(B, 8);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 2; // len= 2 + Payload Len;

    B[3] := 133;   // id;
    B[4] := 0;     // ctrl r/w = r, isQueued = False;
    B[5] := ioAddress;
    B[6] := 0;
    // チェックサム
    checkSum := 0;
    for i := 3 to 6 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[7] := checkSum;

    initResParams;
    ApdComPort1.PutBlock(B[0], 8);
    waitResEnd(500);

    result := (Length(resBuf) = 8) and (resBuf[3] = 133) and (resBuf[5] = ioAddress);
    if result then
      ioValue := resBuf[6];
  end;
end;

function TForm4.GetIODO(ioAddress: Byte; var ioLevel: Byte): boolean;
// 出力状態を取得
var
  checkSum : Byte;
  i : integer;
  B : TBytes;
begin
  result := False;
  if ApdComport1.Open then begin
    SetLength(B, 8);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 2; // len= 2 + Payload Len;

    B[3] := 131;   // id;
    B[4] := 0;     // ctrl r/w = r, isQueued = False;
    B[5] := ioAddress;
    B[6] := 0;
    // チェックサム
    checkSum := 0;
    for i := 3 to 6 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[7] := checkSum;

    initResParams;
    ApdComPort1.PutBlock(B[0], 8);
    waitResEnd(500);

    result := (Length(resBuf) = 8) and (resBuf[3] = 131) and (resBuf[5] = ioAddress);
    if result then
      ioLevel := resBuf[6];
  end;
end;

function TForm4.SetIODO(ioAddress: Byte; ioLevel: Byte): boolean;
// 出力
var
  checkSum : Byte;
  i : integer;
  B : TBytes;
  s : string;
begin
  result := False;
  if ApdComport1.Open then begin
    SetLength(B, 8);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 2; // len= 2 + Payload Len;

    B[3] := 131;   // id;
    B[4] := 1;     // ctrl r/w = W, isQueued = False;
    B[5] := ioAddress;  // EIO Num(1..20)
    B[6] := ioLevel;    // Level output 0-Low level 1-High level

    // チェックサム
    checkSum := 0;
    for i := 3 to 6 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[7] := checkSum;

    initResParams;
    ApdComPort1.PutBlock(B[0], 8);

    waitResEnd(500);
    s := '';
    for i := 0 to Length(resBuf) - 1 do
      s := s + IntToHex(resBuf[i], 2) + '';
    Memo1.Lines.Add(s);

    result := (Length(resBuf) = 8) and (resBuf[3] = 131);

  end;
end;

function TForm4.SetIOMultiplexing(ioAddress: Byte; ioFunction: TIOFunction): boolean;
// 多重入出力を設定
var
  checkSum : Byte;
  i : integer;
  B : TBytes;
begin
  result := False;
  if ApdComport1.Open then begin
    SetLength(B, 8);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 2; // len= 2 + Payload Len;

    B[3] := 130;    // id;
    B[4] := 1;      // ctrl r/w = W, isQueued = False;
    B[5] := ioAddress;       // EIO Num(1..20)
    B[6] := Ord(ioFunction); // TIOFunction,
    // チェックサム
    checkSum := 0;
    for i := 3 to 6 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[7] := checkSum;

    initResParams;
    ApdComPort1.PutBlock(B[0], 8);

    waitResEnd(500);
    result := (Length(resBuf) = 8) and (resBuf[3] = 130);
  end;
end;

function TForm4.ClearAllAlarmsState: boolean;
// アラームクリア
var
  B : TBytes;
begin
  result := false;
  if ApdComport1.Open then begin
    SetLength(B, 6);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 0; // len= 2 + Payload Len;
    B[3] := 20;    // id;
    B[4] := 1;     // ctrl r/w($01) = W, isQueued($02) = false;
    // チェックサム
    B[5] := $EB;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 6);
    waitResEnd(500);
    result := (Length(resBuf) = 6) and (resBuf[3] = 20);
  end;
end;

function TForm4.GetEndEffectorSuctionCup(var isCtrlEnable: Byte; var isSucked: Byte): boolean;
// 吸引カップの状態を取得
var
  B : TBytes;
begin
  result := False;
  if ApdComport1.Open then begin
    SetLength(B, 6);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 0; // len= 2 + Payload Len;
    B[3] := 62;    // id;
    B[4] := 0;     // ctrl r/w($01) = R, isQueued($02) = false;
    B[5] := $C2;   // checkSum;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 6);
    waitResEnd(500);

    result := (Length(resBuf) = 8) and (resBuf[3] = 62);
    if result then begin
      isCtrlEnable := resBuf[5];
      isSucked := resBuf[6];
    end;
  end;
end;

function TForm4.SetEndEffectorSuctionCup(ctrl, suck: Byte):boolean;
// 吸引カップ ON/OFF
var
  B : TBytes;
  i : integer;
  checkSum : Byte;
begin
  result := False;
  if ApdComport1.Open then begin
    SetLength(B, 8);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 2; // len= 2 + Payload Len;
    B[3] := 62;    // id;
    B[4] := 3;     // ctrl r/w($01) = W, isQueued($02) = True;
    B[5] := ctrl;     //isCtrlEnabled
    B[6] := suck;    //issucked

    // チェックサム
    checkSum := 0;
    for i := 3 to 6 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[7] := checkSum;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 8);

    waitResEnd(500);
    result := (Length(resBuf) = 14) and (resBuf[3] = 62);
  end;
end;

function TForm4.GetPose(var x, y, z, r: single; var a0, a1, a2, a3: single): boolean;
// GetPose 現在値を取得
var
  i : integer;
  B : TBytes;
begin
  result := false;
  if ApdComport1.Open then begin
    SetLength(B, 6);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 0; // len= 2 + Payload Len;

    B[3] := 10;   // id;
    B[4] := 0;    // ctrl r/w = R, isQueued = False;
    // チェックサム
    B[5] := $F6;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 6);
    waitResEnd(2000); // Homing 時は2秒程度必要

    if (Length(resBuf) = 38) and (resBuf[3] = 10) then begin
      for i := 0 to 3 do begin
        x.Bytes[i]  := resBuf[5 + i];
        y.Bytes[i]  := resBuf[9 + i];
        z.Bytes[i]  := resBuf[13 + i];
        r.Bytes[i]  := resBuf[17 + i];
        a0.Bytes[i] := resBuf[21 + i];
        a1.Bytes[i] := resBuf[25 + i];
        a2.Bytes[i] := resBuf[29 + i];
        a3.Bytes[i] := resBuf[33 + i];
      end;
      result := true;
    end;
  end;
end;

function TForm4.GetQueuedCmdCurrentIndex(var queuedCmdCurrentIndex: Uint64): boolean;
// コマンドキューの現在の位置
var
  B : TBytes;
begin
  result := False;
  if ApdComport1.Open then begin
    SetLength(B, 6);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 0; // len= 2 + Payload Len;
    B[3] := 246;   // id;
    B[4] := 0;     // ctrl r/w = R, isQueued = False;
    // チェックサム
    B[5] := $A;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 6);

    waitResEnd(2000); // Homing 時は2秒程度必要
    if (Length(resBuf) = 14) and (resBuf[3] = 246) then begin
      queuedCmdCurrentIndex :=
         resBuf[5+0] or
        (resBuf[5+1] shl 8)  or
        (resBuf[5+2] shl 16) or
        (resBuf[5+3] shl 24) or
        (UInt64(resBuf[5+4]) shl 32) or
        (UInt64(resBuf[5+5]) shl 40) or
        (UInt64(resBuf[5+6]) shl 48) or
        (UInt64(resBuf[5+7]) shl 56);
      result := true;
    end;
  end;
end;

function TForm4.WaitResEnd(timeOut: Cardinal): boolean;
// Dobot 返信が終わるまで待つ
var
  Ticks : Cardinal;
begin
  result := false;
  Ticks := GetTickCount;
  while not resEnd do begin
    Sleep(10);
    Application.ProcessMessages;
    if resEnd then begin
      Sleep(10);
      result := True;
      break;
    end
    else if (GetTickCount - Ticks) > timeOut then break;
  end;
end;

procedure TForm4.InitResParams;
// 受信待ちの変数を初期化
begin
  SetLength(resBuf, 0);
  resEnd := False;
  resBegin := False;
  resIndex := 0;
  resCount := 0;
end;

procedure TForm4.ApdComPort1TriggerAvail(CP: TObject; Count: Word);
// Dobot からの返信
var
  B : TBytes;
  i : integer;
begin
  if Count > 0 then begin
    SetLength(B, Count);
    ZeroMemory(B, Count);
    ApdComPort1.GetBlock(B[0], Count);

    for i := 0 to Count -1 do begin
      if not resBegin and (B[i] = $AA) then begin
        resBegin := True;
        resIndex := 0;
        SetLength(resBuf, 3);
      end
      else if resBegin and (resIndex = 2) then begin
        SetLength(resBuf, B[i] + 4);
        resCount := B[i] + 4;
      end;

      if Length(resBuf) > resIndex then
        resBuf[resIndex] := B[i];

      Inc(resIndex);
      if resIndex = resCount then begin
        resEnd := True;
        break;
      end;
    end;
  end;
end;

procedure TForm4.Button10Click(Sender: TObject);
// SetIOMultiplexing
var
  ioLevel : Byte;
begin
  if ApdComport1.Open then begin
    SetIOMultiplexing(18, TIOFunction.IOFunctionDO);
    GetIODO(18, ioLevel);
    // 出力値を反転
    ioLevel := (ioLevel + 1) mod 2;
    SetIODO(18, ioLevel);
  end;
end;

procedure TForm4.Button11Click(Sender: TObject);
// GetIODI
var
  value: Byte;
begin
  SetIOMultiplexing(20, TIOFunction.IOFunctionDI);
  GetIODI(20, value);
  Memo1.Lines.Add('Value=' + value.ToString);
end;

procedure TForm4.Button12Click(Sender: TObject);
// ArcCmd (未検証)
var
  checkSum : Byte;
  i : integer;
  B : TBytes;
  queuedCmdIndex : Uint64;
  executedCmdIndex : Uint64;
  x, y, z, r, a0, a1, a2, a3 : single;
  arcx, arcy, arcz, arcr, tox, toy, toz, tor : single;
begin
  arcx := 200;
  arcy := 0;
  arcz := 70;
  arcr := 0;

  tox := 230;
  toy := -100;
  toz := 70;
  tor := 0;

  if ApdComport1.Open then begin
    SetLength(B, 38);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 32; // len= 2 + Payload Len;

    B[3] := 101;     // id;
    B[4] := 3;      // ctrl r/w = W, isQueued = True;

    // X
    for i := 0 to 3 do B[5 + i] := arcx.Bytes[i];
    // Y
    for i := 0 to 3 do B[9 + i] := arcy.Bytes[i];
    // Z
    for i := 0 to 3 do B[13 + i] := arcz.Bytes[i];
    // R
    for i := 0 to 3 do B[17 + i] := arcr.Bytes[i];

    // X
    for i := 0 to 3 do B[21 + i] := tox.Bytes[i];
    // Y
    for i := 0 to 3 do B[25 + i] := toy.Bytes[i];
    // Z
    for i := 0 to 3 do B[29 + i] := toz.Bytes[i];
    // R
    for i := 0 to 3 do B[33 + i] := tor.Bytes[i];


    // チェックサム
    checkSum := 0;
    for i := 3 to 36 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[37] := checkSum;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 38);
    waitResEnd(500);
    if (Length(resBuf) >= 14) and (resBuf[3] = 101) then begin
      queuedCmdIndex :=
         resBuf[5+0] or
        (resBuf[5+1] shl 8)  or
        (resBuf[5+2] shl 16) or
        (resBuf[5+3] shl 24) or
        (UInt64(resBuf[5+4]) shl 32) or
        (UInt64(resBuf[5+5]) shl 40) or
        (UInt64(resBuf[5+6]) shl 48) or
        (UInt64(resBuf[5+7]) shl 56);
      executedCmdIndex := 0;
      while (executedCmdIndex < queuedCmdIndex) do begin
        if getPose(x, y, z, r, a0, a1, a2, a3) then begin
          Memo1.Lines.Add(Format('X= %.2f, Y= %.2f, Z= %.2f, R= %.2f', [x, y, z, r]));
          GetQueuedCmdCurrentIndex(executedCmdIndex);
        end;
      end;
      if getPose(x, y, z, r, a0, a1, a2, a3) then
        Memo1.Lines.Add(Format('X= %.2f, Y= %.2f, Z= %.2f, R= %.2f', [x, y, z, r]));
      Memo1.Lines.Add('>>>> ArcCmd Finished <<<<');
    end;
  end;


end;

procedure TForm4.Button1Click(Sender: TObject);
// Dobot Open
begin
  ApdComport1.ComNumber := 29;
  ApdComport1.Baud := 115200;
  ApdComport1.Open := True;
end;

procedure TForm4.Button2Click(Sender: TObject);
// Dobot Close
begin
  ApdComport1.Open := False;
end;

procedure TForm4.Button3Click(Sender: TObject);
// HomeCmd ホーミング
var
  checkSum : Byte;
  i : integer;
  B : TBytes;
  queuedCmdIndex : Uint64;
  executedCmdIndex : Uint64;
  x, y, z, r, a0, a1, a2, a3 : single;
begin
  if ApdComport1.Open then begin
    SetLength(B, 10);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 4; // len= 2 + Payload Len;

    B[3] := 31;   // id;
    B[4] := 3;    // ctrl r/w = W, isQueued = True;
    // ダミー(4バイト)
    for i := 0 to 3 do B[5 + i] := 0;

    // チェックサム
    checkSum := 0;
    for i := 3 to 8 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[9] := checkSum;
    initResParams;
    ApdComPort1.PutBlock(B[0], 10);

    waitResEnd(500);
    if (Length(resBuf) >= 14) and (resBuf[3] = 31) then begin
      queuedCmdIndex :=
         resBuf[5+0] or
        (resBuf[5+1] shl 8)  or
        (resBuf[5+2] shl 16) or
        (resBuf[5+3] shl 24) or
        (UInt64(resBuf[5+4]) shl 32) or
        (UInt64(resBuf[5+5]) shl 40) or
        (UInt64(resBuf[5+6]) shl 48) or
        (UInt64(resBuf[5+7]) shl 56);
      executedCmdIndex := 0;
      while (executedCmdIndex < queuedCmdIndex) do begin
        getPose(x, y, z, r, a0, a1, a2, a3);
        Memo1.Lines.Add(Format('X= %.2f, Y= %.2f, Z= %.2f, R= %.2f', [x, y, z, r]));
        GetQueuedCmdCurrentIndex(executedCmdIndex);
      end;
      getPose(x, y, z, r, a0, a1, a2, a3);
      Memo1.Lines.Add(Format('X= %.2f, Y= %.2f, Z= %.2f, R= %.2f', [x, y, z, r]));
      Memo1.Lines.Add('>>>> Homing Finished <<<<');
    end;
  end;
end;

procedure TForm4.Button4Click(Sender: TObject);
// PTPCmd 2点間直線移動
var
  checkSum : Byte;
  i : integer;
  B : TBytes;
  queuedCmdIndex : Uint64;
  executedCmdIndex : Uint64;
  x, y, z, r, a0, a1, a2, a3 : single;
begin
  x := 230;
  y := 0;
  z := 70;
  r := 0;

  if ApdComport1.Open then begin
    SetLength(B, 23);
    B[0] := $AA;
    B[1] := $AA;
    B[2] := 2 + 17; // len= 2 + Payload Len;

    B[3] := 84;     // id;
    B[4] := 3;      // ctrl r/w = W, isQueued = True;
    B[5] := 2;      // PTPMode 2= MOVL_XYZ
    // X
    for i := 0 to 3 do B[6 + i] := x.Bytes[i];
    // Y
    for i := 0 to 3 do B[10 + i] := y.Bytes[i];
    // Z
    for i := 0 to 3 do B[14 + i] := z.Bytes[i];
    // R
    for i := 0 to 3 do B[18 + i] := r.Bytes[i];

    // チェックサム
    checkSum := 0;
    for i := 3 to 21 do checkSum := checkSum + B[i];
    checkSum := $100 - checkSum;
    B[22] := checkSum;

    InitResParams;
    ApdComPort1.PutBlock(B[0], 23);
    waitResEnd(500);
    if (Length(resBuf) >= 14) and (resBuf[3] = 84) then begin
      queuedCmdIndex :=
         resBuf[5+0] or
        (resBuf[5+1] shl 8)  or
        (resBuf[5+2] shl 16) or
        (resBuf[5+3] shl 24) or
        (UInt64(resBuf[5+4]) shl 32) or
        (UInt64(resBuf[5+5]) shl 40) or
        (UInt64(resBuf[5+6]) shl 48) or
        (UInt64(resBuf[5+7]) shl 56);
      executedCmdIndex := 0;
      while (executedCmdIndex < queuedCmdIndex) do begin
        if getPose(x, y, z, r, a0, a1, a2, a3) then begin
          Memo1.Lines.Add(Format('X= %.2f, Y= %.2f, Z= %.2f, R= %.2f', [x, y, z, r]));
          GetQueuedCmdCurrentIndex(executedCmdIndex);
        end;
      end;
      if getPose(x, y, z, r, a0, a1, a2, a3) then
        Memo1.Lines.Add(Format('X= %.2f, Y= %.2f, Z= %.2f, R= %.2f', [x, y, z, r]));
      Memo1.Lines.Add('>>>> PTPcmd Finished <<<<');
    end;
  end;
end;

procedure TForm4.Button5Click(Sender: TObject);
// GetPose
var
  x, y, z, r : single;
  a0, a1, a2, a3 : single;
begin
  if GetPose(x, y, z, r, a0, a1, a2, a3) then begin
    Memo1.Lines.Add(Format('X= %.2f, Y= %.2f, Z= %.2f, R= %.2f', [x, y, z, r]));
    Memo1.Lines.Add(Format('A0= %.2f, A1= %.2f, A2= %.2f, A3= %.2f', [a0, a1, a2, a3]));
  end;
end;

procedure TForm4.Button6Click(Sender: TObject);
//  GetQueuedCmdCurrentIndex
var
  queuedCmdCurrentIndex : Uint64;
begin
  queuedCmdCurrentIndex := 0;
  GetQueuedCmdCurrentIndex(queuedCmdCurrentIndex);
  Memo1.Lines.Add('CurrentIndex=' + queuedCmdCurrentIndex.ToString);
end;

procedure TForm4.Button7Click(Sender: TObject);
// Clear All Alarms State
begin
  ClearAllAlarmsState;
end;

procedure TForm4.Button8Click(Sender: TObject);
// SetEndEffectorSuctionCup
var
  ctrl, suck : Byte;
begin
  GetEndEffectorSuctionCup(ctrl, suck);
  suck := (suck + 1) mod 2;
  SetEndEffectorSuctionCup(1, suck);
end;

procedure TForm4.Button9Click(Sender: TObject);
// SetQueuedCmdForceStopExec,
begin
  if SetQueuedCmdForceStopExec then begin
    ApdComport1.Open := False;
    ShowMessage('Dobot をリセットしてください.' + #13 + 'リセット完了後、再接続してください.');
  end;
end;

end.