Kinovarobotics / Kinova-kortex2_Gen3_G3L

Code examples and API documentation for KINOVA® KORTEX™ robotic arms
https://www.kinovarobotics.com/
Other
114 stars 84 forks source link

Callback Error In Multi RouterClient: No callback list instantiated #166

Open WLucky opened 1 year ago

WLucky commented 1 year ago

Description

When creating two routers in the same code using the Python API, and operating both arms in collaboration using multi-threading, an error "No callback list instantiated" is raised, and one of the arms times out waiting for a response.

Version

At a minimum, provide the Kortex API and Kortex-enabled device versions.

KortexAPI : kortex_api-2.5.0.post6-py3-none-any.whl

Kortex Device : kinova gen3

Steps to reproduce

  1. Create two or more RouterClient instances
  2. create two threads to run two arms meanwhile like human, we use example_trajectory in examples/110-Waypoints/01-send_angular_wapoint_trajectory.py
  3. Error: No callback list instantiated for one arm and will wait for timeout after action end.

Code example

with utilities.DeviceConnection.createTcpConnection(ip=LEFT_ARM_IP) as left_router, utilities.DeviceConnection.createTcpConnection(ip=RIGHT_ARM_IP) as right_router:
        # Create required services
        left_base = BaseClient(left_router)
        right_base = BaseClient(right_router)

       action_thread([action_1_l, action_1_r], [left_base, right_base])

def action_thread(aciton_func_list, base_list):
    threads = []
    for action_func, base in zip(aciton_func_list, base_list):
        t = threading.Thread(target=action_func, args=(base,))
        threads.append(t)

    for t in threads:
        t.start()

    for t in threads:
        t.join()

def action_1_l(base, jointPoses = left_jointPoses, durations = durations):

    # Example core
    success = True

    # success &= move_to_home_position(base)
    success &= move_trajectory(base, jointPoses, durations)

    return 0 if success else 1

Expected behavior

Describe the expected behavior (in regard to the bug described above).

I hope both arms can receive the returned message after completing their respective actions, such as completion notification, and then perform the corresponding processing.

Any other information

Any other information you believe the developers need to know.

The reason for the error is that the notificationService in RouterClient is unique to the class, rather than unique to the instance. As a result, when registering the notification callback, the subsequent router will overwrite the callback function of the previous instance, leading to an error.

class RouterClient:
    notificationService = {}

    def __init__(self, transport, errorCallback=None):
        self.transport = transport
        self.sessionId = 0
        self.m_isActive = True
        self.callback = partial(self.onFrameCallback)
        self.transport.registerOnFrameCallback(self.callback)
        self.errorCallback = errorCallback
        self.frameHandler = FrameHandler()
        self.m_hitCallback = None

fixed:

class RouterClient:
    def __init__(self, transport, errorCallback=None):
        self.notificationService = {}
        self.transport = transport
        self.sessionId = 0
        self.m_isActive = True
        self.callback = partial(self.onFrameCallback)
        self.transport.registerOnFrameCallback(self.callback)
        self.errorCallback = errorCallback
        self.frameHandler = FrameHandler()
        self.m_hitCallback = None
felixmaisonneuve commented 1 year ago

Hi @WLucky,

I looked into it, it seems to only apply for the python API. I opened a bug internally and it will be fixed in an upcoming release.

I will leave this issue opened until it is fixed.

In the meantime, you can either use the C++ API or apply the modification you suggested directly in your local python package (somewhere in home/user/.local/lib/pythonX.X/site-packages/kortex_api/RouterClient.py)

I assume you already did the second option since you posted the fix as well. I assume your system is running now.

Thank you very much for sharing this bug, Felix

WLucky commented 1 year ago

Hi @WLucky,

I looked into it, it seems to only apply for the python API. I opened a bug internally and it will be fixed in an upcoming release.

I will leave this issue opened until it is fixed.

In the meantime, you can either use the C++ API or apply the modification you suggested directly in your local python package (somewhere in home/user/.local/lib/pythonX.X/site-packages/kortex_api/RouterClient.py)

I assume you already did the second option since you posted the fix as well. I assume your system is running now.

Thank you very much for sharing this bug, Felix

Thank you for your reply. I am glad that I could contribute to this project.