Python library to communicate with Marty the Robot V1 and V2 by Robotical
Getting started:
1) Import Marty from the martypy library
2) Create a Marty object that connects the way you want
3) Tell your Marty to dance
from martypy import Marty
my_marty = Marty("wifi","192.168.0.53")
my_marty.dance()
The tags 1️⃣ and 2️⃣ indicate when the method is available for Marty V1 1️⃣ and Marty V2 2️⃣
class Marty(object)
| __init__(method: str, locator: str = "", extra_client_types: dict = dict(), blocking: Union[bool, None] = None, *args, **kwargs) -> None
Start a connection to Marty 1️⃣ 2️⃣
For example:
Blocking Mode
Each command that makes Marty move (e.g. walk(), dance(), move_joint(), but also hold_position()) comes with two modes - blocking and non-blocking.
Issuing a command in blocking mode will make your program pause until Marty physically stops moving. Only then the next line of your code will be executed.
In non-blocking mode, each movement command simply tells Marty what to do and returns immediately, meaning that your code will continue to execute while Marty is moving.
Every movement command takes an optional blocking argument that can be used to choose the mode for that call. If you plan to use the same mode all or most of the time, it is better to to use the Marty.set_blocking() method or use the blocking constructor argument. The latter defaults to True (blocking) if not provided.
Arguments:
Raises:
| dance(side: str = 'right', move_time: int = 3000, blocking: Optional[bool] = None) -> bool
Boogie, Marty! 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| celebrate(move_time: int = 4000, blocking: Optional[bool] = None) -> bool
Coming soon! Same as wiggle() for now. 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| wiggle(move_time: int = 4000, blocking: Optional[bool] = None) -> bool
Wiggle 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| circle_dance(side: str = 'right', move_time: int = 2500, blocking: Optional[bool] = None) -> bool
Circle Dance 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| walk(num_steps: int = 2, start_foot: str = 'auto', turn: int = 0, step_length: int = 25, move_time: int = 1500, blocking: Optional[bool] = None) -> bool
Make Marty walk 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| get_ready(blocking: Optional[bool] = None) -> bool
Move Marty to the normal standing position and wiggle eyebrows 1️⃣ 2️⃣ Will also enable motors for Marty v1 1️⃣
Arguments:
Returns:
True if Marty accepted the request
| stand_straight(move_time: int = 2000, blocking: Optional[bool] = None) -> bool
Move Marty to the normal standing position 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| eyes(pose_or_angle: Union[str, int], move_time: int = 1000, blocking: Optional[bool] = None) -> bool
Move the eyes to a pose or an angle 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| kick(side: str = 'right', twist: int = 0, move_time: int = 2500, blocking: Optional[bool] = None) -> bool
Kick one of Marty's feet 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| arms(left_angle: int, right_angle: int, move_time: int, blocking: Optional[bool] = None) -> bool
Move both of Marty's arms to angles you specify 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| lean(direction: str, amount: Optional[int] = None, move_time: int = 1000, blocking: Optional[bool] = None) -> bool
Lean over in a direction 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| sidestep(side: str, steps: int = 1, step_length: int = 35, move_time: int = 1000, blocking: Optional[bool] = None) -> bool
Take sidesteps 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| play_sound(name_or_freq_start: Union[str,int], freq_end: Optional[int] = None, duration: Optional[int] = None) -> bool
Play a named sound (Marty V2 2️⃣) or make a tone (Marty V1 1️⃣)
Arguments:
Returns:
True if Marty accepted the request
def play_mp3(filename: str, progress_callback: Callable[[int, int], bool] = None) -> bool
Play an mp3 file on the robot. 2️⃣
Arguments:
def send_file(filename: str, progress_callback: Callable[[int, int], bool] = None, file_dest: str = "fs") -> bool
Send a file to Marty. 2️⃣
Arguments:
Returns:
True if the file was sent successfully Throws: - OSError - operating system exceptions May throw other exceptions so include a general exception handler
| get_accelerometer(axis: Optional[str] = None) -> float
Get the latest value from the Marty's accelerometer 1️⃣ 2️⃣
Arguments:
Returns:
Raises:
MartyCommandException if the axis is unknown
| is_moving() -> bool
Check if Marty is moving 2️⃣
Arguments:
none
Returns:
True if Marty is moving
| stop(stop_type: Optional[str] = None) -> bool
Stop Marty's movement 1️⃣ 2️⃣
You can also control what way to “stop” you want with the parameter stop_type. For instance:
Arguments:
Raises:
MartyCommandException if the stop_type is unknown
| resume() -> bool
Resume Marty's movement after a pause 2️⃣
Returns:
True if Marty accepted the request
| hold_position(hold_time: int, blocking: Optional[bool] = None) -> bool
Hold Marty at its current position 2️⃣
Arguments:
hold_time, time to hold position in milli-seconds - blocking - Blocking mode override; whether to wait for physical movement to finish before returning. Defaults to the value returned by self.is_blocking(). Holding position counts as movement because Marty is using its motors to actively resist any attempts to move its joints.
Returns:
True if Marty accepted the request
| is_paused() -> bool
Check if Marty is paused 2️⃣
Returns:
True if Marty is paused
| is_blocking() -> bool
Check the default movement command behaviour of this Marty. 1️⃣ 2️⃣
Returns:
True if movement commands block by default
| set_blocking(blocking: bool)
Change whether movement commands default to blocking or non-blocking behaviour for this Marty. 1️⃣ 2️⃣
The blocking behaviour can also be specified on a per-command basis using the blocking= argument which takes precedence over Marty's overall setting.
Arguments:
| move_joint(joint_name_or_num: Union[int, str], position: int, move_time: int, blocking: Optional[bool] = None) -> bool
Move a specific joint to a position 1️⃣ 2️⃣
Arguments:
Returns:
True if Marty accepted the request
Raises:
MartyCommandException if the joint_name_or_num is unknown
| get_joint_position(joint_name_or_num: Union[int, str]) -> float
Get the position (angle in degrees) of a joint 2️⃣
Arguments:
Returns:
Angle of the joint in degrees
Raises:
MartyCommandException if the joint_name_or_num is unknown
| get_joint_current(joint_name_or_num: Union[int, str]) -> float
Get the current (in milli-Amps) of a joint 1️⃣ 2️⃣ This can be useful in detecting when the joint is working hard and is related to the force which the joint's motor is exerting to stay where it is
Arguments:
Returns:
the current of the joint in milli-Amps (this will be 0 if the joint current is unknown)
Raises:
MartyCommandException if the joint_name_or_num is unknown
| get_joint_status(joint_name_or_num: Union[int, str]) -> int
Get information about a joint 2️⃣ This can be helpful to find out if the joint is working correctly and if it is moving at the moment, etc
Arguments:
Returns:
a code number which is the sum of codes in the Marty.JOINT_STATUS dictionary will be 0 if the joint status is unknown
Raises:
MartyCommandException if the joint_name_or_num is unknown
| get_distance_sensor() -> Union[int, float]
Get the latest value from the distance sensor 1️⃣ 2️⃣
Returns:
The distance sensor reading. The meaning of the returned value is different between Marty V1 and V2: - 1️⃣ Returns a raw distance sensor reading as a float. - 2️⃣ Returns the distance in millimeters as int. Both will return 0 if no distance sensor is found.
| foot_on_ground(add_on_or_side: str) -> bool
Checks whether the foot is on a surface 2️⃣
Arguments:
Returns:
A boolean for whether the addon detects the ground. True for ground detected, False otherwise.
| foot_obstacle_sensed(add_on_or_side: str) -> bool
Checks whether there is an obstacle in front of the foot 2️⃣
Arguments:
Returns:
A boolean for whether the addon detects and obstacle. True for obstacle detected, False otherwise.
| get_obstacle_sensor_reading(add_on_or_side: str) -> int
Gets a raw obstacle sensor reading from an IR or color sensor 2️⃣
Arguments:
Returns:
Raw reading of obstacle sensor data from the add on.
| get_ground_sensor_reading(add_on_or_side: str) -> int
Gets a raw ground sensor reading from an IR or color sensor 2️⃣
Arguments:
Returns:
Raw reading of ground sensor data from the add on.
| get_battery_remaining() -> float
Get the battery remaining percentage 2️⃣
Returns:
The battery remaining capacity in percent
| save_calibration() -> bool
Set the current motor positions as the zero positions 1️⃣ 2️⃣
BE CAREFUL, this can cause unexpected movement or self-interference
| clear_calibration() -> bool
Mark the current calibration as invalid 1️⃣ 2️⃣
This has no immediate physical effect. Marty will still remember the last calibration but will report that it needs to be calibrated again. (You may notice that a “Calibrate” button appears in the app for example.)
| is_calibrated() -> bool
Check if Marty is calibrated 2️⃣
| get_robot_status() -> Dict
Get status of Marty the Robot 2️⃣
Arguments:
none
Returns:
Dictionary containing: “workQCount” number of work items (movements) that are queued up - "isMoving" - True if Marty is moving - "isPaused" - True if Marty is paused - "isFwUpdating" - True if Marty is doing an update
| get_joints() -> Dict
Get information on all of Marty's joints 2️⃣
Arguments:
none
Returns:
Dictionary containing dictionaries (one for each joint) each of which contain: - "IDNo" - the joint identification number (see Marty.JOINT_IDS) - "name" - the name of the joint - "pos" - the angle of the joint - "current" - the joint current (in milli-Amps) - "enabled" - True if the servo is enabled - "commsOK" - True if the servo is communicating ok - "flags" - joint status flags (see Marty.JOINT_STATUS)
| get_power_status() -> Dict
Get information on Marty's battery and power supply 2️⃣
Arguments:
none
Returns:
Dictionary containing: - "battRemainCapacityPercent" - remaining battery capacity in percent - "battTempDegC" - battery temperature in degrees C - "battRemainCapacityMAH" - remaining battery capacity in milli-Amp-Hours - "battFullCapacityMAH" - capacity of the battery when full in milli-Amp-Hours - "battCurrentMA" - current the battery is supplying (or being charged with) milli-Amps - "power5VOnTimeSecs" - number of seconds the power to joints and add-ons has been on - "powerUSBIsConnected" - True if USB is connected - "power5VIsOn" - True if power to the joints and add-ons is turned on
Other values for internal use
Note: Some keys may not be included if Marty reports that the corresponding information is not available.
| get_add_ons_status() -> Dict
Get latest information for all add-ons 2️⃣
Arguments:
none
Returns:
Dictionary containing dictionaries (one for each add-on) each of which contain: - "IDNo" - the add-on identification number - "name" - the name of the add-on - "type" - the type of the add-on (see Marty.ADD_ON_TYPE_NAMES but it may not be in this list) - "whoAmITypeCode" - a code which can be used for further add-on identification - "valid" - True if the data is valid - "data" - 10 bytes of data from the add-on - the format of this data depends on the type of add-on
| get_add_on_status(add_on_name_or_id: Union[int, str]) -> Dict
Get latest information for a single add-on 2️⃣
Arguments:
Returns:
Dictionary containing: - "IDNo" - the add-on identification number - "valid" - True if the data is valid - "data" - 10 bytes of data from the add-on - the format of this data depends on the type of add-on
| add_on_query(add_on_name: str, data_to_write: bytes, num_bytes_to_read: int) -> Dict
Write and read an add-on directly (raw-mode) 2️⃣
Arguments:
Returns:
Dict with keys including: “rslt” - the result which will be “ok” if the query succeeded “dataRead” - the data read from the add-on
| get_system_info() -> Dict
Get information about Marty 2️⃣
Arguments:
none
Returns:
Dictionary containing: - "HardwareVersion" - string containing the version of Marty hardware “1.0” for Marty V1 “2.0” for Marty V2 other values for later versions of Marty - "SystemName" - the name of the physical hardware in Marty - this will be RicFirmwareESP32 for Marty V2 and MartyV1 for Marty V1 - "SystemVersion" - a string in semantic versioning format with the version of Marty firmware (e.g. “1.2.3”) - "SerialNo" - serial number of this Marty - "MAC" - the base MAC address of the Marty - "RicHwRevNo" - the revision number of the RIC hardware
| set_marty_name(name: str) -> bool
Set Marty's name 2️⃣
Arguments:
name to call Marty
Returns:
True if successful in setting the name
| get_marty_name() -> str
Get Marty's name 2️⃣
Arguments:
none
Returns:
the name given to Marty
| is_marty_name_set() -> bool
Check if Marty's name is set 2️⃣
Arguments:
none
Returns:
True if Marty's name is set
| get_hw_elems_list() -> List
Get a list of all of the hardware elements on Marty 2️⃣
Arguments:
none
Returns:
List containing a dictionary for each hardware element, each element is in the form: - "name" - name of the hardware element - "type" - type of element, see Marty.HW_ELEM_TYPES, other types may appear as add-ons - "busName" - name of the bus the element is connected to - "addr" - address of the element if it is connected to a bus - "addrValid" - 1 if the address is valid, else 0 - "IDNo" - identification number of the element - "whoAmI" - string from the hardware which may contain additional identification - "whoAmITypeCode" - string indicating the type of hardware - "SN" - serial number of the hardware element - "versionStr" - version string of hardware element in semantic versioning (semver) format - "commsOK" - 1 if the element is communicating ok, 0 if not
| send_ric_rest_cmd(ricRestCmd: str) -> None
Send a command in RIC REST format to Marty 2️⃣
This is a special purpose command which you can use to do advanced control of Marty
Arguments:
Returns:
None
| send_ric_rest_cmd_sync(ricRestCmd: str) -> Dict
Send a command in RIC REST format to Marty and wait for reply 2️⃣
This is a special purpose command which you can use to do advanced control of Marty
Arguments:
Returns:
Dictionary containing the response received from Marty
| get_motor_current(motor_id: int) -> float
Get current flowing through a joint motor 1️⃣ 2️⃣
Arguments:
motor_id, integer >= 0 (non-negative) selects which motor to query
Returns:
Instantaneous current sense reading from motor motor_id
| is_conn_ready() -> bool
Check if the robot is connected and the connection is ready to accept commands 2️⃣
Arguments:
None
Returns:
True if the robot is connected and ready
| disco_off(add_on: Union[Disco, str] = Disco.ALL) -> bool
Turn disco add on LEDs off 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| disco_pattern(pattern: int, add_on: Union[Disco, str] = Disco.ALL) -> bool
Turn on a pattern of lights on the disco LED add on 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| disco_color(color: Union[str, Tuple[int, int, int]] = 'white', add_on: Union[Disco, str] = Disco.ALL, region: Union[int, str] = 'all') -> bool
Turn on disco add on LED lights to a specific color 2️⃣
Arguments:
Returns:
True if Marty accepted the request
| enable_motors(enable: bool = True, clear_queue: bool = True) -> bool
Toggle power to motors 1️⃣
Arguments:
| enable_safeties(enable: bool = True) -> bool
Tell the board to turn on 'normal' safeties 1️⃣
| fall_protection(enable: bool = True) -> bool
Toggle fall protections 1️⃣
Arguments:
| motor_protection(enable: bool = True) -> bool
Toggle motor current protections 1️⃣
Arguments:
| battery_protection(enable: bool = True) -> bool
Toggle low battery protections 1️⃣
Arguments:
| buzz_prevention(enable: bool = True) -> bool
Toggle motor buzz prevention 1️⃣
Arguments:
| lifelike_behaviour(enable: bool = True) -> bool
Tell the robot whether it can or can't move now and then in a lifelike way when idle. 1️⃣
Arguments:
| ros_command(*byte_array: int) -> bool
Low level proxied access to the ROS Serial API between the modem and main controller 1️⃣
| keyframe(time: float, num_of_msgs: int, msgs) -> List[bytes]
Takes in information about movements and generates keyframes returns a list of bytes 1️⃣
Arguments:
| get_chatter() -> bytes
Return chatter topic data (variable length) 1️⃣
| get_firmware_version() -> bool
Ask the board to print the firmware version over chatter 1️⃣
| ros_serial_formatter(topicID: int, send: bool = False, *message: int) -> List[int]
Formats message into ROS serial format and returns formatted message as a list 1️⃣
Calls ros_command with the processed message if send is True. More information about the ROS serial format can be found here: http://wiki.ros.org/rosserial/Overview/Protocol
| pinmode_gpio(gpio: int, mode: str) -> bool
Configure a GPIO pin 1️⃣
Arguments:
| write_gpio(gpio: int, value: int) -> bool
Write a value to a GPIO port 1️⃣
| digitalread_gpio(gpio: int) -> bool
Read from GPIO 1️⃣
Arguments:
GPIO pin number, >= 0 (non-negative)
Returns:
Returns High/Low state of a GPIO pin
| set_parameter(*byte_array: int) -> bool
Set board parameters 1️⃣
Arguments:
| i2c_write(*byte_array: int) -> bool
Write a bytestream to the i2c port. 1️⃣
The first byte should be the address, following from that the datagram folows standard i2c spec
| i2c_write_to_ric(address: int, byte_array: bytes) -> bool
Write a formatted bytestream to the i2c port. 1️⃣
The bytestream is formatted in the ROS serial format.
address: the other device's address
| i2c_write_to_rick(address: int, byte_array: bytes) -> bool
Write a formatted bytestream to the i2c port. 1️⃣
The bytestream is formatted in the ROS serial format. address: the other device's address
| get_battery_voltage() -> float
Get the voltage of the battery 1️⃣
Returns:
The battery voltage reading as a float in Volts
| hello(blocking: Optional[bool] = None) -> bool
Zero joints and wiggle eyebrows 1️⃣
Arguments:
| discover() -> List[str]
Try and find us some Martys! 1️⃣
You probably won't need to use these directly.
| __del__() -> None
Marty is stopping
| close() -> None
Close connection to Marty