Package: pulse-api
Pulse Robot Python APIThis folder containsPythonwrapper for thePulse RobotREST API.
Tested with Python 3. Compatibility with Python 2 is not guaranteed but the underlying API (calledpdhttp)
supports Python 2.Pulse Robot Python APIRequirementsInstallationSoftware compatibility tableGetting startedQuickstartAPI initializationMotion controlFreedrive modeControlling accessories and signalsControlling accessories and signals during trajectory executionTool APIBase APIEnvironment APIException handlingVersions APIDocumentation and further informationDocumentation and further informationRequirementsPython 3.5+InstallationTo install from thePython Package Index:pip3 install pulse-apior, for a specific versionpip3 install pulse-api==v1.v2.v3Alternatively, to get the version from our repository, use the following
command:pip3 install pulse-api -i https://pip.rozum.com/simpleTo install a specific version:pip3 install pulse-api==v1.v2.v3 -i https://pip.rozum.com/simplewherev1,v2, andv3(e.g., pulse-api==1.4.3) are version numbers as listed below in the compatibility table.Note:To install the underlying API (pdhttp), use:pip3 install pdhttp -i https://pip.rozum.com/simpleSoftware compatibility tableChangelogPulse Desk UI versionPython API version1.4.31.4.31.4.41.4.41.5.0, 1.5.1, 1.5.21.5.01.6.01.6.01.7.01.7.0, 1.7.11.8.0, 1.8.11.8.0, 1.8.11.8.2, 1.8.3, 1.8.41.8.4Getting startedExamples use the latest version of the library.QuickstartWARNING!Before launching this example, make sure that there are no facilities
within 0.6 meters around the manipulator.importmathfrompulseapiimportRobotPulse,pose,position,PulseApiException,MT_LINEARhost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)# create an instance of the API wrapper class# create motion targetshome_pose=pose([0,-90,0,-90,-90,0])start_pose=pose([0,-90,90,-90,-90,0])pose_targets=[pose([10,-90,90,-90,-90,0]),pose([10,-90,0,-90,-90,0]),]position_target=position([-0.42,-0.12,0.35],[math.pi,0,0])position_targets=[position([-0.37,-0.12,0.35],[math.pi,0,0]),position([-0.42,-0.12,0.35],[math.pi,0,0]),position([-0.42,-0.17,0.35],[math.pi,0,0]),position([-0.37,-0.17,0.35],[math.pi,0,0]),]# set the desired speed (controls both motor velocity and acceleration)SPEED=30# set the desired motor velocityVELOCITY=40# set the desired motor accelerationACCELERATION=50# set the desired tcp velocityTCP_VELOCITY_1CM=0.01TCP_VELOCITY_10CM=0.1whileTrue:try:robot.set_pose(home_pose,speed=SPEED)# checks every 0.1 s whether the motion is finishedrobot.await_stop()robot.set_pose(start_pose,velocity=VELOCITY,acceleration=ACCELERATION)robot.await_stop()robot.set_position(position_target,velocity=VELOCITY,acceleration=ACCELERATION)robot.await_stop()# command the robot to go through multiple position waypoints# (execute a trajectory)robot.run_positions(position_targets,SPEED)robot.await_stop()# set the linear motion typerobot.run_positions(position_targets,velocity=VELOCITY,acceleration=ACCELERATION,motion_type=MT_LINEAR,)robot.await_stop()# limit the TCP velocity not to exceed 0.01 m/s (1 cm/s)robot.run_positions(position_targets,tcp_max_velocity=TCP_VELOCITY_1CM,motion_type=MT_LINEAR,)# checks every 0.5 s whether the motion is finishedrobot.await_stop(0.5)# limit the TCP velocity not to exceed 0.1 m/s (10 cm/s)robot.run_poses(pose_targets,tcp_max_velocity=TCP_VELOCITY_1CM)exceptPulseApiExceptionase:# handle possible errorsprint("Exception{}while calling robot at{}".format(e,robot.host))breakBack to the table of contentsAPI initializationfrompulseapiimportRobotPulse# create an instance of the API wrapper classhost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)Back to the table of contentsMotion controlPossible motion targets:Positions (run_linear_positions,set_position,run_positionsandget_positionmethods) - to control
the location of the robot's TCP (tool center point). Use thepositionhelper function to create a
motion targets.Poses (run_linear_poses,set_pose,run_posesandget_posemethods) - to control motor angles.
Use theposehelper function to create a motion targets.Jogging (joggingmethod) - enter the 'jogging' mode. If the robotic arm
already in the 'jogging' mode, use this method to control the direction of the movement.
Usejoghelper function to create motion target.
The motion target has six components ('x', 'y', 'z', 'rx', 'ry', 'rz').
Components are optional with default value equal to 0. Components control
accelerations along the corresponding axis relative to thebasecoordinate
system of the robotic arm. To disable the mode, passjogmotion target, where
all components are zeros.Possible motion types:Joint (MT_JOINT, default)Linear (MT_LINEAR)Auxiliary methods:await_motion- periodically requests robot status (default: every 0.1 s) and
waits until the robot finishes movements.Deprecated, use await_stopawait_stop- periodically requests robot status (default: every 0.1 s) and
waits until the robot finishes movements.status_motion- returns the actual state of the robotic arm: running (arm in motion),
idle (arm not in motion), in the zero gravity mode, or in error state.Deprecated, use statusstatus- returns the actual state of the robotic arm - whether it is
initializing, or twisted, or running (in motion), or active (not in motion), or
in the zero gravity mode, or failed (broken, failed initializing or in emergency).freeze- sets the arm in the "freeze" state.
The arm stops moving, retaining its last position.Note:In the state, it is not advisable to move the arm by hand as this
can cause damage to its components.relax-  sets the arm in the "relaxed" state. The arm stops
moving without retaining its last position. In this state, the user can move the
robotic arm by hand (e.g., to verify/test a motion trajectory).pack- asking the arm to reach a compact pose for transportation.status_motors- returns the actual states of the six servo motors integrated
into the joints of the robotic arm.stop- sets the arm in theProtection mode. The arm stops moving,
retaining its last position and is disabled for command execution untilrecoveris called.WARNING!The following example is sample code. Before running, you must
replace reference motion targets in the sample with the ones applicable to
your specific case. Before launching this example, make sure that manipulator
would not cause any damage to your facilities.importmathimporttimefrompulseapiimportposition,pose,RobotPulse,MT_LINEAR,SystemState,joghost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)# create motion targetspose_target=pose([0,-90,90,-90,-90,0])position_target=position([-0.42,-0.12,0.35],[math.pi,0,0])position_targets=[position([-0.37,-0.12,0.35],[math.pi,0,0]),position([-0.42,-0.12,0.35],[math.pi,0,0]),position([-0.42,-0.17,0.35],[math.pi,0,0]),position([-0.37,-0.17,0.35],[math.pi,0,0]),]SPEED=30# set the desired speedTCP_VELOCITY_1CM=0.01# use the status command as shown belowdefmy_await_stop(robot_instance,asking_interval=0.1):status=robot_instance.status()whilestatus==SystemState.MOTION:time.sleep(asking_interval)status=robot_instance.status()robot.set_pose(pose_target,SPEED)robot.await_stop()# checks every 0.1 s whether the motion is finishedprint("Current pose:\n{}".format(robot.get_pose()))robot.set_position(position_target,SPEED)robot.await_stop(0.5)# checks every 0.5 s whether the motion is finishedprint("Current position:\n{}".format(robot.get_position()))# command the robot to go through multiple position waypoints# (execute a trajectory)robot.run_positions(position_targets,SPEED)my_await_stop(robot)# set the linear motion typerobot.run_positions(position_targets,SPEED,motion_type=MT_LINEAR)robot.await_stop()# limit the TCP velocity not to exceed 0.01 m/s (1 cm/s)robot.run_positions(position_targets,tcp_max_velocity=TCP_VELOCITY_1CM,motion_type=MT_LINEAR)robot.await_stop()# stop the arm in the last positionrobot.freeze()# get status from motorsprint(robot.status_motors())# jogging example# command the robot to execute preparatory motion targetsrobot.set_pose(pose([0,-90,0,-90,-90,0]),SPEED)robot.set_position(position([-0.45,-0,0.33],[math.pi,0,0]),SPEED)robot.await_stop()# start the jogging mode and execute motion targetsrobot.jogging(jog(x=-1,y=-1))time.sleep(2)robot.jogging(jog(x=1,y=1))time.sleep(7)robot.jogging(jog(rx=1,rz=-1))time.sleep(5)robot.jogging(jog(-0.1,-0.8,0.1,0,-1,0.7))time.sleep(5)# disable the jogging moderobot.jogging(jog())The following example demonstrates usage of therun_linear_positionsandrun_linear_posesmethods.Note:the arm must be
in the first position (pose) of the trajectory before usage.importmathfrompulseapiimport(RobotPulse,pose,LinearMotionParameters,position,InterpolationType,)host="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)# create an instance of the API wrapper classSPEED=25VELOCITY=0.3# in meters per secondACCELERATION=0.2# in meters per second squaredBLEND=0.01# in meters - radius of maximum deviation from the trajectory pointHOME_POSE=pose([0,-90,0,-90,0,0])TARGET_POSITIONS=[position([-0.35,0.3,0.45],[math.pi,0.1,1.57],blend=BLEND),position([-0.35,-0.3,0.45],[math.pi,0,0],blend=BLEND),position([-0.35,-0.3,0.5],[math.pi,0,0],blend=BLEND),position([-0.35,0.3,0.5],[math.pi,0.1,1.57],blend=BLEND),]TARGET_POSES=[pose([130,-85,-109,-56,90,8],blend=BLEND),pose([120,-85,-113,-17,90,8],blend=BLEND),pose([100,-93,-104,-26,89,8],blend=BLEND),pose([130,-85,-109,-56,90,8],blend=BLEND),]linear_motion_parameters=LinearMotionParameters(interpolation_type=InterpolationType.BLEND,velocity=VELOCITY,acceleration=ACCELERATION,)robot.set_pose(HOME_POSE,SPEED)robot.set_position(TARGET_POSITIONS[0],SPEED)robot.await_stop()robot.run_linear_positions(TARGET_POSITIONS,linear_motion_parameters,)robot.await_stop()robot.set_pose(TARGET_POSES[0],SPEED)robot.await_stop()robot.run_linear_poses(TARGET_POSES,linear_motion_parameters,)robot.await_stop()Back to the table of contentsFreedrive modeFreedrive ("Zero-gravity") mode is intended to be used when there is a need
to control the robotic arm directly "by-hand". With this functionality, for
example, the user can develop an application that remembers user defined path.
After mode activation, you can press and hold specific button that is described
in user manual and move the robotic arm "by-hand".frompulseapiimportRobotPulsehost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)# enter freedrive moderobot.zg_on()# additional logic goes here# disable freedrive moderobot.zg_off()Back to the table of contentsControlling accessories and signalsAvailable methods:close_gripper,open_gripperwith a preset timeout before executing further commands (default: 500 ms).
Supported grippers: Schunk and OnRobot.disable_gripperandenable_gripper. Use this methods to disable (enable) power supply on wrist for gripper so
that you can safely unplug and change gripper without powering off the robotic armset_digital_output_highset_digital_output_low,get_digital_output- to work with output ports on the controlbox.get_digital_inputto work with input ports on the controlbox.bind_stopbindsstopcommand to high or low input signal on a specific port.Signals:SIG_LOW - port is inactiveSIG_HIGH - port is activefrompulseapiimportRobotPulse,SIG_LOW,SIG_HIGHhost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)# ask the robot to close the gripper and continue execution of# commands after 500 msrobot.close_gripper()# ask the robot to open the gripper and begin to execute further# commands after 100 msrobot.open_gripper(100)# set the first output port to the active staterobot.set_digital_output_high(1)# execute required operations when input port 3 is activeifrobot.get_digital_input(3)==SIG_HIGH:print("Input port 3 is active")# execute required operations when input port 1 is inactiveifrobot.get_digital_input(1)==SIG_LOW:print("Input port 1 is inactive")# execute stop() command if input singnal is HIGH on input port 4robot.bind_stop(4,SIG_HIGH)Back to the table of contentsControlling accessories and signals during trajectory executionUseoutput_action(),open_gripper_action(),close_gripper_action()functions combined withpose()andposition()helper functions to control gripper/output signals during trajectory
execution.Note:actions are performed asynchronously.frompulseapiimport(RobotPulse,SIG_LOW,SIG_HIGH,output_action,position,open_gripper_action,close_gripper_action,)host="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)# create motion targets with actions# ask the robot to set output signal to SIG_LOW value on port 1# when it reaches the specified posepose_target=pose([0,-90,90,-90,-90,0],[output_action(1,SIG_LOW)])# ask the robot to set output signal to SIG_HIGH value on port 1# when it reaches the specified positionposition_target=position([-0.42,-0.12,0.35],[math.pi,0,0],[output_action(1,SIG_HIGH)])position_targets=[# ask the robot to open gripper at the specified positionposition([-0.37,-0.12,0.35],[math.pi,0,0],[close_gripper_action()]),position([-0.42,-0.12,0.35],[math.pi,0,0]),position([-0.42,-0.17,0.35],[math.pi,0,0]),# ask the robot to close gripper at the specified position and# to set output signal to SIG_LOW value on port 1 at the specified positionposition([-0.37,-0.17,0.35],[math.pi,0,0],[open_gripper_action(),output_action(1,SIG_LOW),]),]SPEED=30# set the desired speedrobot.set_pose(pose_target,SPEED)robot.await_stop()robot.set_position(position_target,SPEED)robot.await_stop()robot.run_positions(position_targets,SPEED)robot.await_stop()Back to the table of contentsTool APIUse the Tool API methods when you need to calculate a robot motion trajectory with
regard to the used tool and to take the tool into account when the robot calculates collisions.Available methods:change_tool_info- set tool info for trajectory calculations.change_tool_shape- set tool shape for collision validation.get_tool_info,get_tool_shape- receive information about current tool settings.Helper functions:tool_info- creates a tool info instance to be passed intochange_tool_infomethod.tool_shape- creates a tool shape instance to be passed intochange_tool_shapemethod.frompulseapiimportRobotPulse,position,Pointfrompulseapiimportcreate_simple_capsule_obstacle,tool_shape,tool_infohost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)# get info about the current toolcurrent_tool_info=robot.get_tool_info()current_tool_shape=robot.get_tool_shape()print("Current tool info\n{}".format(current_tool_info))print("Current tool shape\n{}".format(current_tool_shape))# create new tool propertiesnew_tool_info=tool_info(position([0,0,0.07],[0,0,0]),name="CupHolder")new_tool_shape=tool_shape([create_simple_capsule_obstacle(0.03,Point(0,0,0),Point(0,0,0.07))])# change tool propertiesrobot.change_tool_info(new_tool_info)robot.change_tool_shape(new_tool_shape)print("New tool info\n{}".format(robot.get_tool_info()))print("New tool shape\n{}".format(robot.get_tool_shape()))Back to the table of contentsBase APIUse the Base API methods when you need to calculate a robot motion trajectory
relative to a specific point in space.Available methods:change_baseget_basefrompulseapiimportRobotPulse,positionhost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)current_base=robot.get_base()print("Current base\n{}".format(current_base))# move the new base point along x and y axesnew_base=position([0.05,0.05,0],[0,0,0])robot.change_base(new_base)print("New base\n{}".format(robot.get_base()))Back to the table of contentsEnvironment APIUse the Environment API to add virtual obstacles to be taken into account when calculating collisions.Available methods:add_to_environment- adds an obstacle to an environment. Use the helper functions below
to describe obstacles.get_all_from_environment- returns all obstacles from an environment.get_from_environment_by_name-  returns an obstacle with a specific name from an environment.remove_all_from_environment- removes all obstacles from an environment.remove_from_environment_by_name-  removes an obstacle with a specific name from an environment.Helper functions:create_box_obstaclecreate_capsule_obstaclecreate_plane_obstaclefrompulseapiimportRobotPulse,Point,positionfrompulseapiimport(create_plane_obstacle,create_box_obstacle,create_capsule_obstacle,)host="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)print("Current environment\n{}".format(robot.get_all_from_environment()))# add obstacles to the environment for calculating collisionsbox=create_box_obstacle(Point(0.1,0.1,0.1),position((1,1,1),(0,0,0)),"example_box")capsule=create_capsule_obstacle(0.1,Point(0.5,0.5,0.2),Point(0.5,0.5,0.5),"example_capsule")plane=create_plane_obstacle([Point(-0.5,0.4,0),Point(-0.5,0,0),Point(-0.5,0,0.1)],"example_plane",)robot.add_to_environment(box)robot.add_to_environment(capsule)robot.add_to_environment(plane)print("New environment\n{}".format(robot.get_all_from_environment()))print("Get example box\n{}".format(robot.get_from_environment_by_name(box.name)))# remove specific obstaclesrobot.remove_from_environment_by_name(box.name)print("Environment without box\n{}".format(robot.get_all_from_environment()))# remove all obstacles from an environmentrobot.remove_all_from_environment()print("Empty environment\n{}".format(robot.get_all_from_environment()))Back to the table of contentsException handlingFor information about errors, see theAPI reference.
The client wraps errors from the robot intoPulseApiException.Available methods:recover- the function recovers the arm after an emergency, setting its motion status to IDLE.
Recovery is possible only after an emergency that is not fatal (corresponds
to the ERROR status).status_failure- the method  returns complete list of recent failures. Each
list entry could contain failure message, type, level and datetime. This
information could be used for error handling or incident investigation.For example, we can trigger an API exception by sendingposeintoset_positionmethod.frompulseapiimportRobotPulse,PulseApiException,pose,SystemStatehost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)try:robot.set_position(pose([0,-90,90,-90,-90,0]),10)robot.await_stop()exceptPulseApiExceptionase:print("Exception{}while calling robot at{}".format(e,robot.host))status=robot.status()failure=robot.status_failure()ifstatus==SystemState.EMERGENCY:print("Robot in emergency. Error message:{}".format(failure))If the robotic arm went into "EMERGENCY" state, you can attemt to "recover" the
arm in order to continue operations execution:frompulseapiimportRobotPulse,PulseApiException,pose,SystemStatehost="http://127.0.0.1:8081"# replace with a valid robot addressrobot=RobotPulse(host)recover_result=robot.recover()print("Recover result:{}".format(recover_result))Back to the table of contentsVersions APIUse the Version API methods to get information about the software and hardware versions.
You may need to use the methods for contacting support specialists when you notice
strange robot behaviour.Available methods:hardware- returns the hardware versions for all motors, the USB-CAN dongle, safety board and wrist.software- returns the software version for all motors, the USB-CAN dongle, safety board and wrist.robot_software- returns the version of the robot control software.frompulseapiimportVersionshost="http://127.0.0.1:8081"# replace with a valid robot addressversions=Versions(host)print(versions.hardware())print(versions.software())print(versions.robot_software())Back to the table of contentsDocumentation and further informationFor further details, see theAPI reference guide.