def example_manipulation_protobuf_list(): # In protobuf, list are called repeated once they are affected to a python # variable they can be used as a normal list. # Take note that a repeated message field doesn't have an append() function, it has an # add() function that create the new message object. # For this example we will use those two messages # message Sequence { # SequenceHandle handle = 1 # string name = 2 # string application_data = 3 # repeated SequenceTask tasks = 4 # } # message SequenceTask { # uint32 group_identifier = 1; # Action action = 2; # string application_data = 3; # } # To keep a clearer example the attribute action in SequenceTask message will be keep to default value # Here's 2 way to add to a repeated message field # Create the parent message sequence = Base_pb2.Sequence() sequence.name = "Sequence" # The extend way sequence_task_1 = Base_pb2.SequenceTask() sequence_task_1.group_identifier = 10 action = sequence_task_1.action action = Base_pb2.Action() # Using Action default constructor sequence.tasks.extend([sequence_task_1]) # Extend expect an iterable # Created for the add() function unique to repeated message field sequence_task_2 = sequence.tasks.add() sequence_task_2.group_identifier = 20 action = sequence_task_2.action action = Base_pb2.Action() # Using Action default constructor # Since sequence.task is a list we can use all the python toolset to # loop, iterate, interogate and print element in that list for i in range(len(sequence.tasks)): print("sequence ID with index : {0}".format( sequence.tasks[i].group_identifier)) # The list still have the iterator proprety of python list so you can directly iterate # throught element without creating a iterator like previous example for task in sequence.tasks: print("sequence ID with object iterator : {0}".format( task.group_identifier))
def example_manipulation_protobuf_list(): # In Google Protocol Buffer, 'repeated' is used to designate a list of indeterminate length. Once affected to a Python # variable they can be used in the same way as a standard list. # Note that a repeated message field doesn't have an append() function, it has an # add() function that create the new message object. # For this example we will use the following two messages # message Sequence { # SequenceHandle handle = 1 # string name = 2 # string application_data = 3 # repeated SequenceTask tasks = 4 # } # message SequenceTask { # uint32 group_identifier = 1; # Action action = 2; # string application_data = 3; # } # For a clearer example the attribute action in SequenceTask message will be kept to default value # Here's two ways to add to a repeated message field # Create the parent message sequence = Base_pb2.Sequence() sequence.name = "Sequence" # The 'extend' way sequence_task_1 = Base_pb2.SequenceTask() sequence_task_1.group_identifier = 10 action = sequence_task_1.action action = Base_pb2.Action() # Using Action default constructor sequence.tasks.extend([sequence_task_1]) # Extend expect an iterable # Created for the add() function unique to repeated message field sequence_task_2 = sequence.tasks.add() sequence_task_2.group_identifier = 20 action = sequence_task_2.action action = Base_pb2.Action() # Using Action default constructor # Since sequence.task is a list we can use all the Python features to # loop, iterate, interogate and print elements in that list. for i in range(len(sequence.tasks)): print("sequence ID with index : {0}".format( sequence.tasks[i].group_identifier)) # Lists have the iterator property of a Python list, so you can directly iterate # throught element without creating a iterator as in the previous example for task in sequence.tasks: print("sequence ID with object iterator : {0}".format( task.group_identifier))
def example_manipulation_protobuf_object(): # One of the basics element in protobuf are the message. They are the main element in protobuf # just like class in python. You need a message to make workable object. A message can contain # many kind of element. For now, we have already covered the Scalar Value and in this section we # going to cover message. # A message can make a reference to another message to make more complete element # For this example I'll use the FullUserProfile and UserProfile message # message FullUserProfile { # UserProfile user_profile = 1; //User Profile, which includes username # string password = 2; //User's password # } # message UserProfile { # Kinova.Api.Common.UserProfileHandle handle = 1; //User handle (no need to be set) # string username = 2; // username, which is used to connect to robot (or login via Web App) # string firstname = 3; //user first name # string lastname = 4; //user last name # string application_data = 5; //other application data (used by Web App) # } # https://developers.google.com/protocol-buffers/docs/proto3#simple full_user_profile = Base_pb2.FullUserProfile() # Now I'll put data in the scalar value full_user_profile.password = "******" # Now I want to work with the user profile attribute which is a message itself. # Since user profile is a message you can use the . to get access # to those attribute. full_user_profile.user_profile.username = "******" full_user_profile.user_profile.firstname = "Johnny" full_user_profile.user_profile.lastname = "Cash" # Another basic element is the Enum. Enum are directly available from # the message no need to pass by the enum 'message'. # Here's a example: # enum LimitationType { # UNSPECIFIED_LIMITATION = 0; //unspecified limitation # FORCE_LIMITATION = 1; //force limitation # ACCELERATION_LIMITATION = 2; //acceleration limitation # VELOCITY_LIMITATION = 3; //velocity limitation # } # message LimitationTypeIdentifier { # LimitationType type = 1; //limitation type # } # https://developers.google.com/protocol-buffers/docs/proto3#enum limitation_type_identifier = Base_pb2.LimitationTypeIdentifier() limitation_type_identifier.type = Base_pb2.FORCE_LIMITATION
def example_notification(base_service): def notification_callback(data): print("****************************") print("* Callback function called *") print(json_format.MessageToJson(data)) print("****************************") # Subscribe to ConfigurationChange notification try: notif_handle = base_service.OnNotificationConfigurationChangeTopic( notification_callback, Base_pb2.NotificationOptions()) except KException: print("Error occured user probably already exist") except Exception: print("Error occured") # ... miscellenaous tasks !!! time.sleep(3) # Creating a user full_user_profile = Base_pb2.FullUserProfile() full_user_profile.user_profile.username = '******' full_user_profile.user_profile.firstname = 'Johnny' full_user_profile.user_profile.lastname = 'Cash' full_user_profile.user_profile.application_data = "Custom Application Stuff" full_user_profile.password = "******" try: user_profile_handle = base_service.CreateUserProfile(full_user_profile) except KException: print("User creation failed") # ... following the creation of the user_profile we should receive the ConfigurationChange notification (fct notification_callback() should be call) print("User {0} created".format(full_user_profile.user_profile.username)) # ... miscellenaous tasks !!! and to let the notification works. time.sleep(3) print("Now unsubscribe ConfigurationChange notification") base_service.Unsubscribe(notif_handle) try: print("Deleting user {0}".format( full_user_profile.user_profile.username)) base_service.DeleteUserProfile( user_profile_handle ) # Should not received notification about this modification except KException: print("User deletion failed") # ... here sleep to confirm that ConfigurationChange notification is not raised anymore after the unsubscribe time.sleep(3)
def example_manipulation_protobuf_object(): # Messages are the main element in Google Protocol Buffer in the same way classes are to Python. You need a message # to make a workable object. A message can contain many kind of elements. We have already # covered the scalar value and in this section we are going to cover the message. # # A message can make a reference to another message to make more comprehensive element. # For this example we'll use the FullUserProfile and UserProfile messages. # message FullUserProfile { # UserProfile user_profile = 1; //User Profile, which includes username. # string password = 2; //User's password # } # message UserProfile { # Kinova.Api.Common.UserProfileHandle handle = 1; // User handle (no need to be set) # string username = 2; // username, which is used to connect to robot (or via Web App login) # string firstname = 3; // user first name # string lastname = 4; // user last name # string application_data = 5; // other application data (used by Web App) # } # https://developers.google.com/protocol-buffers/docs/proto3#simple full_user_profile = Base_pb2.FullUserProfile() # Now we'll add data to the scalar full_user_profile.password = "******" # Now I want to work with the user profile attribute which is a message itself. # Since user profile is a message you can use the '.' to access # these attributes. full_user_profile.user_profile.username = "******" full_user_profile.user_profile.firstname = "Johnny" full_user_profile.user_profile.lastname = "Cash" # Another basic element is the enum. Enum are directly available from # the message - no need to use the enum 'message'. # Here's an example: # enum LimitationType { # UNSPECIFIED_LIMITATION = 0; // unspecified limitation # FORCE_LIMITATION = 1; // force limitation # ACCELERATION_LIMITATION = 2; // acceleration limitation # VELOCITY_LIMITATION = 3; // velocity limitation # } # message LimitationTypeIdentifier { # LimitationType type = 1; // limitation type # } # https://developers.google.com/protocol-buffers/docs/proto3#enum limitation_type_identifier = Base_pb2.LimitationTypeIdentifier() limitation_type_identifier.type = Base_pb2.FORCE_LIMITATION
def create_sequence(router): print("Creating Action for Sequence") angular_action = create_angular_action() cartesian_action = create_cartesian_action() print("Creating Sequence") sequence = Base_pb2.Sequence() sequence.name = "Example sequence" print("Appending Actions to Sequence") task_1 = sequence.tasks.add() task_1.group_identifier = 0 task_1.action.CopyFrom(angular_action) task_2 = sequence.tasks.add() task_2.group_identifier = 1 # Sequence element with same group_id are played at the same time task_2.action.CopyFrom(cartesian_action) print("Create sequence on device and execute it") base_client_service = BaseClient(router) handle_sequence = base_client_service.CreateSequence(sequence) base_client_service.PlaySequence(handle_sequence) print("Waiting 30 seconds to finish movement...") time.sleep(30)
def create_angular_action(): print("Creating angular action") action = Base_pb2.Action() action.name = "Example angular action" action.application_data = "" angle_value = [0, 0, 0, 0, 0, 0, 0] for joint_id in range(7): joint_angle = action.reach_joint_angles.joint_angles.joint_angles.add() joint_angle.value = angle_value[joint_id] return action
def create_cartesian_action(): print("Creating cartesian action") action = Base_pb2.Action() action.name = "Example cartesian action" action.application_data = "" cartesian_pose = action.reach_pose.target_pose cartesian_pose.x = 0.80 # (meters) cartesian_pose.y = 0 # (meters) cartesian_pose.z = 0.36 # (meters) cartesian_pose.theta_x = 10 # (degrees) cartesian_pose.theta_y = 90 # (degrees) cartesian_pose.theta_z = 10 # (degrees) return action
def example_manipulation_protobuf_basic(): # In protobuf, there's many scalar value types you can declare. # All those type have a coresponding type in python. # Here's the list: # Proto type : Python type # double : float # float : float # int32 : int # int64 : int # uint32 : int/long # uint64 : int/long # sint32 : int # sint64 : int/long # fixed32 : int/long # fixed64 : int/long # sfixed32 : int # sfixed64 : int/long # bool : bool # string : str # bytes : str # Those type can be used like regular python variable. # For more information about Scalar Value Types visits: # https://developers.google.com/protocol-buffers/docs/proto3#scalar # You can regroup many of these scalar value in a message. The message is a structure used in protobuf # to make sure all information is scope in an object. Scalar Value can't live on their own # if they are not contain in a message. # Here's a quick example using the Kinova API UserProfile message: # message UserProfile { # Kinova.Api.Common.UserProfileHandle handle = 1; //User handle (no need to set it with CreateUserProfile() # string username = 2; // username, which is used to connect to robot (or login via Web App) # string firstname = 3; //user first name # string lastname = 4; //user last name # string application_data = 5; //other application data (used by Web App) # } user_profile = Base_pb2.UserProfile() # Each scalar value in a message have a set_<field> function to set the value and a getter which is # simply the variable name user_profile.username = "******" # We can directly affect data to variable attribute user_profile.firstname = "Johnny" user_profile.lastname = "Cash"
def angular_movement(base_client_service): print("Starting angular motion ...") action = Base_pb2.Action() action.name = "Example angular motion" action.application_data = "" angle_value = [0, 0, 0, 0, 0, 0, 0] # arm straight up for joint_id in range(7): joint_angle = action.reach_joint_angles.joint_angles.joint_angles.add() joint_angle.joint_identifier = joint_id joint_angle.value = angle_value[joint_id] print("Executing action") base_client_service.ExecuteAction(action) print("Waiting 10 seconds to finish movement...") time.sleep(10) print("Angular movement finish")
def cartesian_movement(base_client_service): print("Starting Cartesian motion ...") action = Base_pb2.Action() action.name = "Example Cartesian motion" action.application_data = "" cartesian_pose = action.reach_pose.target_pose cartesian_pose.x = 0.80 # (meters) cartesian_pose.y = 0 # (meters) cartesian_pose.z = 0.36 # (meters) cartesian_pose.theta_x = 10 # (degrees) cartesian_pose.theta_y = 90 # (degrees) cartesian_pose.theta_z = 10 # (degrees) print("Executing action") base_client_service.ExecuteAction(action) print("Waiting 20 seconds for motion to finish ...") time.sleep(20) print("Cartesian motion ended")
def example_error_management(base_service): try: base_service.CreateUserProfile(Base_pb2.FullUserProfile()) except KServerException as ex: # get sub error codes error_code = ex.get_error_code() sub_error_code = ex.get_error_sub_code() print("error_code:{0} sub_error_code:{1} ".format( error_code, sub_error_code)) # error exception to string (here the try/except addresses an known issue that will be fixed in a future version) try: print("Error: {0}".format(ex)) except Exception: print( "Unkonown error details for error_code:{0} sub_error_code:{1} " .format(error_code, sub_error_code)) except Exception: import sys print("generic exception: {0}".format(sys.exc_info()[0]))
def example_manipulation_protobuf_helpers(): # Google offers some helpers with protobuf # We will cover some of them in this section # All the module google.protobuf documentation is available here: # https://developers.google.com/protocol-buffers/docs/reference/python/ # First, the function include with message instance. We will cover the next function # Clear # MergeFrom # CopyFrom # The Clear function is strainght forward it clear all the message attribute. # MergeFrom and CopyFrom have the same purpose, To duplicate data into another object. # The difference between them is CopyFrom will do a Clear before a MergeFrom. # For it's part MergeFrom will merge data if the new field is not empty. # In case of repeated, the content receive in parameter will be append # For this example, I'll used the Ssid message # message Ssid { # string identifier = 1; # } # First I'll create 4 of them with unique string ssid_1 = Base_pb2.Ssid() ssid_1.identifier = "" ssid_2 = Base_pb2.Ssid() ssid_2.identifier = "123" ssid_3 = Base_pb2.Ssid() ssid_3.identifier = "@#$" # Now I'll Merge ssid_1 in ssid_2 and print the identifier of ssid_2 ssid_2.MergeFrom(ssid_1) print("Content ssid_2: {0}".format(ssid_2.identifier)) # output : Content ssid_2: 123 # Now I'll Copy ssid_1 in ssid_3 and print the identifier of ssid_3 ssid_3.CopyFrom(ssid_1) print("Content ssid_3: {0}".format(ssid_3.identifier)) # output : Content ssid_3: # For more function visit the Class Message documentation # https://developers.google.com/protocol-buffers/docs/reference/python/google.protobuf.message.Message-class # From the protobuf library you can used the json_format module. # One useful function is the MessageToJson. # This function serialize the protobuf message to a json object it help alot when you want to print large object in # a human readable way. # Here's an example with the following two message # message Sequence { # SequenceHandle handle = 1 # string name = 2 # string application_data = 3 # repeated SequenceTask tasks = 4 # } # message SequenceTask { # uint32 group_identifier = 1; # Action action = 2; # string application_data = 3; # } # I quickly populate the message sequence = Base_pb2.Sequence() sequence.name = "A Name" for i in range(5): sequence_task = sequence.tasks.add() sequence_task.group_identifier = 10 * ( i + 1) # Some further function doesn't print if value = 0 action = sequence_task.action action = Base_pb2.Action() # Using Action default constructor # We need to import the module from google.protobuf import json_format # Now to get the json object json_object = json_format.MessageToJson(sequence) # Now you can print it print("Json object") print(json_object) # output: # Json object # { # "name": "A Name", # "tasks": [ # { # "groupIdentifier": 10 # }, # { # "groupIdentifier": 20 # }, # { # "groupIdentifier": 30 # }, # { # "groupIdentifier": 40 # }, # { # "groupIdentifier": 50 # } # ] # } # From the protobuf library you can used the text_format module # A useful function is the MessageToString. It has the same purpose of # MessageToJson convert the message to a human readable format # For the example I'll reuse the sequence object created in previous example # First import the module from google.protobuf import text_format # Now print print("Text format") print(text_format.MessageToString(sequence))