二次開発用のSDKはC++、C#、Pythonが準備されている
SDKで準備されている関数はマニュアルに記載されているが、モジュール自体はDUCOより入手する必要がある(代理店にお願いすれば入手可能)。
コントローラーのファームフェアのバージョンとSDKのバージョンが適合している必要があるため場合によってはファームウェアの更新が必要になる。

本SDKではRPC(Apache Thrift)を使用してコントローラーへ動作要求を実施、結果を受信している。接続するポートは7003
SDK(python)の構成
フォルダ内DucoCobotApi_py内は以下のファイル、フォルダが存在する。
- フォルダ内データ
- __init__.py … 中身は無し
- DucoCobot.py … DUCOが準備した関数が記述されているファイル。基本は変更はせず、自作のクラス、関数から本モジュールを呼び出し使用。
- demo.py … サンプルプログラム。ロボットコントローラーへの接続し、ロボット電源ON、イネーブル動作、ジョイント角(movej)動作、軌跡動作を実行するコードが記述されている。
- lib … apache thriftのモジュールファイルが格納されている。
- gen_py … thriftで自動生成されたファイル。変更しない。

pythonサンプルプログラムの実行
以下のコードが記述されたファイルsample.pyをDucoCobot.pyと同じフォルダに保存し、sample.pyを実行すると、ロボットの電源ON、イネーブル化、Movel(現在位置からZ軸+50mm)を行う。
今回動作確認したバージョンはpython 3.11.9、ロボットファームウェア V3.9、SDKバージョンV3.8.3。
ロボットステータス情報の取得は、DucoCobotモジュールの関数getRobotStatus()により取得しているが、TCP/IPでポート2001と接続する方法でも取得可能。
import sys
import time
import threading
import msvcrt
sys.path.append('lib')
from DucoCobot import DucoCobot
from thrift import Thrift
from gen_py.robot.ttypes import StateRobot, StateProgram, OperationMode, TaskState, Op, RealTimeControlData, PointOp, MoveJogTaskParam
class RobotControl:
# 接続するLANポートのIPアドレス
ip='192.168.1.10'
# ポート名は固定
port = 7003
_stopheartthread = False
_robot_status = None
def __init__(self):
pass
# ハートビートスレッドの実行内容
def _hearthread_fun(self):
duco_heartbeat = DucoCobot(self.ip, self.port)
duco_heartbeat.open()
while not self._stopheartthread:
duco_heartbeat.rpc_heartbeat()
time.sleep(1)
duco_heartbeat.stop(True)
duco_heartbeat.close()
# ステータス取得スレッドの実行内容
def _get_status_thread_fun(self):
duco_getstatus = DucoCobot(self.ip, self.port)
duco_getstatus.open()
while not self._stopheartthread:
robot_status = duco_getstatus.getRobotStatus()
if robot_status != None:
self._robot_status = robot_status
time.sleep(0.1)
duco_getstatus.close()
# ロボット動作指令実行関数
def run(self):
thd= threading.Thread(target=self._hearthread_fun)
thd.start()
self._duco_cobot = DucoCobot(self.ip, self.port)
res = self._duco_cobot.open()
if res == 0:
print("Connect Success: DUCOとの接続に成功")
else :
print("Connect Fail: DUCOとの接続に失敗")
return
thd2= threading.Thread(target=self._get_status_thread_fun)
thd2.daemon = True
thd2.start()
print(f"Robot Version: {self._duco_cobot.get_robot_version()}")
res = self._duco_cobot.power_on(True)
if res == TaskState.ST_Finished:
print("Power On Success: 電源投入に成功")
else:
print("Power On Fail: 電源投入に失敗")
return
res = self._duco_cobot.enable(True)
if res == TaskState.ST_Finished:
print("Enable Success: イネーブルに成功")
else:
print("Enable Fail: イネーブルに失敗")
return
print(f"Z座標: {self._robot_status.cartActualPosition[2]:f}")
pose1 = self._duco_cobot.get_tcp_pose()
pose1[2] += 0.05
# 現在の位置からTCPをZ方向に50mm移動 v=0.1 a=1.2
res = self._duco_cobot.movel(pose1, 0.1, 1.2, 0, None, "", "", True)
if res == TaskState.ST_Finished:
print("Movel Success: ロボット動作指令成功")
else:
print("Movel Fail: ロボット動作指令失敗")
time.sleep(0.5)
print(f"Z座標: {self._robot_status.cartActualPosition[2]:f}")
# 何かキー入力すると接続を解除して終了
msvcrt.getch()
self._stopheartthread = True
time.sleep(1)
res = self._duco_cobot.close()
if res == 0:
print("Disconnect Success: DUCOとの切断に成功")
else :
print("Disconnect Fail: DUCOとの切断に失敗")
return
if __name__ == '__main__':
robot = RobotControl()
try:
robot.run()
except Thrift.TException as tx:
print('%s' % tx.message)