# history & comment A history log that largely overlaps with `CHANGELOG.md`. This page primarily collects update notes posted to Slack. Development has involved exploration and trial and error. Occasionally, robot features that were rarely used turned out to be important, although most discoveries had little practical impact. The entries also document the difficulties encountered during development. ## 2026.05.13 The main modules have been updated. Basic testing has been completed. ese774_frame-v0.4.20 https://github.com/ohara-lab-su/ese774_frame/archive/refs/tags/v0.4.20.zip cobotta2-v0.13.8 https://github.com/ohara-lab-su/cobotta2/archive/refs/tags/v0.13.8.zip aandd_reader-v0.2.11 https://github.com/ohara-lab-su/aandd_reader/archive/refs/tags/v0.2.11.zip --- [Note] Upgrade `ese774_frame` to v0.4.20 or later before installing the other packages. --- [Changes] Existing usage remains supported (backward compatibility). All communication frameworks used by SUSANOO are transparent. The `DeviceProxy` interface was introduced to make this explicit. The conventional device-specific client classes (which are also transparent internally) remain available. Advantages Device classes can be specified explicitly. Avoids confusing distinctions between asynchronous and synchronous interfaces. Makes transparent communication explicit and clarifies the distinction between device-side servers and control clients. Uses the widely adopted concepts of device classes and device proxies. Organizes the implementation around the Registry and Factory design patterns. New syntax ```python config = Config("cobotta1_server1.yaml") client = DeviceProxy("CobottaCtrl", config=config, async_mode=True,,,,)The default is `async_mode=True`. ``` Previous syntax (async) ```python config = Config("cobotta1_server1.yaml") client = AsyncCobottaCtrl(config=config,,,,,) ``` New syntax(sync) ```python config = Config("cobotta1_server1.yaml") client = DeviceProxy("CobottaCtrl", config=config, async_mde=False,,,,) ``` Other options remain unchanged. `DeviceProxy` provides the common interface. For example, to use the AanddReader device class transparently with the new syntax: New syntax ```python config_reader = Config("aandd1_server1.yaml") reader = DeviceProxy("AandReader", config=config_reader, async_mode=True,,,,) config_cobotta = Config("cobotta1_server1.yaml") cobotta = DeviceProxy("CobottaCtrl", config=config_reader, async_mode=True,,,,) ``` This provides a consistent way to instantiate the different device classes. ## 2026.05.12 cobotta2-v0.13.7 has been released. https://github.com/ohara-lab-su/cobotta2/archive/refs/tags/v0.13.7.zip https://ohara-lab-su.github.io/cobotta2/ - Resolved annotation inconsistencies between interface layers. - Adjusted internal compatibility between b-CAP and ORiN2. - Consolidated previously scattered environments. - Improved compatibility between b-CAP and ORiN2 modes. After extracting the archive, cobtta2/tests/fastapi/async the test programs are collected in this directory. At present: --- Items for which retesting is nearly complete - angle - autucal - busy - drive - error_code - get_bstrOpt (unused) - get_cobotta_file_name - get_cord_type - get_P - get_path_blaned - get_position - get_speed - hand - init_hand - is_empty_position - move_fig - move_J - offset - P - p2j - release_arm - reset - set_P - speed - status - stop - rotate - rotate_H removed - Run PacScript (b-CAP mode) - Bug fixed - save_load ---- In ORiN2/b-CAP, around version 0.13.3, it was used in practice, but the test program still needs further verification - camera ---- Not yet tested with the latest version, but unlikely to be affected in principle (rarely used) - log ---- Items deferred because they are rarely used and difficult to test Work-coordinate-system operations, including redefining coordinate systems. These have not yet been used in full production, and for direct teaching there is little need for them, so they have been deferred. - work ---- Many items remain, and test coverage is still insufficient Because the implementation contains so many features, frequent version updates have outpaced testing of some functions. - move (some options) ## 2026.04.28 cobotta2 v0.13.3 has been released. https://github.com/ohara-lab-su/cobotta2/archive/refs/tags/v0.13.3.zip git(https://github.com/ohara-lab-su/cobotta2) This release primarily fixes bugs and reorganizes the test code. Some tests had stopped working as features were added, development policies changed, and the number of robots increased. The test programs have been reorganized and adjusted to run again, including examples using the underlying b-CAP, ORiN2, and REST API communication implementations. When using COBOTTA, refer to the programs under: https://github.com/ohara-lab-su/cobotta2/tree/main/tests - `fastapi` - `local` The `fastapi` directory provides minimal examples and tests for each function using SPring-8-compatible communication. The `local` directory provides tests that control COBOTTA directly without communication middleware. These examples help distinguish between failures caused by errors or incorrect use of the COBOTTA control program and failures caused by communication. They also serve as tutorials for COBOTTA features, including advanced functions and usage patterns that we do not normally employ. ## 2026.04.28 ### Recovery after a robot collision For a minor collision, the current system can resume normal control by executing commands such as: ```python stop() take_arm() turn_on_motor() ``` However, an error may recur immediately after recovery. In that case, it is necessary to turn off the motors or press the emergency-stop button, then switch to Free mode and recover the robot manually. We asked DENSO WAVE whether software-only recovery was possible, as it is for minor collisions. Their explanation was as follows: > If the collision is substantial and an external force continues to act on the robot at the contact point, collision detection is triggered immediately when the motors are enabled, preventing motion commands from being executed. Allowing motor-driven recovery in this condition could damage the mechanism or surrounding equipment, so the robot inhibits motion as a safety measure. When an external force remains after a collision, manual intervention, such as releasing the constraint in Free mode, is necessary. This is not merely a control limitation but an essential safety requirement; it cannot always be replaced by software-only recovery. Thus, there appears to be no alternative to the recovery procedure we already understand. For example, when attaching a rubber cap to a vial, a motion that strikes the top of the cap with the robot may trigger an abnormal-force condition and stop the robot. In that case, all operations must be stopped and the robot must be recovered manually. In our studies so far, we have generally been able to push to within approximately 5 mm of the target without triggering a force abnormality. This is not a universal threshold: the speed and resulting force depend on the distance to the target and the `path_blend` value. Nevertheless, movements of a few millimeters were possible in our tests. ## 2026.04.21 Robot positions can be specified using two coordinate representations: P-coordinate representation (x, y, z, rx, ry, rz) J-coordinate representation (J1, J2, …, J6) A single P coordinate can correspond to multiple joint-coordinate (J) configurations. Many robots provide additional information specifying the robot configuration (joint arrangement), but its representation differs by manufacturer. Even when the P coordinates are identical, the configuration information changes the robot posture, so a motion to the same coordinates may succeed or fail. For DENSO WAVE robots, in addition to the six position-and-orientation components, a motion configuration identifier (Fig) is defined to distinguish robot postures. In P-coordinate representation, Fig is treated as the seventh element. Until now, the SUSANOO-based robot device server represented P coordinates as [x, y, z, rx, ry, rz, option] This is represented as six axes plus one additional element. get_current_position() and get_P(xx) also return seven elements. For now, the robot-native specification takes precedence; this may change when other robot manufacturers are supported. A potentially confusing distinction: COBOTTA uses J1–J6 in J-coordinate representation, although DENSO software also defines unused J7 and J8. By contrast, the seventh P-coordinate element is not an unused axis; it is the posture identifier Fig. Previously, when coordinates were passed to move() or set_P(), the last element (Fig) was fixed at -1 or discarded even if more than six elements were supplied. Consequently, the current implementation has two cases: A) Movement using an internal P coordinate that includes Fig information B) Movement using explicit coordinates without Fig information (fixed to -1) These two patterns coexist. As a result, A) Movement to a stored P position fails (using the robot-stored Fig) B) Movement to explicitly specified coordinates succeeds (without using Fig) This behavior can occur. [17:18] Comparable concepts used by other manufacturers include: DENSO: Fig (motion configuration number) Techman: Pose / Config UR: qNear and other parameters for selecting among multiple joint solutions (proximity to a joint solution) FANUC: config YASKAWA: form (configuration) These are examples of equivalent concepts. It should be possible to specify this posture information when executing move. Because the name config has a broad meaning and is prone to naming conflicts, alternatives such as ik_config are also being considered. ik stands for inverse kinematics, a standard term paired with fk (forward kinematics). The term pose used by Techman is concise and easy to understand, and seems more intuitive than DENSO’s fig. However, returning pose is natural when working with P coordinates, and DENSO’s seven-element representation (six coordinates plus pose) has a reasonable basis. The current specification policy is as follows. For seven-element input, treat the seventh element as pose (Fig). If a pose option is provided, it takes precedence. move([6 axes], pose=xxx) (new option) move([7-element or 6-element list]) (extension of existing specification) move(P10) (uses stored Fig information; existing option) At present, pose takes an integer corresponding to DENSO’s Fig. For six-element input, Fig remains -1 (current behavior). For now, only move-family APIs are supported. The final specification will be revised after examining implementations from other manufacturers, probably by introducing a dedicated pose class. The program is currently being revised according to this policy. It is expected to remain outside the stable phase for some time. The 0.12.x series will remain on its current version branch, and the above new specification is planned for 0.13.x onward. ## 2026.04.21 cobotta2 v0.13.0 https://github.com/ohara-lab-su/cobotta2/archive/refs/tags/v0.13.0.zip A provisional release is available. Substantial changes may have left some bugs, although basic testing has been performed. The main changes are as follows. Behavior is largely unchanged, but Previously, for P-coordinate motion specified with six coordinates, the seventh element containing pose information was discarded entirely; it can now be handled directly. Six-element input retains the previous behavior without using the seventh element. Getter methods continue to return seven-element information. Six-element input plus the pose option is supported. In the next version, the plan is to specify robot configurations such as LEFT/FLIP through the pose option to support such moves. For now, specify the numeric value defined by DENSO. https://www.fa-manuals.denso-wave.com/jp/CVRover202508/006995/ Fixed an issue where the hand did not move correctly when the speed option was omitted. - Corrected b-CAP speed-related set/get operations, mainly initialization. - Fixed bugs in b-CAP client speed/jspeed/accel/decel handling. ## 2026.04.20 v0.13.0, nakada ### Purpose of the revision Added pose interfaces and corrected handling of the seventh P-coordinate element. This applies to the move family. ### High-level interface - The active high-level interfaces in cobotta_ctrl.py are move() and dev(). - Add pose to CobottaCtrl.move(), which is part of the pose interface, and forward it to the lower-level move(). - Do not add pose to CobottaCtrl.dev(), which performs a six-coordinate offset calculation. ### FastAPI - Add pose to MoveRequest. - Because the current specification still includes move_P/L/C/S in MoveXRequest, - add pose for model consistency. - This does not mean restoring the commented-out CobottaCtrl wrappers. - Correct dev in spec_ctrl.py from ApproachRequest to DevRequest; the former is clearly incorrect. ### target and pose - Treat move([6 axes]) as six P coordinates, as before. - Treat move([6 axes], pose=xxx) as P coordinates with xxx as the seventh element. - Treat the seventh element of move([7 axes]) as pose/fig. - For move([7 axes], pose=xxx), replace the seventh element with xxx; do not append an eighth element. - For move("P10"), do not interpret pose because the target is a string; retain the existing path using the stored Fig for that P number. - Likewise, do not interpret pose in the string syntax move("P10+(...)"). ### offset - offset is a six-coordinate P-coordinate dev operation, also valid for P-number targets. - move("P10", offset=...) follows the dev("P10", offset) path; do not interpret pose in a string target. - For move([6 or 7 axes], offset=...), pass only six reference coordinates to dev. The offset does not change the seventh element. Use the dev result as the P-coordinate motion target, without mixing pose into the offset. ### ORiN2 / b-CAP - Align helper function names between ORiN2 and b-CAP. - The names _make_vnt_pose() and _build_move_target() are unclear, so rename both to _make_move_target(). - _to_pose_string() serializes six P coordinates for dev/offset; do not use it for pose. - _make_offset_pose() is for the "P10+(...)" string syntax; do not interpret pose. - Do not raise TypeError; return False on failure, and have callers detect and propagate False. ## 2026.04.17 Investigation revealed new findings. For example, suppose a stored position P10 is near a singularity. Movement fails: A starting point → move(P10) Movement succeeds: pos = coordinate list for P10 A starting point → move(pos) This behavior was confirmed. It was identified during image-recognition processing that makes extensive use of coordinate systems. It was confirmed that this is not a server-side program bug, and the investigation included inquiries to DENSO WAVE. As a result, it became clear that additional options exist for specifying the robot coordinate configuration. Similar concepts were also identified in robots from other manufacturers, including Universal Robots and Techman, and support is now being developed. ## 2026.04.16 cobotta2-0.12.6 Released. Added a method to check whether an internal position is unused. is_empty_position(position) returns True if the position is unused. For example, the following script teaches the current position into an unused internal variable slot. ```python START_ID = 100 END_ID = 200 for id_num in range(START_ID, END_ID + 1): if client.is_empty_position(id_num, coord_type="P"): pos = await client.get_current_position() await client.set_P(id_num, pos) logger.info(f"learned current position -> P{id_num}") logger.info(pos) breakZip ``` ## 2026.04.10 cobotta2 v0.12.4 Released. Testing camera-related functionality exposed problems introduced by switching to b-CAP. Various updates address these issues. All control servers have been replaced; update them together with the frame-side changes. Enabled PACScript/camera-related methods with b-CAP. Changed the handling policy for take_camera/take_script under ORiN2 to improve stability (release and reacquire handles each time). Adjusted ctrl (interface), b-CAP (backend), and ORiN2 (backend). Organized sample scripts in the package. ## 2026.04.08 cobotta-0.12.3 ese774_frame-0.4.19 was released. The b-CAP backend now works with the weighing code; operation has been verified. Some functions are still incomplete, but compatibility is maintained within the scope of the weighing code, so it should work without problems. On the HTTP (ese774) side, even without using the previously introduced set_timeout() method, the default timeout has been extended to 60 seconds for now. This should make blocking operations reasonably safe. Use set_timeout() for operations exceeding 60 seconds. The b-CAP socket communication timeout is 2000 seconds. Blocking operations are unlikely to take that long, but if timeouts occur on the HTTP side or the underlying robot-control (b-CAP) side, check both settings. ## 2026.04.08 Teaching can now be performed without using the DENSO WAVE application. To save the current position as P110: ```python new_pos = await client.get_current_position() client.P110 = new_pos ``` Alternatively: ```python new_pos = await client.get_current_position() You can use await client.set_P(110, new_pos). Choose whichever form is more convenient. If the position number (such as 110) must be variable, the method is more convenient than a property. ``` To move the arm during teaching, you can either move it manually in direct mode or move it using a game controller. Using the controller makes it possible to operate entirely without DENSO software. All provided methods return a value indicating success or failure. For operation inside a glovebox or hatch, it is important to avoid reliance on DENSO software or physical buttons on the robot. ## 2026.04.08 About COBOTTA errors When COBOTTA collides with an object, even after resetting the error, the error often persists because COBOTTA continues trying to move. One underlying cause has been identified. It concerns how the COBOTTA control program is used. ```python await client.move("P10") await client.move("P11") ``` is a typical sequence. If move("P10") fails due to a collision, move("P11") may still execute even though the previous move did not complete successfully. Movement commands then continue to execute one after another. This becomes a problem when an error occurs. In this case, check the boolean return value of move(), even if it is normally omitted. As described in cobotta_client on GitHub, the sample scripts include patterns such as the following: ```python ret = await client.move("P10") if not ret: error_description = await client.error_description() print(error_description) exit() ret = await client.move("P11") ``` With this approach, an abnormal termination at P10 prevents the move to P11. It also displays information explaining the error that stopped the operation. Robot errors can be displayed using Python alone. You can identify errors without launching DENSO software. Error reset is commonly used, await client.reset_error() and can be performed as shown. ## 2026.04.07 ese774_frame 0.4.18 cobotta 0.12.1 Primarily preparation for seamless integration of joypad (gRPC) and COBOTTA (FastAPI [b-CAP, ORiN]) functions. Fixed server timeouts during long robot operations. Added client-side timeout configuration. client.set_timeout(30) prevents a timeout for 30 seconds. Implemented autocal functionality in earnest. Previously, calibration could only be invoked by powering COBOTTA off and on; it can now be started programmatically (essential for operation inside a glovebox or hatch). Updates are required on the frame, COBOTTA, and client sides. ## 2026.03.27 Made it easy to switch between b-CAP and ORiN2 backends. Extended b-CAP functionality to match the ORiN2 backend. Completed in v0.11.1. Verified take_arm, reset_error, get_error_count, other error-related operations, and move. Confirmed minimum required functionality. Improved Python 3.7 compatibility. Found and fixed a regression that disabled drive/rotate commands and their extended options. ```python server = FastApiServer( device_cls=CobottaCtrl, # Control class router_cls=CobottaRouterCtrl, # Router class config=Config, api_spec=cobotta_ctrl_api_spec, device_kwargs={ "cobotta_ip": Config.COBOTTA_IP, "backend": "bcap", # "backend": "orin2", }, # Constructor arguments for the COBOTTA control class logger=logger, logger_name=Config.SERVER_LOGGER_NAME, # LOGGER_NAME lifespan_msg_prefix="COBOTTA", ) When starting the server with server.run(host=Config.SERVER_IP, port=Config.SERVER_PORT), switch between orin2 and bcap using the backend key in device_kwargs. ``` The b-CAP version can invoke autocal() regardless of the COBOTTA mode, unlike the previous restriction. In other words, autocal can now run without powering off COBOTTA. Zip ## 2026.03.26 Modified the system for detector support so that Python 3.7 works in the global environment rather than a virtual environment. (Previously, Python 3.11 or later was the primary target; this change supports older Python versions.) cobotta2 v0.10.9 ese774_frame v0.4.16 (edited) ## 2026.03.26 v0.10.8, Fixed an important bug in the COBOTTA device server (ORiN2). Details: - Changed offset handling from forced integer conversion to float. The ORiN2 dev P-variable specification had been misread as requiring an integer [in] argument. (This device server internally uses dev to calculate offset coordinates.)