Smoother linear motion with xArm 7 + Leap Motion

Hi there,

For context, I’m aware that Leap Motion was supported for uArm previously although I’m not very sure of its application.

However currently we are trying to build a prototype using Leap Motion to control xArm’s movement. Basically we are trying to get the xArm to imitate a person’s hand motion, simply tracking a hand motion and translating that position to X Y Z position of the xArm.

Is there anyone working on something similar? Or would xArm has any recommendation on how to approach this?

Right now we are purely using set_position to set the cartesian coordinates of xArm whenever the hand positions are being output by Leap Motion. But because Leap Motion outputs about 120 frames per second, the xArm doesn’t move fast enough and the xArm moves and stop from set_position to set_position, and I think we may have exceeded the number of caches stored.

I’m considering using move_arc_lines and specifying path list instead.

Please advise! Thank you.

Yes, use move_arc_line and set wait=fales to let the controller to do the path planning.

I’m trying it now, setting first_pause_time to zero. Can you help to better clarify what does it do?

that one is set a time duration for the xArm Controller to do the planning, you could try 0.1s first

Hey Daniel,

I’ve tried move_arc_line. It does interpolate and smoothen the movements for the multiple paths injected, but it needs to calibrate first.

With this, we can’t imitate an actual person’s hand motion in real time.

This is being done with the Python SDK. Would the ROS SDK be able to help us achieve what we want to do?

Don’t know if this will help you …

In my experience, the only way to make the xArm6 robot respond quickly (> 100Hz) is:

  1. Turn reporting off. When reporting is on, the robot controller is sending
    updates back to your application at about 10 Hz. This overhead can screw
    up timing severely.

  2. For very smooth motion, you need to use “servoj” commands at a high rate.
    In our experience, around 40 Hz starts looking smooth. The problem is that
    servoj commands want angles not xyz/rpy coordinates so IK (inverse kinematics)
    is up to you.

We have experimented with around 40Hz in house using a dedicated network and precomputed
IK. In other words, we precompute angles into a file and feed the robot with servoj angle commands at
about 40Hz.

In your case, your realtime needs mean you can’t precompute angles, you have to do it on the fly.
Probably means you have to use a fast IK implementation such as IKFAST (see openrave site http://openrave.org/docs/0.8.2/openravepy/ikfast/) so you can generate the appropriate angles
and feed them to the robot at a fast enough rate. I haven’t tried it though so don’t know how much
of a pain that might be.

CAVEAT EMPTOR: I’m no expert at this robot so perhaps UFactory can give you better advice! Just thought it would
be useful to you to hear what others are experiencing.

Good luck,

Andre

Not sure if this will work, but you could try with the ROS.

You could use set_mode(1) and set_servo_angle_j. You can use PyBullet for inverse kinematics (<0.3 milliseconds) and visualization and then send the joint controls to xArm 6 (should be similar for xArm 7, just replace the URDF file). Here is some example code that computes IK on-the-fly: xArm-Python-SDK/example/wrapper/xarm6 at master · erwincoumans/xArm-Python-SDK · GitHub
Here is video of PyBullet IK in sim and on real xArm: real xArm6 and PyBullet xArm visualizer and inverse kinematics - YouTube
(I briefly tried ikfast, but it was not reliable, often no solutions)

1 Like

Did you try PyBullet on xArm 7?

Yes, I just created a URDF file for xArm 7 (with optimized collision meshes) and inverse kinematics support:
xarm 7 using PyBullet inverse kinematics and dynamics simulation - YouTube and
xArm-Python-SDK/example/wrapper/xarm7 at master · erwincoumans/xArm-Python-SDK · GitHub
accurate IK takes about 280 microseconds (0.28 milliseconds) for 50 iterations and using null-space to keep the arm upward.

You can try it out on Linux, Mac OSX and Windows using
pip3 install pybullet
git clone GitHub - erwincoumans/xArm-Python-SDK
cd examples/wrapper/xarm7
python3 loadxarm_sim.py
I didn’t try running on real xArm 7 (In don’t have one) but you could try it like this:
python3 http://xarm_real_ik.py/

Thanks, let us try on xArm 7 and get back to you.

Please do so and report back so we can improve things if needed. Note you can set useNullSpace to 0 for higher precision, in xarm_sim.py, but the arm may drift down eventually, without null space.

I run the scripts on my PC and to connect a xarm controller with a real xArm 7 robot, it did work.
But the motion is a bit odd, it moves aournd 2-3cm and then stop and then moves another 2-3cm and then stop, each stop is short but it make the robot looks like shaking during the movement, we can not get continue movements as the real time 3D model shows.
I think the biggest problem should the communication delay between my PC and the xarm controller.
I will try to run the scrips on the controller directly, but i think that is not the best way, since it execute calculatation on the Linux Gentoo(the system the xarm controller use) by Python and then pass the commands to firmware and the send to the xarm robot, there will be also a delay on the process of sending the commands from Python to the firmware.
So the best way might be integrated the calculation part to the firmware which based on C++, that means we need let that scripts run on C++ platform, we found the scripts are based on python and python libs such as numpy, we are trying to figure out away to let it run on C++ but have no idea yet.
Any advice will be appreciate.

Thanks

Could you please share a video to show the motion on real xArm 7 arm? Perhaps your PC has slow graphics? You could try replacing the p.connect(p.GUI) by p.connect(p.DIRECT)?

I didn’t notice the delay on our xArm 6, using Windows/Python 3:

If I have time, I can create a quick C++ example using the cmake build system. PyBullet is all C++ with Python bindings.

Got that, I used a Linux virtual machine which I did not assign much source for it, that’s may one of the reason. Let me try my Windows PC directly and post a video then.
Thanks very much.

It works! Let me share the video to you by Email.

Hi Erwin

I appreciate the time you put into showing how to achieve that smooth motion.

Since I have a lite6 robot, the setup will differ a bit, could you give me a quick list of the steps i need to take to adapt your project for the lite6 robot?

Does the URDF need to be created in a certain way? can I Just do it with blender?
are there other aspects i need to change?

Your help will be greatly appreciated.

Regards
Max

I mistook URDF for something else. How did you create the specific URDF file you use for the simulation?

I found the lite6 URDF at the ufactory github but its much shorter than yours.

when i try to create a urdf file with xacro using the lite6.urdf.xacro file, i get an empty urdf file. see the output of the console below. I’m using a ros docker container to do this.

root@6978348f4773:~/catkin_ws/src/xarm_ros/xarm_description/urdf/lite6# rosrun xacro xacro --verbosity=3 lite6.urdf.xacro
set lite6_urdf: <xacro.Macro object at 0x7f259f306610> (lite6.urdf.xacro)
<?xml version="1.0" ?>
<!-- =================================================================================== -->
<!-- |    This document was autogenerated by xacro from lite6.urdf.xacro               | -->
<!-- |    EDITING THIS FILE BY HAND IS NOT RECOMMENDED                                 | -->
<!-- =================================================================================== -->
<robot>
</robot>

the contents of the lite6.urdf.xacro file are here:

<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro">
  <xacro:macro name="lite6_urdf" params="prefix
    joint1_lower_limit:=${-2.0*pi}  joint1_upper_limit:=${2.0*pi}
    joint2_lower_limit:=${-2.61799}  joint2_upper_limit:=${2.61799}
    joint3_lower_limit:=${-0.061087}  joint3_upper_limit:=${5.235988}
    joint4_lower_limit:=${-2.0*pi}  joint4_upper_limit:=${2.0*pi}
    joint5_lower_limit:=${-2.1642}  joint5_upper_limit:=${2.1642}
    joint6_lower_limit:=${-2.0*pi}  joint6_upper_limit:=${2.0*pi}
    inertial_params_filename:='' kinematics_params_filename:='' "
    >

    <!-- load params and define property -->
    <xacro:property name="default_inertial_params_filename" value="xarm6_type9_HT_BR2"/>
    <xacro:if value="${inertial_params_filename != ''}">
      <xacro:property name="link_inertial_params_file" value="$(find xarm_description)/config/link_inertial/${inertial_params_filename}.yaml"/>
    </xacro:if>
    <xacro:unless value="${inertial_params_filename != ''}">
      <xacro:property name="link_inertial_params_file" value="$(find xarm_description)/config/link_inertial/${default_inertial_params_filename}.yaml"/>
    </xacro:unless>
    <xacro:if value="${use_xacro_load_yaml}">
      <xacro:property name="inertial_params" value="${xacro.load_yaml(link_inertial_params_file)}"/>
      <xacro:property name="kinematics_config" value="${xacro.load_yaml(kinematics_params_filename)}"/>
    </xacro:if>
    <xacro:unless value="${use_xacro_load_yaml}">
      <xacro:property name="inertial_params" value="${load_yaml(link_inertial_params_file)}"/>
      <xacro:property name="kinematics_config" value="${load_yaml(kinematics_params_filename)}"/>
    </xacro:unless>
    <xacro:property name="kinematics_params" value="${kinematics_config['kinematics']}"/>
    
    <link name="${prefix}link_base">
      <inertial>
        <origin xyz="-0.00829544579053192 3.26357432323433E-05 0.0631194584987089" rpy="0 0 0" />
        <mass value="1.65393501783165" />
        <inertia
          ixx="0" ixy="0" ixz="0"
          iyy="0" iyz="0" izz="0" />
      </inertial>
      <xacro:common_link_visual 
        mesh_filename="lite6/visual/link_base"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0"
        material_name="${prefix}White" />
      <xacro:common_link_collision 
        mesh_filename="lite6/collision/link_base"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0" />
    </link>
    <link name="${prefix}link1">
      <xacro:common_link_inertial 
        link_inertial_params="${inertial_params['link1']}" 
        origin_rpy="0 0 0"/>
      <xacro:common_link_visual 
        mesh_filename="lite6/visual/link1"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0"
        material_name="${prefix}White" />
      <xacro:common_link_collision 
        mesh_filename="lite6/collision/link1"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0" />
    </link>
    <joint name="${prefix}joint1" type="revolute">
      <!-- <origin xyz="0 0 0.2435" rpy="0 0 0" /> -->
      <xacro:common_joint_origin joint_kinematic_params="${kinematics_params['joint1']}" />
      <parent link="${prefix}link_base" />
      <child link="${prefix}link1" />
      <axis xyz="0 0 1" />
      <limit
        lower="${joint1_lower_limit}"
        upper="${joint1_upper_limit}"
        effort="50.0"
        velocity="3.14"/>
      <dynamics damping="1.0" friction="1.0"/>
    </joint>
    <link name="${prefix}link2">
      <xacro:common_link_inertial 
        link_inertial_params="${inertial_params['link2']}" 
        origin_rpy="0 0 0"/>
      <xacro:common_link_visual 
        mesh_filename="lite6/visual/link2"  
        origin_xyz="0 0 ${-kinematics_params['joint2']['y']}" 
        origin_rpy="0 0 0"
        material_name="${prefix}White" />
      <xacro:common_link_collision 
        mesh_filename="lite6/collision/link2"  
        origin_xyz="0 0 ${-kinematics_params['joint2']['y']}" 
        origin_rpy="0 0 0" />
    </link>
    <joint name="${prefix}joint2" type="revolute">
      <!-- <origin xyz="0 0 0" rpy="1.5708 -1.5708 3.1416" /> -->
      <xacro:common_joint_origin joint_kinematic_params="${kinematics_params['joint2']}" />
      <parent link="${prefix}link1" />
      <child link="${prefix}link2" />
      <axis xyz="0 0 1" />
      <limit
        lower="${joint2_lower_limit}"
        upper="${joint2_upper_limit}"
        effort="50.0"
        velocity="3.14"/>
      <dynamics damping="1.0" friction="1.0"/>
    </joint>
    <link name="${prefix}link3">
      <xacro:common_link_inertial 
        link_inertial_params="${inertial_params['link3']}" 
        origin_rpy="0 0 0"/>
      <xacro:common_link_visual 
        mesh_filename="lite6/visual/link3"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0"
        material_name="${prefix}White" />
      <xacro:common_link_collision 
        mesh_filename="lite6/collision/link3"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0" />
    </link>
    <joint name="${prefix}joint3" type="revolute">
      <!-- <origin xyz="0.2002 0 0" rpy="-3.1416 0 1.5708" /> -->
      <xacro:common_joint_origin joint_kinematic_params="${kinematics_params['joint3']}" />
      <parent link="${prefix}link2" />
      <child link="${prefix}link3" />
      <axis xyz="0 0 1" />
      <limit
        lower="${joint3_lower_limit}"
        upper="${joint3_upper_limit}"
        effort="32.0"
        velocity="3.14"/>
      <dynamics damping="1.0" friction="1.0"/>
    </joint>
    <link name="${prefix}link4">
      <xacro:common_link_inertial 
        link_inertial_params="${inertial_params['link4']}" 
        origin_rpy="0 0 0"/>
      <xacro:common_link_visual 
        mesh_filename="lite6/visual/link4"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0"
        material_name="${prefix}White" />
      <xacro:common_link_collision 
        mesh_filename="lite6/collision/link4"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0" />
    </link>
    <joint name="${prefix}joint4" type="revolute">
      <!-- <origin xyz="0.087 -0.22761 0" rpy="1.5708 0 0" /> -->
      <xacro:common_joint_origin joint_kinematic_params="${kinematics_params['joint4']}" />
      <parent link="${prefix}link3" />
      <child link="${prefix}link4" />
      <axis xyz="0 0 1" />
      <limit
        lower="${joint4_lower_limit}"
        upper="${joint4_upper_limit}"
        effort="32.0"
        velocity="3.14"/>
      <dynamics damping="1.0" friction="1.0"/>
    </joint>
    <link name="${prefix}link5">
      <xacro:common_link_inertial 
        link_inertial_params="${inertial_params['link5']}" 
        origin_rpy="0 0 0"/>
      <xacro:common_link_visual 
        mesh_filename="lite6/visual/link5"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0"
        material_name="${prefix}White" />
      <xacro:common_link_collision 
        mesh_filename="lite6/collision/link5"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0" />
    </link>
    <joint name="${prefix}joint5" type="revolute">
      <!-- <origin xyz="0 0 0" rpy="1.5708 0 0" /> -->
      <xacro:common_joint_origin joint_kinematic_params="${kinematics_params['joint5']}" />
      <parent link="${prefix}link4" />
      <child link="${prefix}link5" />
      <axis xyz="0 0 1" />
      <limit
        lower="${joint5_lower_limit}"
        upper="${joint5_upper_limit}"
        effort="32.0"
        velocity="3.14"/>
      <dynamics damping="1.0" friction="1.0"/>
    </joint>
    <link name="${prefix}link6">
      <xacro:common_link_inertial 
        link_inertial_params="${inertial_params['link6']}" 
        origin_rpy="0 0 0"/>
      <xacro:common_link_visual 
        mesh_filename="lite6/visual/link6"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0"
        material_name="${prefix}Silver" />
      <xacro:common_link_collision 
        mesh_filename="lite6/collision/link6"  
        origin_xyz="0 0 0" 
        origin_rpy="0 0 0" />
    </link>
    <joint name="${prefix}joint6" type="revolute">
      <!-- <origin xyz="0 0.0625 0" rpy="-1.5708 0 0" /> -->
      <xacro:common_joint_origin joint_kinematic_params="${kinematics_params['joint6']}" />
      <parent link="${prefix}link5" />
      <child link="${prefix}link6" />
      <axis xyz="0 0 1" />
      <limit
        lower="${joint6_lower_limit}"
        upper="${joint6_upper_limit}"
        effort="20.0"
        velocity="3.14"/>
      <dynamics damping="1.0" friction="1.0"/>
    </joint>

    <!-- <link name="${prefix}link_eef" />
    <joint name="${prefix}joint_eef" type="fixed">
      <origin xyz="0 0 0" rpy="0 0 0" />
      <parent link="${prefix}link6" />
      <child link="${prefix}link_eef" />
    </joint> -->
  </xacro:macro>
</robot>

Did you figure out how to generate urdf file from urdf.xacro file by any chance?

Hi Jason,

You can generate urdf file yourself, check the command below, you need to modify the parameter according to your model.

ros2 run xacro xacro src/xarm_ros2/xarm_description/urdf/xarm_device.urdf.xacro dof:=6 > xarm6.urdf

Best regards,
Minna