Package: mecademicpy
Mecademic Python APIA python module designed for robot products from Mecademic. The module offers tools that give access to the features of the Mecademic Robots such as MoveLin and MoveJoints available through the TCP/IP text interface. The module can be started from a terminal or a python application and controls the Mecademic products.Supported RobotsMeca500, Mcs500Supported Firmware Versions8.3 and upSupported Python versionsMecademicpy 2.1 targets Python version 3.7 and above.
It has been tested with the following Python versions:Python 3.7.17Python 3.8.18Python 3.9.18Python 3.10.13Python 3.11.8Python 3.12.2PrerequisitesPlease read theuser programming manualto understand concepts necessary for proper usage of the API. This API implements a subset of the commands in theCommunicating over TCP/IPsection. For the exact list of available commands, use thehelp()command as explained inAPI Reference.To be able to use the module without unexpected errors, the user must have a copy of python installed on their machine and it is required to use python version 3.7 or higher. We recommend using Python 3.9 since this is the version on which this module is actively tested.Pythoncan be installed from its main website (a reboot will be require after the installation to complete the setup).The user can validate their python installation by runningpython --versionin a terminal.This library is compatible with Windows, Linux, and Mac.Downloading the packageTo download and install the package, the user can easily do so through pip. Pip will download and install the package on your machine and place it in the python local packages directory. This is done by running the following command:pip install mecademicpyQuick StartEnsure the robot is properly connected to the computer, powered on, and in a nominal state.In a python shell or script, import the library. Then initialize an instance of theRobotclass. Finally, use theConnectfunction by passing the IP Address of the robot as an argument to establish a connection:importmecademicpy.robotasmdrrobot=mdr.Robot()robot.Connect(address='192.168.0.100')TheConnectfunction will raise if connection with robot fails.
This function is synchronous (awaits for success or timeout) even when using theRobotclass inasynchronous mode.Before using the robot, it must be activated and homed. To do so, run the following functions:robot.ActivateRobot()robot.Home()The robot should move slightly to perform its homing routine. We can also userobot.WaitHomed()orsynchronous modeto block execution until homing is done.Once homing is complete, the robot is now ready to perform operations.The user programming manualor the documentation in the module is sufficient to be able to make the Robot perform actions and control the robot.Here is an example of a simple motion to perform:robot.MoveJoints(0,0,0,0,0,0)robot.MoveJoints(0,-60,60,0,0,0)When done with the robot, the user should always deactivate and disconnect. Note that deactivating before the motion is complete will cause the motion to immediately stop. The user can wait for motions to complete usingWaitIdle().Deactivating and disconnecting can be done with the following commands:robot.WaitIdle()robot.DeactivateRobot()robot.Disconnect()It is recommended to useGetStatusRobot()to learn about the current robot status before resuming operation.For complete and working examples, please refer to theexamplesfolder.Features and Additional InformationSynchronous vs. Asynchronous ModeBy default the API operates in 'asynchronous mode', which means sending a command to the robot does not block program execution. To illustrate, the following code will be able to successfully print out the changing joint values resulting from theMoveJointscommand:importmecademicpy.robotasmdrimporttimerobot=mdr.Robot()robot.Connect(address='192.168.0.100',enable_synchronous_mode=False)robot.ActivateAndHome()robot.WaitHomed()robot.MoveJoints(0,0,0,0,0,0)robot.MoveJoints(0,-60,60,0,0,0)# Print robot position while it's movingfor_inrange(100):print(robot.GetJoints())time.sleep(0.05)robot.WaitIdle()robot.DeactivateRobot()robot.WaitDeactivated()robot.Disconnect()However, sometimes it is desired for programs to wait until the previous command is completed before sending the next command. It is generally encouraged to use thecheckpointssystem or the variousWait()functions, but for smaller or simpler programs, the user can setenable_synchronous_mode=Trueto have each command block until the robot has completed the command.The code block below will only print out the final joint position, sincerobot.GetJoints()doesn't execute until the motion is complete.importmecademicpy.robotasmdrrobot=mdr.Robot()robot.Connect(address='192.168.0.100',enable_synchronous_mode=True)robot.ActivateAndHome()robot.MoveJoints(0,0,0,0,0,0)robot.MoveJoints(0,-60,60,0,0,0)# The returned robot position will be (0, -60, 60, 0, 0, 0), because this line will only be executed once MoveJoints(0, -60, 60, 0, 0, 0) has completed.print(robot.GetJoints())robot.DeactivateRobot()robot.Disconnect()One disadvantage of using synchronous mode is that blending between motions is not possible, since the next motion is not sent to the robot until the previous motion is complete.Disconnect on ExceptionBy default, if any unrecoverable error occurs during usage of the Robot class, the class will automatically disconnect from the robot to avoid possible issues. Disconnection also causes the robot to pause its motion.However, disconnecting on exceptions may be undesired when using an interactive terminal or Jupyter notebook, as an accidental mal-formed function call may cause disconnection. As such, this feature can be disabled by settingdisconnect_on_exception=Falsewhen attempting the connection:robot.Connect(address='192.168.0.100',disconnect_on_exception=False)CheckpointsThe checkpoint system allows for creating event objects which will be triggered once the robot reaches a specified point in its execution. TheSetCheckpoint(n)call registers a checkpoint with the robot (withnas the ID), and returns an event-type object that can be used to wait for the checkpoint. This is true for both robot connection type (asynchronous and synchronous mode). For example, the following code will wait until bothMoveJoints()motions have completed, and then print "The MoveJoints() motions are complete.":robot.MoveJoints(0,-60,60,0,0,0)robot.MoveJoints(0,0,0,0,0,0)checkpoint_1=robot.SetCheckpoint(1)checkpoint_1.wait(timeout=10)# A timeout of 10s is set to avoid infinite wait in case of error.print('The MoveJoints() motions are complete.')Note that creating multiple checkpoints with the same ID is possible but not recommended. The checkpoints will be triggered in the order they are set.Checkpoints may also be set in an offline program, saved to robot memory. UseExpectExternalCheckpoint(n)to receive these checkpoints while the robot is running the offline program. The call toExpectExternalCheckpoint(n)should be made before the offline program is started, or otherwise must be guaranteed to occur before the robot can possibly send the checkpoint. For example, the following code will start an offline program and expect to receive a checkpoint from the program, and then print "Received expected external checkpoint":checkpoint_event=robot.ExpectExternalCheckpoint(5)robot.StartOfflineProgram(1)checkpoint_event.wait(timeout=30)print("Received expected checkpoint from running program")where offline program 1 isMoveJoints(100,0,0,0,0,0)
MoveJoints(-100,0,0,0,0,0)
SetCheckpoint(5)
MoveJoints(0,-60,60,0,0,0)
MoveJoints(0,0,0,0,0,0)
SetOfflineProgramLoop(1)If the robot motion command queue is cleared (usingClearMotion()for example), or the robot is disconnected, all pending checkpoints will be aborted, and all activewait()calls will raise anInterruptException.CallbacksTheRobotclass supports user-provided callback functions on a variety of events. These callbacks are entirely optional and are not required, but useful to implement asynchronous applications. The available events are listed in theRobotCallbacksclass. Here are some of these callbacks:on_connectedon_disconnectedon_activatedon_deactivatedon_homedon_erroron_checkpoint_reachedetc... (refer to classRobotCallbacksfor exhaustive list of callbacks)Note that some callbacks pass arguments. For exampleon_checkpoint_reachedpasses the ID of the checkpoint,on_command_messageandon_monitor_messagepasses amecademicpy.robot.Messageobject. Refer to class documentation for details.A simple usage example:importmecademicpy.robotasmdrrobot=mdr.Robot()defprint_connected():print('Connected!')callbacks=mdr.RobotCallbacks()callbacks.on_connected=print_connectedrobot.RegisterCallbacks(callbacks=callbacks,run_callbacks_in_separate_thread=True)robot.Connect(address='192.168.0.100')# Will print 'Connected!' if successful.If the user does not want to automatically run callbacks in a separate thread, setrun_callbacks_in_separate_thread=Falseand callRunCallbacks()when ready to run all triggered callbacks.Running any callback in a separate thread (either through theRobotclass or otherwise) requires that the callback function is thread-safe and uses the proper locks when accessing shared state. Calling any public method of theRobotclass is thread-safe.Note that, due to a Python limitation, all Python threads share the same CPU core and will not take advantage of parallelism and multiple CPU cores of a PC. Unfortunately, this means that an application performing heavy computations (in callback thread or in any other thread) may impact the performance of theRobotclass (especially when processing many monitoring messages at high frequency).If non-trivial computation and high-frequency monitoring are both necessary, the user may offload computation into a separate python process using the built-inmultiprocessinglibrary.Handling Robot ErrorsIf the robot encounters an error during use, the robot will go into error mode. In this mode, the module will refuse any command to the robot unless the error is reset. If the robot is in an error state,GetStatusRobot().error_statuswill returnTrue. To properly reset errors on the robot, the following function must be run:robot.ResetError()It is recommended to useGetStatusRobot()to learn about the current robot status and reset the relevant flags to an appropriate state before resuming operation. For example, an error may require to callResumeMotion(). In this case, verify thatGetStatusRobot().pause_motion_statusis set toTruebefore callingResumeMotion().Theon_errorcallback can also be used to manage robot errors.Improper use of the class can also cause exceptions to be raised. For example, callingMoveJoints()without any arguments will raise an exception.If the user is waiting on an event or checkpoint that theRobotclass later determines will never occur, the event will unblock and raise an exception. For example, if the user is waiting on a checkpoint (WaitCheckpoint), but callsDisconnect()orClearMotion()before the checkpoint is received, the checkpoint will unblock and raise an exception. Events and checkpoints will also unblock with exception on robot error state.The user should use python's built-intry...exceptblocks to handle appropriate exceptions.Handling Robot safety stop conditions(Note: This section applies to robots running firmware 10.1 and above)The robot may encounter safety stop conditions based on external safety signals (EStop, PStop1, PStop2, operation mode changed, enabling device released) or other conditions (connection timeout).
It is recommended to useGetSafetyStatusto learn about the current safety stop signals status.
Theon_safety_stop,on_safety_stop_reset,on_safety_stop_resettableandon_safety_stop_state_changecallbacks can also be used to manage the safety stop signals status.Some safety stop signals cause motor voltage to be removed (EStop, PStop1, operation mode change, etc.).
When these safety signals are present, the robot cannot be activated until the safety signals are reset.
For safety reasons, resetting these signals cannot be done programmatically from the Mecademicpy API. They require to press the Reset button on the power supply (or trigger the reset function from dedicated power supply input pins).Other safety stop signals will cause the robot to pause motion (PStop2, enabling device released, connection dropped).
Once these safety conditions are resolved, the robot may be activated or, if already activated, motion can be resumed usingResumeMotion().For more information about safety signals, refer to the robot's programming manual.Preserved State on DisconnectionOnce the robot is disconnected, not all states are immediately cleared. Therefore, it is possible to still get the last-known state of the robot.Logging Data to FileIt is possible to continuously log the robot state to a file using the API either using theStartLoggingandEndLoggingfunctions or using theFileLoggercontext.An example usage ofStartLoggingandEngLogging:robot.WaitIdle()robot.StartLogging(0.001)try:robot.MoveJoints(0,-60,60,0,0,0)robot.MoveJoints(0,0,0,0,0,0)robot.WaitIdle()exceptBaseExceptionase:print(f'Logging unsuccessful, exception encountered:{e}')finally:robot.EndLogging()Note that the user should wait for the robot to be idle (WaitIdle) before starting to log, and also wait for idle before ending the log. This is to ensure the log correctly captures the movements of interest.It should also be noted that it is mandatory to give a monitoring interval, in seconds, toStartLogging, to specify at which rate data should be logged. In the example above, the monitoring interval is set at 0.001 seconds, or 1 ms. It is the minimum monitoring interval that can be set usingSetMonitoringInterval, which is the robot command used byStartLoggingto choose the monitoring interval.The user can also use theFileLoggercontext:robot.WaitIdle()withrobot.FileLogger(0.001):robot.MoveJoints(0,-60,60,0,0,0)robot.MoveJoints(0,0,0,0,0,0)robot.WaitIdle()TheFileLoggercontext will automatically end logging after either completing thewithblock or encountering an exception.The user can select which fields to log using thefieldsparameter inStartLoggingorFileLogger. By default, all available fields are logged. The available fields are currently:"TargetJointPos""TargetCartPos""TargetJointVel""TargetCartVel""TargetConf""TargetConfTurn""JointPos""CartPos""JointVel""JointTorq""CartVel""Conf""ConfTurn""Accel""Wrf""Trf""Checkpoint""ExtToolStatus""ValveState""GripperState""GripperForce""GripperPos""IoModuleStatus""IoModuleOutputState""IoModuleInputState""SigGenStatus""SigGenOutputState""SigGenInputState""VacuumState""VacuumPressure"These strings should be placed into the list given to thefieldsparameter.The following example only logs the"TargetJointPos"and"JointPos".robot.WaitIdle()withrobot.FileLogger(0.001,fields=['TargetJointPos','JointPos']):robot.MoveJoints(0,-60,60,0,0,0)robot.MoveJoints(0,0,0,0,0,0)robot.WaitIdle()Note that theSetRealTimeMonitoringcommand is used by inStartLoggingorFileLoggerto enable all the real-time monitoring events which are logged.Sending Custom CommandsIt is possible to send an arbitrary command to the robot using theSendCustomCommand()call. The user can optionally provide expected response codes, which will causeSendCustomCommand()to return an event which can be used to wait for the response.Example usage:importmecademicpy.robotasmdrimportmecademicpy.mx_robot_defasmdr_def# Connect, activate, and home robot...response_codes=[mdr_def.MX_ST_ERROR_RESET,mdr_def.MX_ST_NO_ERROR_RESET]response=robot.SendCustomCommand('ResetError',expected_responses=response_codes,timeout=10)Although raw numerical response codes can also be used, it is recommended to use the named aliases provided inmx_robot_def.pyfor clarity.API ReferenceFor a complete list of available methods and further documentation, use the help() function on any class in a python terminal (such asipython).>>>importmecademicpy.robotasmdr>>>help(mdr.Robot)>>>help(mdr.Message)>>>help(mdr.RobotCallbacks)Getting HelpTo get support, you can start an issue on the Mecademic github page, issues section or send an email tosupport@mecademic.com.LicenseAll packages in this repository are licensed under the MIT license.AuthorsMecademic-Continuous work