CHANGELOG

This file records the change history of this project.

v0.1.2 - 2026-09-09

Fixed

  • Corrected motion execution result handling for the Dobot MG400.

    • Fixed an issue where move() was considered successful solely because a JointMovJ, MovJ, or MovL command had been accepted.

    • For blocking motion, the robot’s error state is now checked after Sync(), and False is returned if an alarm occurs during execution.

    • Execution errors occurring after command acceptance are now detected using the Feedback ErrorStatus and GetErrorID().

    • Failed responses from the motion commands themselves continue to be treated as failures.

  • Corrected retrieval and display of Dobot alarm information.

    • The GetErrorID() response is now parsed while preserving the Controller / Servo distinction, rather than flattening it into a simple integer sequence.

    • Fixed an implementation in which alarm definitions could overwrite each other when Controller and Servo alarms shared the same alarm ID.

    • Error messages now include the alarm ID and its source.

    • Japanese text from the alarm definition’s jp field is preferred; when unavailable, the existing language is used as a fallback.

    • Both description and solution are now retrieved and displayed.

    • Only information actually present in alarm definitions is displayed; missing information is neither inferred nor fabricated.

  • Cleaned up raw GetErrorID() response logging.

    • Nested arrays used for internal parsing are no longer written to normal INFO logs.

    • Raw GetErrorID() responses are now logged at DEBUG level.

    • Normal operation displays parsed and formatted alarm information.

Refactored

  • Moved error handling previously concentrated in dobot_tcp.py into dobot_error.py.

    • Added DobotErrorManager.

    • Separated retrieval and parsing of GetErrorID().

    • Separated identification of Controller / Servo alarms.

    • Separated loading and indexing of alarm JSON data.

    • Separated generation of error descriptions.

    • Separated motion error detection using Feedback ErrorStatus.

    • Separated error monitoring immediately after motion commands.

  • Preserved compatibility of the public error APIs of DobotTcp:

    • get_error()

    • get_error_code()

    • get_error_count()

    • get_error_info()

    • get_error_description()

    • get_current_error_info()

    • error_code

    • error_description

    These APIs remain available; only their internal implementation is delegated to DobotErrorManager.

Compatibility

  • The vendor-supplied dobot_api.py remains unchanged.

  • The existing public interface of DobotTcp is preserved.

v0.1.1 - 2026-09-09

Changes

  • Reorganized acquisition of actual MG400 robot state.

    • current_position is obtained from Dashboard API GetPose().

    • current_angle is obtained from Dashboard API GetAngle().

    • servo_on is obtained from Feedback EnableStatus.

    • busy_status is determined from Feedback RunningStatus / JogStatus.

    • state() uses Feedback RunningStatus as the basic running state.

    • DOBOT-specific RobotMode() is handled separately rather than being confused with the running state.

  • Reorganized conversion between the MG400’s four-axis coordinates and the public six-component representation.

    • Cartesian coordinates [x, y, z, r] are represented as [x, y, z, 0, 0, rz].

    • The MG400’s four joint values are converted to the six-component interface, with J5/J6 set to 0.0.

    • Implemented conversions of User / Tool coordinate-system definitions appropriate to the four-axis MG400.

  • Implemented Tool coordinate-system operations.

    • Implemented set_tool_define() / set_tool().

    • Implemented get_tool_define() / get_tool().

    • When retrieving a Tool definition, the current Tool index is saved, the target Tool is selected and read from Feedback, and the original Tool is restored.

  • Implemented and reorganized Work coordinate systems using the MG400 User coordinate systems.

    • Adapted retrieval and configuration of User coordinate-system definitions to the MG400 coordinate representation.

  • Reorganized speed-related interfaces.

    • SpeedL is used for the linear motion speed percentage.

    • SpeedJ is used for the joint motion speed percentage.

    • SpeedFactor is used for the global speed multiplier.

    • Stopped returning dummy values for deceleration and extended acceleration/deceleration features for which no semantically equivalent MG400 API has been confirmed.

  • Implemented approach() as motion relative to a reference position plus an offset.

  • Clarified the roles of digital I/O.

    • Digital inputs are read using DI().

    • Corrected the confusion between reading outputs and reading inputs.

  • Clarified handling of unsupported interfaces.

    • Unimplemented functions no longer return dummy values such as None, 0, or an empty string in a way that makes them appear implemented.

    • Features with no confirmed equivalent in the MG400 API are explicitly marked unsupported.

    • DOBOT-specific functions are not mechanically mapped to similarly named common-interface functions when their semantics differ.

  • Corrected take_arm() / give_arm() to be compatibility no-ops for the MG400.

    • Because the MG400 has no separate operation for acquiring or releasing arm-control authority, these methods return True without sending commands to the robot.

    • They are not incorrectly mapped to EnableRobot() / DisableRobot().

  • Cleaned up comments and docstrings in the Dobot implementation.

    • Removed names and explanations specific to other robots, controllers, and APIs.

    • Standardized comments and docstrings to describe only the specifications and behavior of the MG400/Dobot implementation.

Design policy

  • Implement DOBOT API mappings according to the semantics of the common interface, not merely similarities between API names.

  • Where the MG400 lacks an equivalent function, do not substitute another function and change the intended meaning.

  • Distinguish intentional compatibility no-ops from unimplemented features.

  • Keep vendor-supplied code unchanged; implement necessary behavior and conversions in the Dobot control layer.

v0.1.0 - 2026-09-08

Starting from v0.0.0, the architecture for controlling the DOBOT MG400 through a common interface was reorganized, and basic motion control was verified on actual hardware.

Common interface and implementation layers

  • Organized DobotCtrl as the common public robot-control interface.

  • Separated the MG400-specific implementation into DobotTcp.

  • DOBOT-specific functionality is handled by DobotTcp, preserving the common interface exposed by DobotCtrl.

  • Standardized Cartesian poses as [x, y, z, rx, ry, rz] in the common interface, converting to the MG400’s [x, y, z, r] with r = rz.

  • Also organized conversion between the common joint-pose representation and the MG400’s four-axis representation.

Official DOBOT API and extended API

  • Used vendor-supplied dobot_api.py without modification.

  • Introduced DobotApiExt, DobotApiDashboardExt, and DobotApiMoveExt as inheritance/extension layers over the vendor classes.

  • DobotTcp accesses the official DOBOT API through the extended API layer.

  • Organized connections for Dashboard (29999), Move (30003), and real-time status (30004).

  • Integrated API communication into the logger using [DobotApi][CONN], [DobotApi][TX], and [DobotApi][RX].

  • Distinguished DobotTcp control logs from API-level communication logs.

Basic control

  • Made EnableRobot() / DisableRobot() available through the common interface.

  • Connected speed and acceleration settings to the MG400 Dashboard API.

  • Mapped PTP / LINE motion to MG400 MovJ() / MovL().

  • Organized handling of TCP/IP command responses so that command acceptance results are returned to the caller.

Work / User coordinate systems

  • Organized the mapping between common Work coordinates and MG400 User coordinates.

  • Implemented change_work() using MG400 User(index).

  • Mapped definition and retrieval of MG400 User coordinate systems to common Work coordinate-system operations.

Motion control

  • move() accepts a six-component pose from the common interface, converts it to the MG400’s four-component pose, and sends it to the robot.

  • is_async selects blocking or non-blocking execution.

  • wait_for_complete() uses the independent Sync() command on the TCP/IP Move port.

Final correction of blocking / non-blocking behavior

During development, an implementation was introduced that sent SYNC=0 / SYNC=1 from DobotStudio Pro script instructions as dynamic arguments to MovJ() / MovL() on TCP/IP port 30003.

On actual hardware, the TCP/IP response to MovJ(...,SYNC=1) returned immediately, failing to provide the blocking behavior required by the common interface. That approach was therefore abandoned.

The v0.1.0 implementation is:

is_async=True
    MovJ(...) / MovL(...)
    -> Command accepted
    -> return

is_async=False
    MovJ(...) / MovL(...)
    -> Command accepted
    -> Sync()
    -> Motion completed
    -> return

This separates the SYNC option in DobotStudio Pro scripts from the independent Sync() command in the TCP/IP API.

Hardware verification as of v0.1.0

  • Local direct-control blocking example: verified working.

  • Local direct-control non-blocking example: verified working.

  • These examples serve as the reference implementations for basic motion control in v0.1.0.

v0.0.0

  • Initial development release.

  • Began developing the DOBOT MG400 control-code architecture, common interface, TCP/IP communication, and motion control.

2026-09-08 - Initial record

This initial changelog entry summarizes the design, implementation, and corrections completed up to this point for the DOBOT MG400 control package.

Separation of the common interface and MG400 implementation

The public control interface was separated into DobotCtrl and the MG400-specific implementation into DobotTcp.

DobotCtrl
    Common public interface
        |
        v
DobotTcp
    MG400-specific implementation

DobotCtrl is responsible only for exposing the common interface. It delegates TCP/IP API selection, coordinate conversion, and real-time status retrieval to DobotTcp.

DOBOT-specific features that do not belong in the common interface are kept in DobotTcp.

Changed architecture to avoid direct modifications to vendor dobot_api.py

The dobot_api.py supplied by DOBOT is retained unchanged as vendor code.

Additional processing is implemented in derived classes:

DobotApiExt
DobotApiDashboardExt
DobotApiMoveExt

Connection handling and logger-based TX/RX/CONN output were separated from vendor code.

Implemented the three MG400 port connections

DobotTcp manages three connections:

29999 Dashboard
30003 Motion
30004 Real-time status

Port 30004 is received by a dedicated thread. The implementation accumulates and parses 1440-byte frames and maintains the latest state.

Standardized logging through a logger

All control-layer output uses the logger.

[DobotApi][CONN]
[DobotApi][TX]
[DobotApi][RX]
[DobotTcp]
[DobotStatus]

These prefixes distinguish connections, transmissions, receptions, state changes, and errors.

Mapped motor ON/OFF to the MG400 API

Common motor operations are mapped as follows:

turn_on_motor()  -> EnableRobot()
turn_off_motor() -> DisableRobot()
reset_error()    -> ClearError()

take_arm() / give_arm() are separate from motor ON/OFF.

No concept equivalent to TakeArm / GiveArm has been confirmed in the MG400 TCP/IP API, so these are no-ops preserving the common interface.

Standardized common coordinates to six components

The common Cartesian interface uses:

[x, y, z, rx, ry, rz]

The MG400 uses four components:

[x, y, z, r]

Conversion is defined as:

r = rz
rx = 0
ry = 0

Coordinates returned from the MG400 are expanded to:

[x, y, z, 0, 0, r]

The common joint interface also uses six components. Four MG400 joint values are expanded to:

[j1, j2, j3, j4, 0, 0]

Implemented MG400 conversion in move()

Basic motion mappings were implemented:

P + PTP  -> MovJ
P + LINE -> MovL
J + PTP  -> JointMovJ

The MG400 API’s SYNC was mapped to the common interface’s is_async:

is_async=True  -> SYNC=0
is_async=False -> SYNC=1

Separated motion_mode from path_blend

The trajectory types PTP / LINE / CIRCLE / SPLINE and the path-passing condition path_blend were clarified as separate concepts.

Because DOBOT’s CP does not have the same meaning as the common interface’s path_blend, no automatic path_blend -> CP conversion is performed.

Implemented motion-completion detection

Using execution state from port 30004, the following methods were implemented:

motion_complete()
get_motion_complete()
wait_for_complete()

Successful command acceptance is distinguished from completion of physical motion.

Implemented current position and joint-angle retrieval

The following fields are read from port 30004:

tool_vector_actual
q_actual

Values are converted to the six-component common interface before being returned.

Implemented forward and inverse kinematics

The following mappings use the MG400 API:

p2j() -> InverseSolution()
j2p() -> PositiveSolution()

Implemented Work coordinates using User coordinates

The common Work coordinate system was defined to use the MG400 User coordinate system.

Responsibilities are separated as follows:

set_work()            Define a User coordinate system
change_work()         Select an existing User coordinate system
get_current_work_no() Get the current User index
get_work()            Retrieve a User coordinate-system definition

change_work() uses:

User(index)

get_current_work_no() uses the userCoordinate field on port 30004.

get_work() uses the user field on port 30004.

set_work() was implemented using the command defined in the MG400 manual:

SetUser(index,{x,y,z,r})

Even if vendor dobot_api.py has no Python wrapper for SetUser(), the vendor file remains unchanged; DobotTcp sends the TCP/IP command directly.

The six-component Work definition:

[x, y, z, rx, ry, rz]

is converted to the MG400 representation:

{x,y,z,r}

with r = rz.

Work coordinate systems with nonzero rx or ry are rejected because the four-axis MG400 cannot represent them.

Implemented Tool coordinate-system selection

Selecting and retrieving the current Tool index is mapped to:

Tool(index)
toolCoordinate

Reading or changing Tool definitions themselves was not yet implemented.

Implemented I/O

Common I/O methods are mapped to:

get_IO() -> 30004 digital_input_bits
set_IO() -> DO(index,status)

Implemented error retrieval and description display

Error IDs are retrieved using GetErrorID(), and descriptions are looked up in DOBOT-supplied alarm JSON files.

If the first return value of an API command is not 0, the error ID and description are written to the logger.

Reorganized the FastAPI layer

DobotCtrl is passed as a device class to FastAPI’s automatic dispatch.

Synchronous and asynchronous clients are distinguished by their HTTP calling mechanisms. This is separate from the is_async setting for robot motion.

Split test scripts by interface

Individual executable scripts were prepared to verify each public method and property.

Because PyCharm recognizes test_*.py as automated tests, scripts intended for hardware verification were renamed to use check_*.py.

Each script is independently executable and does not depend on a shared helper.

Explicitly documented unimplemented interfaces

The reason for an unimplemented or partially implemented interface is documented in a comment immediately before the corresponding method.

In particular, the documentation distinguishes:

  • Features physically impossible with the MG400’s mechanical configuration.

  • Features for which no direct equivalent has been confirmed in the currently exposed API.

  • Semantic conversions that have not yet been implemented.

  • Features that are simply not yet implemented.

Main currently identified unimplemented or partially implemented features

  • halt()

  • hand_stop()

  • Mapping path_blend to actual MG400 behavior

  • Independent decel

  • External-axis speed, acceleration, and deceleration

  • Full coordinate-conversion semantics of dev()

  • CIRCLE / SPLINE in move()

  • approach()

  • rotate()

  • Project-name resolution in run_script()

  • Hand control

  • autocal()

  • Controller / servo log interfaces

  • Reading and setting Tool definitions

  • direct_mode

  • task object

  • Retrieving the actual robot version

Hardware verification on 2026-09-08

Successful connection to MG400 10.170.10.63, EnableRobot(), SpeedFactor(30), AccL(30), and AccJ(30) were confirmed.

It was also confirmed that the current position can be obtained from real-time status in a form such as:

[x, y, z, 0.0, 0.0, rz]

An earlier local example passed four-component MG400-native coordinates:

[x, y, z, r]

to move(), and was confirmed to be rejected by the common interface’s six-component validation.

Future examples use:

[x, y, z, 0, 0, rz]