Main Module Handling
The first steps are equal for all interface modules. These are the instantiation of the main wrapper (ANNiCub_wrapper class), that is needed exactly once.
import ANN_iCub_Interface as ann_icub
iCub = icub_int.iCub_Interface.ANNiCub_wrapper()
After creating this instance the respective modules can be created. For this two alternatives are currently possible and can also be combined. The first option is the instanciation on the individual module level, that is described in the respective module sections. The second opportunity is to create multiple modules at once based on a configuration given in a XML-config file. This config-file is further explained in the Manual->Configuration section.
ret_val, robot_dict = ann_icub.init_robot_from_file(iCub, "./data/demo_robot.xml")
if not ret_val:
sys.exit("Interface initialization failed!")
The inidivual instance can then be acquired from the wrapper:
rarm_jreader = iCub.get_jreader_by_part("PART_KEY")
rarm_jreader = iCub.get_jreader_by_name("JR_name")
rarm_jwriter = iCub.get_jwriter_by_part("PART_KEY")
rarm_jwriter = iCub.get_jwriter_by_name("JW_name")
rarm_sreader = iCub.get_skinreader_by_name("SR_name")
vreader = iCub.get_vis_reader_by_name("VR_name")
kinread = iCub.get_kin_reader_by_name("KR_name")
kinwrite = iCub.get_kin_writer_by_name("KW_name")
Joint Reader
In case the module is handled indiviually, the first step is the creation and initialization of the Joint Reader module:
jreader = Joint_Reader.PyJointReader()
if not jreader.init(iCub, "name_reader", iCub_Const.PART_KEY_HEAD, 0.5, 15, ini_path=params.INTERFACE_INI_PATH):
sys.exit("Initialization failed!")
The joint angles can be read in two different formats (explicit degree values or gaussian population code) and from single, multiple or all joints at the same time. For the explicit values the following set of methods:
joint_angle = jreader.read_double_one(joint=0)
joint_angles = jreader.read_double_multiple(joints=[0,1,3])
joint_angles = jreader.read_double_all()
For population-coded values the following set of methods:
joint_angle_coded = jreader.read_pop_one(joint=0)
joint_angles_coded = jreader.read_pop_multiple(joints=[0,1,3])
joint_angles_coded = jreader.read_pop_all()
For information about the configuration several getter methods are provided:
jreader.get_joint_count()
jreader.get_joints_deg_res()
jreader.get_neurons_per_joint()
Joint Writer
In case the module is handled indiviually, the first step is the creation and initialization of the Joint Writer module:
jwriter = Joint_Writer.PyJointWriter()
if not jwriter.init(iCub, "name_writer", iCub_Const.PART_KEY_HEAD, 0.5, 15, ini_path=params.INTERFACE_INI_PATH):
sys.exit("Initialization failed!")
To configure the motion properties like acceleration use the specific setter methods:
jwriter.set_joint_controlmode(control_mode, joint)
jwriter.set_joint_acceleration(acc, joint)
jwriter.set_joint_velocity(speed, joint)
The Joint Writer follows the same schema as the Joint Reader, providing methods to control the robot joints either with explicit degree values or population-coded values. For the explicit values the following set of methods:
jwriter.write_double_one(joint_angle, joint, mode, blocking, timeout)
jwriter.write_double_multiple(joint_angles, joints, mode, blocking, timeout)
jwriter.write_double_all(joint_angles, mode, blocking, timeout)
For population-coded values the following set of methods:
jwriter.write_pop_one(joint_angle, joint, mode, blocking, timeout)
jwriter.write_pop_multiple(joint_angles, joints, mode, blocking, timeout)
jwriter.write_pop_all(joint_angles, mode, blocking, timeout)
For information about the configuration several getter methods are provided:
jwriter.get_joint_count()
jwriter.get_joints_deg_res()
jwriter.get_neurons_per_joint()
jwriter.get_joint_limits()
jwriter.get_joint_limits_max()
jwriter.get_joint_limits_min()
Visual Reader
In case the module is handled indiviually, the first step is the creation and initialization of the Visual Reader module:
visreader = Visual_Reader.PyVisualReader()
if not visreader.init(iCub, "name_reader", 'r', ini_path=params.INTERFACE_INI_PATH):
sys.exit("Initialization failed!")
For the image retrieval from the robot currently two methods exists: First Method: The images from the iCub are preprocessed (normalization [0., 1.] and either RGB or grayscale images) and dependent on the configuration the left, right or both images are retrieved. For the images of both eyes only one reader module is necessary.
imgs = visreader.read_robot_eyes()
imgs = test_imgs.reshape(2, 240, 320)
imgright = imgs[0]
imgleft = imgs[1]
Second Method: The raw images are retrieved from the iCub. The images are in RGB-colors and in the value range is [0, 255]. For the images of both eyes only two reader modules are necessary.
imgright = np.array(visreader_r.retrieve_robot_eye()).reshape(240, 320, 3)
imgleft = np.array(visreader_l.retrieve_robot_eye()).reshape(240, 320, 3)
Skin Reader
In case the module is handled indiviually, the first step is the creation and initialization of the Skin Reader module:
sreader = Skin_Reader.PySkinReader()
if not sreader.init(iCub, "skin_right", "r", True, ini_path=params.INTERFACE_INI_PATH):
sys.exit("Initialization failed!")
At this point the skin reader only handles the skin/tactile sensors at the iCub arms. To read the data from the sensors two the skin reader offers two different ways: The first option is to directly receive the sensor data from the different arm sections:
print("Data arm:")
print(sreader.read_skin_arm())
print("Data forearm:")
print(sreader.read_skin_forearm())
print("Data hand:")
print(sreader.read_skin_hand())
In the second option the data is buffered inside the reader module and can be collected per part after the data acquisition:
for i in range(10):
sreader.read_tactile()
print("Data arm:")
print(sreader.get_tactile_arm())
print("Data forearm:")
print(sreader.get_tactile_forearm())
print("Data hand:")
print(sreader.get_tactile_hand())
To get information about the sensor count and therefore the vector size of the different data arrays the following getter-methods are provided:
sreader.get_tactile_arm_size()
sreader.get_tactile_forearm_size()
sreader.get_tactile_hand_size()
Kinematic Reader
In case the module is handled indiviually, the first step is the creation and initialization of the Kinematic Reader module:
kinreader = Kinematic_Reader.PyKinematicReader()
if not kinreader.init(iCub, "name_fkin", part=iCub_const.PART_KEY_RIGHT_ARM, version=2, ini_path=params.INTERFACE_INI_PATH, offline_mode=params.offline):
sys.exit("Initialization failed")
To get information about the current state of the kinematic chain several methods exists:
print("DOF:", kinreader.get_DOF())
print("Active DOF:", kinreader.get_DOF_links())
print("Blocked links:", kinreader.get_blocked_links())
print("Current angles:", np.rad2deg(kinreader.get_jointangles()))
The forward kinematic is by default in an online mode, directly receiving the joint angles from the robot. But if the reader is configured to work in offline mode, no connection to the robot is established. Then the state of the kinematic chain need to be handled manually. This means the static links should be blocked and the joint angles of the active part has to be set in radians. Since all angles are initialized with zero, blocked links may need to be set once before blocking them.
if params.offline:
kinreader.block_links([0, 1, 2])
joint_angles = np.deg2rad(np.array([15., 16., 0., 70., -90., 0., 0.]))
kinreader.set_jointangles(joint_angles)
Finally the forward kinematic can be performed, either for the end-effector (hand for the arms) or for a specific joint in the kinematic chain. The position is given in the robot reference frame.
end_eff_pos = kinreader.get_handposition()
print("End-Effector", end_eff_pos)
print("End-Effector", iTransform.transform_position(end_eff_pos, params.Transfermat_robot2world))
joint3_pos = kinreader.get_jointposition(3)
print("Joint 3", joint3_pos)
print("Joint 3", iTransform.transform_position(joint3_pos, params.Transfermat_robot2world))
Kinematic Writer
In case the module is handled indiviually, the first step is the creation and initialization of the Kinematic Reader module:
kinwriter = Kinematic_Writer.PyKinematicWriter()
if not kinwriter.init(iCub, "invkin", part=iCub_Const.PART_KEY_RIGHT_ARM, version=2, ini_path=params.INTERFACE_INI_PATH, offline_mode=params.offline):
sys.exit("Initialization failed")
To get information about the current state of the kinematic chain several methods exists:
print("DOF:", kinwriter.get_DOF())
print("Active DOF:", kinwriter.get_DOF_links())
print("Blocked links:", kinwriter.get_blocked_links())
print("Current angles:", np.rad2deg(kinwriter.get_jointangles()))
The inverse kinematic is by default in an online mode, directly receiving the joint angles from the robot. But if the writer is configured to work in offline mode, no connection to the robot is established. Then the state of the kinematic chain need to be handled manually. This means the static links should be blocked and the joint angles of the active part has to be set in radians. Since all angles are initialized with zero, blocked links may need to be set once before blocking them. Finally the inverse kinematic can be performed depended on online or offline mode:
if params.offline:
kinwriter.block_links(blocked_joints)
kinwriter.set_jointangles(joint_angles)
joint_angles = kinwriter.solve_InvKin(target_position)
else:
joint_angles = kinwriter.solve_InvKin(target_position, blocked_joints)
print("Estimated joint angles:", np.rad2deg(joint_angles))
Final Wrap-up
To clean up at the end, each module is equipped with a close-method. These can be called for all in one from the main wrapper with the clear method to clean up all initialized modules.
module.close(iCub)
print('----- Close interface instances -----')
iCub.clear()