代用的なexample

コボッタの基本的使用例とそこで使っている関数の説明

config.yaml の書き方

機能拡張によって名前の方針が少しぶれているところがある。

途中で gRPC 対応にした時に FastAPI(ese774) 利用と gRPC 利用で PORTを分けるために用語を切り分けた。gRPC を読み込んでいる場合は、SERVER_PORT が FASTAPI_PORT に してないとだ正しく機能しない(サーバーが GRPC_PORT と FASTAPI_PORT の二つになる) サーバー起動時に文句を言われる。 これを区別してないサーバー設定サンプルがどこかに残っていることがある。

サーバーを使うだけのユーザーは気にしなくて良い。 デバイスサーバーを立ち上げる管理人は注意する必要がある。

# Server
SERVER_IP: "10.170.10.33"
# SERVER_IP: "10.170.10.38"
FASTAPI_PORT: 8004
GRPC_PORT: 50051
SERVER_LOGGER_NAME: "AanddReaderServer"
# Device
DEVICE_PORT: "COM4"
  • CLIENT_LOGGER_NAME と SERVER_LOGGER_NAME は好きな名前でいい。

  • JOYPAD を使う時は JOYPAD_PORT の設定が必須

  • CAMERA を使う時は CAMERA_IP の設定が必須

コボッタサーバーとコボッタと他のサーバ(joypad)など、 yaml から設定を読むので混乱しないように注意する

# --- cobotta-server
SERVER_IP: "10.170.10.41"
FASTAPI_PORT: 8000
CLIENT_LOGGER_NAME: "cobotta4_client"
SERVER_LOGGER_NAME: "cobotta4_server"
TIMEOUT: 5
LOGGER_LEVEL: "debug"
# --- joypad-server
JOYPAD_PORT: 50051
JOYPAD_LOGGER_NAME: "cobotta4_joypad"
# --- cobotta
COBOTTA_IP: "10.170.10.43"
COBOTTA_CAMERA_IP: None

STOP

停止する

現在発生しているエラーの把握

ほぼ全ての関数は、関数で指定された動作が正しく終了したかどうか? の判定を bool (True/False) で返す。その結果を参照しても しなくても問題ないが、False のときはその動作が正しく終了してない ので、ハンドリングした方が健全であり、エラーの原因を表示した方がいい。

import asyncio
from pathlib import Path
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger

async def main():
    # config はパス情報も含めたほうがトラブルは少ない
    HERE = Path(__file__).parent
    Config.load_yaml(HERE / "config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)

    try:
        # 現在のエラーコード
        code = await client.error_code()
        # 現在のエラー
        description = await client.error_description()
        logger.info(f"cdoe={code}, description={description}")
    except Exception as e:
        print(e)
    assert "result" == "result"
    
if __name__ == "__main__":
    asyncio.run(main())

基本命令 (take_arm)

アーム権限の取得 アーム権限を取得してないと動かすことができない。 これは、本質的にはサーバー側で取得される。

つまり、サーバを複数人で使っているときは注意。

マルチユーザー環境でまだ作り組んでいないので、同時に別端末から 使うときの排他的扱いはバグがある(むしろ「仕様上」つめてないので、 設計上の不備がある)

import asyncio

async def main():
    # ...
    await client.take_arm()

基本命令 (give_arm) 未実装

取得したアーム権限を解放する。 サーバー側でアームを取得しているので、クライアントからは 一度アームを取得してしまえば、熱心にアーム解放をしなくても動くが、 マルチユーザー環境だと take/given は注意する。

import asyncio

async def main():
    # ...
    await client.given_arm()

実は release_arm() というメソッドもある。ないような同じで愛絵違いなだけ。

基本命令 (turn_on_motor)

モーターのon

import asyncio

async def main():
    # ...
    await client.turn_on_motor()

基本命令 (turn_off_motor)

モーターの off。 モーターを off したら色々切れるので割と重要

import asyncio

async def main():
    # ...
    await client.turn_off_motor()

基本命令 (set_coord_type)

メソッドごとではなくて、全体に設定。

import asyncio

async def main():
    # ...
    await client.set_coord_type("J")
    await client.set_coord_type("P")

基本命令 (set_motion_mode)

メソッドごとではなくて、全体に設定。

import asyncio

async def main():
    # ...
    await client.set_motion_mode(MotionMode.PTP)
    await client.set_coord_type(MotionMode.LINE)
    await client.set_coord_type(MotionMode.CIRCLE)
    await client.set_coord_type(MotionMode.SPLINE)

基本命令 (set_speed)

メソッドごとではなくて、全体に設定。

import asyncio

async def main():
    # ...
    await client.set_speed(100)

基本命令 (set_accel)

メソッドごとではなくて、全体に設定。

import asyncio

async def main():
    # ...
    await client.set_accel(100)

基本命令 (set_decel)

メソッドごとではなくて、全体に設定。

import asyncio

async def main():
    # ...
    await client.set_decel(100)

現在のアームの位置

import asyncio
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)

    try:
        # 現在の位置(xyz)情報
        positon = await client.get_current_position()
        # 現在の位置(angle)情報
        angle = await client.get_current_angle()
        
        logger.info(f"{positon}")
        logger.info(f"{angle}")
    except Exception as e:
        print(e)
    assert "result" == "result"
    # send_command("unknown")  # これはエラーになる

動作に対してエラー判定する

大抵のロボット系関数は戻り値として動作したか?異常に終わったか?の判定ができる

import asyncio

async def main():
    # ...
    ret = await client.take_arm()
    if not ret:
        # アームが取得できないときにエラーの種類を用事して止める
        error = await client.error_description()
        logger.error(f"take_arm error: {error}")
        sys.exit(1)
        
if __name__ == "__main__":
    asyncio.run(main())

移動コマンド始め、ほぼあらゆるコマンドで成功の可否を取れる

import asyncio

async def main():
    # ...
    # 移動命令
    ret = await client.move('P10')
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)
        
if __name__ == "__main__":
    asyncio.run(main())

アームの移動0 (デンソー形式)

move() では string で デンソーのスクリプト契機っぽい記述もできる。 使用は推奨しない。

import sys
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("../config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    # エラーがある時は rest しないと動かすことができない
    await client.reset_error()

    # アームを動かす前には take_arm をする必要がある
    ret = await client.take_arm()
    if not ret:
        # アームが取得できないときにエラーの種類を用事して止める
        error = await client.error_description()
        logger.error(f"take_arm error: {error}")
        sys.exit(1)

    logger.info("turn_on_motor")
    await client.turn_on_motor()

    client.motion_mode = MotionMode.LINE
   
    # P62 へ移動する
    ret = await client.move("P62+(0,0,10)")
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    # モーションが終わるまで待つ
    await client.wait_for_complete()

アームの移動1 標準的な使い方

ロボット自体が内部で標準で持っている座標を使う

import sys
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("../config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    # エラーがある時は rest しないと動かすことができない
    await client.reset_error()

    # アームを動かす前には take_arm をする必要がある
    ret = await client.take_arm()
    if not ret:
        # アームが取得できないときにエラーの種類を用事して止める
        error = await client.error_description()
        logger.error(f"take_arm error: {error}")
        sys.exit(1)

    logger.info("turn_on_motor")
    await client.turn_on_motor()

    client.motion_mode = MotionMode.LINE
   
    # P62 へ移動する
    ret = await client.move("P62")
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    # モーションが終わるまで待つ
    await client.wait_for_complete()

アームの移動2 (position)

  • xyz 座標(P)

  • angle 座標(J), J1-J6

を与えて移動する

import logging
from pathlib import Path
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    HERE = Path(__file__).parent
    Config.load_yaml(HERE / "../config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # global設定: motion_mode PTP を指定
    client.motion_mode = MotionMode.PTP
    # client.motion_mode = MotionMode.LINE
    # client.motion_mode = MotionMode.CIRCLE
    # client.motion_mode = MotionMode.SPLINE

    # global設定: xyz座標形式(P) で移動する
    await client.set_coord_type("P")
   
    # positon を作る (タプルでもリストでもどちらでもいい)
    pos = (
        -29.0453511306835,
        343.1440808456958,
        115.31284305934872,
        -178.28955954148657,
        -16.619847808793967,
        141.1028536689876,
    )
    # position に移動する
    ret = await client.move(pos)
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    assert ret is not None, "接続失敗"
    await client.wait_for_complete()

アームの移動3 (j2p, p2j)

angle から position 変更してから移動

import logging
from pathlib import Path
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    HERE = Path(__file__).parent
    Config.load_yaml(HERE / "../config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # global設定: PTP を指定
    client.motion_mode = MotionMode.PTP
    # client.motion_mode = MotionMode.LINE
    # client.motion_mode = MotionMode.CIRCLE
    # client.motion_mode = MotionMode.SPLINE

    # global設定: xyz座標形式(P) で移動する
    await client.set_coord_type("P")
   
    # positon を作る (タプルでもリストでもどちらでもいい)
    new_pos = (
        -29.0453511306835,
        343.1440808456958,
        115.31284305934872,
        -178.28955954148657,
        -16.619847808793967,
        141.1028536689876,
    )
    # P --> J 変換
    next_angle = await client.p2j(new_pos)
    
    # 指定の軸だけ 度を変える
    next_angle[4] = next_angle[4] - 15
    
    # J --> P 変換
    next_pos = await client.j2p(next2_angle)
    
    # position に移動する
    ret = await client.move(next_pos)
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    assert ret is not None, "接続失敗"
    await client.wait_for_complete()

アームの移動4 (angle)

指定Angle での move。 位置や角度の微調整をして、座標を作るのも使う

import logging
from pathlib import Path
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    HERE = Path(__file__).parent
    Config.load_yaml(HERE / "../config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # global設定: PTP を指定
    client.motion_mode = MotionMode.PTP
    # client.motion_mode = MotionMode.LINE
    # client.motion_mode = MotionMode.CIRCLE
    # client.motion_mode = MotionMode.SPLINE

    # angle を作る (タブプルでリストでもok)
    target_angle = [
        56.04999367408907,
        35.12319454476854,
        114.33533666988626,
        -4.0077312418009745,
        0,
        -25.962042331415812,
        0.0,
        0.0,
    ]
    # target_angle に移動する
    # angle だと coord_type を J 指定にする
    ret = await client.move(
        pos, 
        coord_type="J",
    )
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    assert ret is not None, "接続失敗"
    await client.wait_for_complete()

アームの移動5 (coord_type)

coord_type 指定での移動

import logging
from pathlib import Path
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    HERE = Path(__file__).parent
    Config.load_yaml(HERE / "../config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # angle を作る (タブプルでリストでもok)
    target_angle = [
        56.04999367408907,
        35.12319454476854,
        114.33533666988626,
        -4.0077312418009745,
        0,
        -25.962042331415812,
        0.0,
        0.0,
    ]
    # target_angle に移動する
    # angle だと coord_type を J 指定にする
    ret = await client.move(
        pos, 
        coord_type="J",
    )
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    assert ret is not None, "接続失敗"
    await client.wait_for_complete()

アームの移動6 (path_blend)

A -> B -> C

と移動する時に、 B で位置保証性を重要視するか? Bで速度を維持するか? その代わりにパスをA-B混ぜて中間点のような一度経由して通るなど path が複数ある時に、そのパス操作の混ぜ方を変更する。 速度だけでも、加減速だけでもなくパス自体に対する影響パラメータ。 メーカーによって言い方が異なるが大抵は同じ意味のパラメータとなる

import logging
from pathlib import Path
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    HERE = Path(__file__).parent
    Config.load_yaml(HERE / "../config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # global設定: PTP を指定
    client.motion_mode = MotionMode.PTP
    # client.motion_mode = MotionMode.LINE
    # client.motion_mode = MotionMode.CIRCLE
    # client.motion_mode = MotionMode.SPLINE

    # target_angle に移動する
    # angle だと coord_type を J 指定にする
    ret = await client.move(
        pos, 
        coord_type="P",
        path_blend="@P",
    )
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    assert ret is not None, "接続失敗"
    await client.wait_for_complete()

アームの移動7 (speed)

スピード

import sys
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("../config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    # エラーがある時は rest しないと動かすことができない
    await client.reset_error()

    # アームを動かす前には take_arm をする必要がある
    ret = await client.take_arm()
    if not ret:
        # アームが取得できないときにエラーの種類を用事して止める
        error = await client.error_description()
        logger.error(f"take_arm error: {error}")
        sys.exit(1)

    logger.info("turn_on_motor")
    await client.turn_on_motor()

    client.motion_mode = MotionMode.LINE
   
    # P62 へ移動する
    ret = await client.move(
        "P62", 
        coord_type="P",
        path_blend="@P",
        speed=100,
    )
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    # モーションが終わるまで待つ
    await client.wait_for_complete()

アームの移動8 (accel/decel)

加減速

import sys
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("../config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    
    # エラーがある時は rest しないと動かすことができない
    await client.reset_error()

    # アームを動かす前には take_arm をする必要がある
    ret = await client.take_arm()
    if not ret:
        # アームが取得できないときにエラーの種類を用事して止める
        error = await client.error_description()
        logger.error(f"take_arm error: {error}")
        sys.exit(1)

    logger.info("turn_on_motor")
    await client.turn_on_motor()

    client.motion_mode = MotionMode.LINE
   
    # P62 へ移動する
    ret = await client.move(
        "P62",
        path_blend="@P",
        coord_type="P",
        speed=100,
        accel=100,
        decel=100,
    )
    if not ret:
        error = await client.error_description()
        logger.error(f"move error: {error}")
        sys.exit(1)

    # モーションが終わるまで待つ
    await client.wait_for_complete()

アームの移動9 (motion_mode)

モーションモード

import asyncio

# from http import client
from pathlib import Path
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)

    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    angle = await client.get_current_angle()
    angle[5] = angle[5] + -40
    new_pos = await client.j2p(angle)
    await client.move(
        new_pos,
        motion_mode=MotionMode.PTP,
        # motion_mode = MotionMode.PTP,
        # motion_mode = MotionMode.LINE,
        # motion_mode = MotionMode.CIRCLE,
        # motion_mode = MotionMode.SPLINE,
        path_blend="@P",
        coord_type="P",
        speed=100,
        accel=100,
        decel=100,
    )

if __name__ == "__main__":
    asyncio.run(main())

アームの移動10 (drive命令)

drive 命令で指定の軸だけ直接回すことができる

from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("config_cobotta3_server2.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # 相対移動 (J6 を -90) 回転
    await client.drive([6, -90], relative=True)

if __name__ == "__main__":
    asyncio.run(main())

アームの移動11 (offset命令)

オフセット移動

from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("config_cobotta3_server2.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # 相対移動 offset x=0, y=0, z= -10, rx=0, ry=0, rz=0)
    await client.move(
        'P62',
        offset=(0, 0, -10, 0, 0, 0)
    )

if __name__ == "__main__":
    asyncio.run(main())

アームの移動12 (ratete)

ある軸座標を中心にして回転運動をする。 もしかして cobotta のみの関数になるかもしれない?

命令の実装(オプション形式など) まだ迷っているので変える可能性がある

# import pytest
import asyncio
import sys
import json

from pathlib import Path
import logging

# httpx のログを WARNING レベル以上にする(INFO を抑制)
logging.getLogger("httpx").setLevel(logging.WARNING)

# import time

from cobotta2 import Config, MotionMode, RobotVarManager
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():

    HERE = Path(__file__).parent
    config_cobotta2 = Config(HERE / "../config_cobotta2.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=config_cobotta2, logger=logger)
    ret = await client.reset_error()
    if ret is None or ret is False:
        assert False, "Cobotta2 Connect Error"
    await client.release_arm()

    await client.turn_on_motor()
    await client.take_arm()

    await client.move(
        "P123",
        path_blend="@E",
        motion_mode=MotionMode.PTP,
        speed=100,
    )
    await client.wait_for_complete()
    
    # (200,-50, 197) を原点として 45 度回転
    await client.rotate("XY", 45, [200, -50, 197])

    ret = await client.get_current_position()
    print(json.dumps(ret, indent=2))


if __name__ == "__main__":
    # asyncio.run(worker_cobotta2())
    asyncio.run(main())

ハンド1 (距離移動)

import asyncio
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger

async def main():
    Config.load_yaml("../config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # 位置 10mm に移動する
    await client.hand(pos=10, speed=100)
    sleep(2)
    # 現在のところ
    # ハンドは client.wait_for_complete() が使えない

if __name__ == "__main__":
    asyncio.run(main())

ハンド2 (力移動、閉じる)

import asyncio
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger

async def main():
    Config.load_yaml("../config_cobotta1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)
    await client.reset_error()
    await client.take_arm()
    await client.turn_on_motor()

    # 6N でターゲットを掴む
    await client.hand(force=6)
    sleep(2)
    # 現在のところ
    # ハンドは client.wait_for_complete() が使えない

if __name__ == "__main__":
    asyncio.run(main())

座標系を変える (work座標 定義)

work 座標系を変える。標準だとロボット座標系がそのまま work 座標系となるが、 たとえば、斜め方向に傾いたxyz座標軸を取り替えた方が、xyz指定で楽な倍がある。 相対的な移動などoffset 座標の取り方が楽になる。

import asyncio
from cobotta2 import Config, CobottaCtrl, MotionMode, RobotVarManager
from x_logger import XLogger


async def main():
    Config.load_yaml("../config_cobotta1.yaml")

    logger = XLogger(log_level="debug", logger_name=Config.CLIENT_LOGGER_NAME)
    cobotta = AsysncCobottaClient(cobotta_ip=Config.COBOTTA_IP, arm_name="Arm", logger=logger)
    await cobotta.reset_error()

    try:
        await cobotta.take_arm()
        await cobotta.turn_on_motor()

        current_pos = await cobotta.get_current_position()
        logger.info(f"current_pos = {current_pos}")

        pos = [
            # 20.259341327288382,
            0.0,
            # 276.59469818653,
            280,
            # 38.52868750215305,
            50.0,
            # 178.72745234477128,
            180.0,
            # 4.521890180915519,
            0.0,
            # -89.24661909122011,
            -90.0,
            261.0,
        ]
        data = await cobotta.get_work(0)
        logger.info(f"get_work {data}")

        logger.info(f"change_work(0)")
        await cobotta.change_work(0)

        logger.info("******")
        logger.info("")
        logger.info(f"set_work {pos}")
        await cobotta.set_work(1, pos)
        logger.info(f"change_work(1)")
        await cobotta.change_work(1)

        data = await cobotta.get_current_position()
        logger.info(f"current_pos = {data}")
        logger.info("")
        logger.info("******")

        logger.info("")
        logger.info(f"change_work(0)")
        await cobotta.change_work(0)
        current_pos = await cobotta.get_current_position()
        logger.info(f"current_pos = {current_pos}")

if __name__ == "__main__":
    asyncio.run(main())
    

コボッタのハードウエアログ取得

import asyncio

async def main():
    # ..
    await client.start_log()
    await client.start_servo_log() 

コボッタのハードウエア側(テーティングペンダント上)のログを取る

内部変数への読み書き1 (get_P)

メソッドを使って、コボッタ内部の指定の P を取得する

import asyncio
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)

    await client.take_arm()

    logger.info("== turn on motor()")
    ret = await client.turn_on_motor()
    assert ret is not None, "接続失敗"

    logger.info("== run test()")
    ret = await client.get_P(61)

    assert "result" == "result"

内部変数への読み書き2 (property)

import asyncio
from cobotta2 import Config, MotionMode
from cobotta2.server import AsyncCobottaClient
from x_logger import XLogger


async def main():
    Config.load_yaml("config_cobotta1.yaml")
    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)

    await client.take_arm()

    logger.info("== turn on motor()")
    ret = await client.turn_on_motor()

    logger.info("== run test()")
    p61 = await client.P61
    logger.info(f"ret = {p61}")


ファイルに保存してある内部変数値 cobotta へ書きこみ

import asyncio
import re
import json
from samples.cobotta2 import Config
from samples.cobotta2 import AsyncCobottaClient
from x_logger.x_logger import XLogger


async def main():
    Config.load_yaml("config_server1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)

    await client.take_arm()
    await client.turn_on_motor()

    start = "P60"
    end = "P105"
    filepath = f"COBOTTA1_{start}_{end}_pos.json"

    # Pの後ろの数字を抽出して整数に変換
    start_num = int(re.findall(r"\d+", start)[0])
    end_num = int(re.findall(r"\d+", end)[0])

    # ファイルから読み込み
    with open(filepath, "r", encoding="utf-8") as f:
        memory_loaded = json.load(f)

    for i in range(start_num, end_num + 1):
        key = f"P{i}"
        value = memory_loaded.get(key)
        if value is not None:
            await client.set_P(i, value)
            logger.info(f"set_P({i}, {value})")
        else:
            print(f"{key} は存在しません")

if __name__ == "__main__":
    asyncio.run(main())

内部変数をファイルへ SAVE する

import asyncio
import time
import re
import json
from datetime import datetime
from cobotta2 import Config
from cobotta2 import AsyncCobottaClient
from x_logger.x_logger import XLogger

async def main():
    Config.load_yaml("config_server1.yaml")

    logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
    client = AsyncCobottaClient(config=Config, logger=logger)

    await client.take_arm()
    await client.turn_on_motor()

    start = "P120"
    end = "P140"

    # Pの後ろの数字を抽出して整数に変換
    start_num = int(re.findall(r"\d+", start)[0])
    end_num = int(re.findall(r"\d+", end)[0])

    memory = {}
    for i in range(start_num, end_num + 1):
        name_pos = await client.get_P(i)
        logger.info(f"P{i}: {name_pos}")
        target = list(name_pos)
        memory[f"P{i}"] = target

    now = datetime.now()
    dt_str = now.strftime("%Y-%m-%d_%H%M")  # 例: '2025-07-17_1632'

    # ファイルに書き込む
    filepath = f"COBOTTA1_{start}_{end}_pos_{dt_str}.json"
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(memory, f, ensure_ascii=True, indent=4)

    filepath = f"COBOTTA1_{start}_{end}_pos.json"
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(memory, f, ensure_ascii=True, indent=4)

    time.sleep(0.1)

if __name__ == "__main__":
    asyncio.run(main())

内部の PacScript 一覧

基本的に特別な場合を除いて、推奨してないが、直接デンソーのスクリプトを使うことができる。 デンソーウェーブのコボッタ形式PacScript 一覧。 コボッタ内にあるものを表示する。

from cobotta2 import Config, CobottaCtrl, MotionMode

Config.load_yaml("config_cobotta1.yaml")

logger = XLogger(log_level="debug", logger_name=Config.CLIENT_LOGGER_NAME)
cobotta = CobottaCtrl(cobotta_ip=Config.COBOTTA_IP, arm_name="Arm", logger=logger)

print(cobotta.get_cobotta_file_names())

内部の PacScriptを run する

基本的に特別な場合を除いて、推奨してないが、直接デンソーのスクリプトを使うことができる。 デンソーウェーブのコボッタ形式PacScript 扱う。 制御クラスのテストに使える。

*) 必ず、local で直接 CobottaCtrl を使うときは、終了時には disconnect する KeyboardInterrupt を含めて異常終了するときは disconnect しておく

from cobotta2 import Config, CobottaCtrl, MotionMode

Config.load_yaml("config_cobotta2.yaml")
logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
cobotta = CobottaCtrl(cobotta_ip=Config.COBOTTA_IP, arm_name="Arm", logger=logger)

try:
    cobotta.reset_error()
    
    cobotta.turn_on_motor()
    cobotta.release_arm()
    
    name = "Pro1.pcs"  # 拡張子はあってもなくてもいい

    # take_script() とは排他的なので注意
    cobotta.take_script(name)
    cobotta.run_script()
    cobotta.wait_for_complete()

except KeyboardInterrupt as e:
    logger.error(e)
except Exception as e:
    loggger.error(e)
finally:
    cobotta.disconnect()

内部の PacScript を Load (Upload)

基本的に特別な場合を除いて、推奨してないが、直接デンソーのスクリプトを使うことができる。 デンソーウェーブのコボッタ形式PacScript 扱う。 制御クラスのテストに使える。

from cobotta2 import Config, CobottaCtrl, MotionMode

Config.load_yaml("config_cobotta2.yaml")

logger = XLogger(log_level="info", logger_name=Config.CLIENT_LOGGER_NAME)
cobotta = CobottaCtrl(cobotta_ip=Config.COBOTTA_IP, arm_name="Arm", logger=logger)

file_content = """
Sub Main 

	TakeArm Keep = 0
	
	' 下降動作    P[61]に下降
	Move L, @0 P[61]

End Sub
"""
# Pro2.pcs に file_content の内容をアップロードする
cobotta.upload_content_to_cobotta(file_content, "Pro2.pcs")
print(cobotta.get_cobotta_file_names())

内部の PacScript の Save (Download)

基本的に特別な場合を除いて、推奨してないが、直接デンソーのスクリプトを使うことができる。 デンソーウェーブのコボッタ形式PacScript 扱う。 制御クラスのテストに使える。

*) 必ず、local で直接 CobottaCtrl を使うときは、終了時には disconnect する KeyboardInterrupt を含めて異常終了するときは disconnect しておく

from cobotta2 import Config, CobottaCtrl
from x_logger import XLogger


Config.load_yaml("config_cobotta1.yaml")

logger = XLogger(log_level="debug", logger_name=Config.CLIENT_LOGGER_NAME)
cobotta = CobottaCtrl(cobotta_ip=Config.COBOTTA_IP, arm_name="Arm", logger=logger)

print(cobotta.get_cobotta_file_names())
cobotta.download_file_from_cobotta("P62.pcs")


作者

  • Kengo NAKADA