# 代用的なexample コボッタの基本的使用例とそこで使っている関数の説明 ## config.yaml の書き方 機能拡張によって名前の方針が少しぶれているところがある。 途中で gRPC 対応にした時に FastAPI(ese774) 利用と gRPC 利用で PORTを分けるために用語を切り分けた。gRPC を読み込んでいる場合は、SERVER_PORT が FASTAPI_PORT に してないとだ正しく機能しない(サーバーが GRPC_PORT と FASTAPI_PORT の二つになる) サーバー起動時に文句を言われる。 これを区別してないサーバー設定サンプルがどこかに残っていることがある。 サーバーを使うだけのユーザーは気にしなくて良い。 デバイスサーバーを立ち上げる管理人は注意する必要がある。 ```yaml # 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 から設定を読むので混乱しないように注意する ```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 のときはその動作が正しく終了してない ので、ハンドリングした方が健全であり、エラーの原因を表示した方がいい。 ```python 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) アーム権限の取得 アーム権限を取得してないと動かすことができない。 これは、本質的にはサーバー側で取得される。 つまり、サーバを複数人で使っているときは注意。 **マルチユーザー環境でまだ作り組んでいないので、同時に別端末から 使うときの排他的扱いはバグがある(むしろ「仕様上」つめてないので、 設計上の不備がある)** ```python import asyncio async def main(): # ... await client.take_arm() ``` ## 基本命令 (give_arm) 未実装 取得したアーム権限を解放する。 サーバー側でアームを取得しているので、クライアントからは 一度アームを取得してしまえば、熱心にアーム解放をしなくても動くが、 マルチユーザー環境だと take/given は注意する。 ```python import asyncio async def main(): # ... await client.given_arm() ``` 実は ```release_arm()``` というメソッドもある。ないような同じで愛絵違いなだけ。 ## 基本命令 (turn_on_motor) モーターのon ```python import asyncio async def main(): # ... await client.turn_on_motor() ``` ## 基本命令 (turn_off_motor) モーターの off。 モーターを off したら色々切れるので割と重要 ```python import asyncio async def main(): # ... await client.turn_off_motor() ``` ## 基本命令 (set_coord_type) メソッドごとではなくて、全体に設定。 ```python import asyncio async def main(): # ... await client.set_coord_type("J") await client.set_coord_type("P") ``` ## 基本命令 (set_motion_mode) メソッドごとではなくて、全体に設定。 ```python 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) メソッドごとではなくて、全体に設定。 ```python import asyncio async def main(): # ... await client.set_speed(100) ``` ## 基本命令 (set_accel) メソッドごとではなくて、全体に設定。 ```python import asyncio async def main(): # ... await client.set_accel(100) ``` ## 基本命令 (set_decel) メソッドごとではなくて、全体に設定。 ```python import asyncio async def main(): # ... await client.set_decel(100) ``` ## 現在のアームの位置 ```python 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") # これはエラーになる ``` ## 動作に対してエラー判定する 大抵のロボット系関数は戻り値として動作したか?異常に終わったか?の判定ができる ```python 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()) ``` 移動コマンド始め、ほぼあらゆるコマンドで成功の可否を取れる ```python 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 で デンソーのスクリプト契機っぽい記述もできる。 使用は推奨しない。 ```python 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 標準的な使い方 ロボット自体が内部で標準で持っている座標を使う ```python 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 を与えて移動する ```python 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 変更してから移動 ```python 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。 位置や角度の微調整をして、座標を作るのも使う ```python 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 指定での移動 ```python 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 が複数ある時に、そのパス操作の混ぜ方を変更する。 速度だけでも、加減速だけでもなくパス自体に対する影響パラメータ。 メーカーによって言い方が異なるが大抵は同じ意味のパラメータとなる ```python 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) スピード ```python 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) 加減速 ```python 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) モーションモード ```python 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 命令で指定の軸だけ直接回すことができる ```python 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命令) オフセット移動 ```python 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 のみの関数になるかもしれない? 命令の実装(オプション形式など) まだ迷っているので変える可能性がある ```python # 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 (距離移動) ```python 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 (力移動、閉じる) ```python 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 座標の取り方が楽になる。 ```python 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()) ``` ## コボッタのハードウエアログ取得 ```python import asyncio async def main(): # .. await client.start_log() await client.start_servo_log() ``` コボッタのハードウエア側(テーティングペンダント上)のログを取る ## 内部変数への読み書き1 (get_P) メソッドを使って、コボッタ内部の指定の P を取得する ```python 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) ```python 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 へ書きこみ ```python 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 する ```python 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 一覧。 コボッタ内にあるものを表示する。 ```python 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 しておく ```python 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 扱う。 制御クラスのテストに使える。 ```python 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 しておく ```python 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