We’ve been working with Kinova’s Jaco arm with joint torque sensors for the last year or so as part of our research at Applied Brain Research, and we put together a fun adaptive control demo and got to show it to Justin Trudeau. As you might have guessed based on previous posts, the robotic control used force control. Force control is available on the Jaco, but the API that comes with the arm has much too slow an update time for practical use for our application (around 100Hz, if I recall correctly).
So part of the work I did with Pawel Jaworski over the last year was to write an interface for force control to the Jaco arm that had a faster control loop. Using Kinova’s low level API, we managed to get things going at about 250Hz, which was sufficient for our purposes. In the hopes of saving other people the trouble of having to redo all this work to begin to be able to play around with force control on the Kinova, we’ve made the repo public and free for non-commercial use. It’s by no means fully optimized, but it is well tested and hopefully will be found useful!
The interface was designed to plug into our ABR Control repo, so you’ll also need that installed to get things working. Once both repos are installed, you can either use the controllers in the ABR Control repo or your own. The interface has a few options, which are shown in the following demo script:
import abr_jaco2 from abr_control.controllers import OSC robot_config = abr_jaco2.Config() interface = abr_jaco2.Interface(robot_config) ctrlr = OSC(robot_config) # instantiate things to avoid creating 200ms delay in main loop zeros = np.zeros(robot_config.N_LINKS) ctrlr.generate(q=zeros, dq=zeros, target=zeros(3)) # run once outside main loop as well, returns the cartesian # coordinates of the end effector robot_config.Tx('EE', q=zeros) interface.connect() interface.init_position_mode() interface.send_target_angles(robot_config.INIT_TORQUE_POSITION) target_xyz = [.57, .03 .87] # (x, y, z) target (metres) interface.init_force_mode() while 1: # returns a dictionary with q, dq feedback = interface.get_feedback() # ee position xyz = robot_config.Tx('EE', q=q, target_pos = target_xyz) u = ctrlr.generate(feedback['q'], feedback['dq'], target_xyz) interface.send_forces(u, dtype='float32') error = np.sqrt(np.sum((xyz - TARGET_XYZ[ii])**2)) if error < 0.02: break # switch back to position mode to move home and disconnect interface.init_position_mode() interface.send_target_angles(robot_config.INIT_TORQUE_POSITION) interface.disconnect()
You can see you have the option for position control, but you can also initiate torque control mode and then start sending forces to the arm motors. To get a full feeling of what is available, we’ve got a bunch of example scripts that show off more of the functionality.
Here are some gifs feature Pawel showing the arm operating under force control. The first just shows compliance of normal operational space control (on the left) and an adaptation example (on the right). In both cases here the arm is moving to and trying to maintain a target location, and Pawel is pushing it away.
You can see that in the adaptive example the arm starts to compensate for the push, and then when Pawel lets go of the arm it overshoots the target because it’s compensating for a force that no longer exists.
So it’s our hope that this will be a useful tool for those with a Kinova Jaco arm with torque sensors exploring force control. If you end up using the library and come across places for improvement (there are many), contributions are very appreciated!
Also a big shout out to the Kinova support team that provided many hours of support during development! It’s an unusual use of the arm, and their engineers and support staff were great in getting back to us quickly and with useful advice and insights.