Controlling Franka & ROS

Starting ROS to control Franka

The recommended setup for controlling the franka can be seen in the tree below. The top level shows the devices required and their IP address, the second tier shows the commands needed to run the files:

.
├── Franka Control Box (192.168.0.88)
├── Host workstation computer (192.168.0.77)
│   ├── roscore
│   └── ./franka_controller_sub 192.168.0.88
└── Project workstation computer
    ├── roslaunch openni2_launch openni2.launch
    ├── camera_subscriber.py (this does not need to be run seperately)
    └── main.py

Tip

To test the image feed out without using it in main.py you can use the test_camera.py file in the tests folder.

Networking with other workstations

Instead of running the master node and subscriber nodes on your own workstation, these can be running on the main workstation in the lab instead. This means that libfranka won’t need to be installed on your specific workstation.

To communicate over the lab network you need to change two main ROS variables. Firstly you need to find the IP address of your computer when connected to the lab network (via ethernet). To do this you can use ifconfig in a terminal window to give you your <ip_address_of_pc>.

You then need to run the following two commands in your terminal window (substitute in you IP address):

export ROS_MASTER_URI=http://192.168.0.77:11311
export ROS_IP=<ip_address_of_pc>

As you will see, this is connecting you to the static IP address of the main Franka workstation, 192.168.0.77. In order for you to continue with running a Python publisher, you need to ensure that roscore and the subscriber is running on the main workstation.

Note

That this configuration of assigning IP addresses to ROS_MASTER_URI and ROS_IP is non-permanent, and is only active for the terminal window you are working in. This has to be repeated for every window you use to run rospy. Alternatively you can add these commands to your bashrc.

Running the subscriber

Once roscore is running, the subsciber has to run in the background to read the messages from our Python publisher and execute them with libfranka. To run the subscriber (from the project folder), run:

cd franka/
./franka_controller_sub 192.168.0.88

Sometimes there is an “error with no active exception” thrown by this executable. This can sometimes be solved by simply manually moving the arm using the buttons a bit. Then rerun the command above again.

Warning

This subscriber is compiled for libfranka 0.1.0. You can check your current libfranka version with rosversion libfranka command.

Using the publisher

First, make sure you are running roscore and the subscriber, franka_controller_sub on the main lab workstation.

Example

Assuming you are writing a script (script.py) that wants to use control franka, the files should be stored as:

.
├── README.md
├── franka
│   ├── __init__.py
│   ├── franka_control_ros.py
│   ├── franka_controller_sub
│   ├── franka_controller_sub.cpp
│   ├── print_joint_positions
│   └── print_joint_positions.cpp
└── script.py

To use the FrankaRos class in your own Python script would look something like this:

from franka.franka_control_ros import FrankaRos

franka = FrankaRos(debug_flag=True)
# we set the flag true to get prints to the console about what FrankaRos is doing

while True:
   data = arm.get_position()
   print("End effector position:")
   print("X: ", data[0])
   print("Y: ", data[1])
   print("Z: ", data[2])
class franka.franka_control_ros.FrankaRos(log=False, ip='192.168.0.88', debug=False, init_ros_node=False)[source]
get_position()[source]

Get x, y, z position of end-effector and returns it to caller.

Returns:list as [x, y, z]
grasp(object_width, speed, force)[source]

Grasp an object in the grippers. Note that this can only be called if the object width is smaller than the current distance between the grippers.

The grippers attempt to move to the width of the object defined with speed defined, and then proceed to apply a defined force against the object. If no object is present it evaluates as failed and moves to next task.

0 width defined == 2.2 cm difference real-world

Parameters:
  • object_width – width of target object to grab (float)
  • speed – with which to move the gripper to object width (float)
  • force – to apply to the object once the grippers are at object width (float)
move_gripper(width, speed)[source]

Set gripper width by assigning width with a desired speed to move at. Note this must be called before grasping if gripper fingers are too close together grasp() call.

0 width defined == 2.2 cm difference real-world

Parameters:
  • width – desired distance between prongs on end-effector (in millimetres)
  • speed – desired speed with which to move the grippers
move_relative(dx, dy, dz, speed)[source]

Moves robot end effector in desired direction (in robot reference frame) given a target displacement and speed to travel at. The robot will not necessarily travel at this speed due to safety controls in the subscriber.

Parameters:
  • dx – float value displacement in robot reference axis
  • dy – float value displacement in robot reference axis
  • dz – float value displacement in robot reference axis
  • speed – float value desired speed to target displaced position
move_to(x, y, z, speed)[source]

Moves robot end effector to desired coordinates (in robot reference frame) given a target velocity. The robot will not necessarily travel at this speed due to safety controls in the subscriber.

Parameters:
  • x – float value position in robot reference axis
  • y – float value position in robot reference axis
  • z – float value position in robot reference axis
  • speed – float value desired speed to target position
send_trajectory(trajectory)[source]
start_subscriber()[source]
stop_subscriber()[source]
subscribe_position_callback(data)[source]
franka.franka_control_ros.example_movement()[source]

Used to test if the arm can be moved with gripper control.

Function moves the arm through a simple motion plan and then tried moving the grippers. To use this test, add the -m or --motion-example flag to the command line.

franka.franka_control_ros.example_position()[source]

Used to test if position reporting is working from Arm.

It will repeatedly print the full arm position data and the XYZ position of the end-effector. To use this test, add the -p or --position-example flag to the command line.

Using Franka without ROS

Note

This method is deprecated. It is now recommended you use ROS to control the Arm using a Python publisher, such as the way described above.

Setting Permissions

To control the Franka Arm, Fabian and Petar have written a small collection of C++ files which can be compiled to run as executables and control the Franka Arm using libfranka.

You need to ensure you have set the correct permissions for libfranka. You can check that in Using the franka_ros library.

Downloading the C++ Executables and Python Class

Now that you have libfranka set up properly you can get use the C++ files provided. These resources can be found in the /franka directory of the repository. Firstly, go to your project directory in the terminal by using cd <project_dir>. If you have already downloaded the files before and are replacing them with an up-to-date version, run rm -rf franka/ first. To download the necessary folder, run:

svn export https://github.com/nebbles/DE3-ROB1-CHESS/trunk/franka

Once this directory is downloaded into your project directory, you need to change directory and then make the binaries executable:

cd franka/
chmod a+x franka*
chmod a-x *.cpp

Warning

This next command will move the FRANKA. Make sure you have someone in charge of the external activation device (push button).

These binaries can now be used from the command line to control the Arm:

./franka_move_to_relative <ip_address> <delta_X> <delta_Y> <delta_Z>

Alternatively, you can control the Arm using the easy custom Python class Caller (see below).

Python-Franka API with franka_control.py

The Python-FRANKA module (franka_control.py) is designed to allow easy access to the C++ controller programs provided by Petar. The provided Python module is structured as follows.

Example

To use the FrankaControl class in your own Python script would look something like this:

from franka.franka_control import FrankaControl

arm = FrankaControl(debug_flag=True)
# we set the flag true to get prints to the console about what Caller is doing

arm.move_relative(dx=0.1, dy=0.0, dz=-0.3)
# we tell teh arm to move down by 30cm and along x away from base by 10cm

Note

This example code assumes you are following the general project structure guide. See below for more information. The code above would be called from a main script such as run.py.

General Structure of Project

The structure of the project is important to ensure that importing between modules works properly and also seperates externally maintained code from your own. An example of a project tree is:

.
├── LICENSE.txt
├── README.md
├── run.py
├── __init__.py
├── docs
│   ├── Makefile
│   ├── build
│   ├── make.bat
│   └── source
├── franka
│   ├── __init__.py
│   ├── franka_control.py
│   ├── franka_get_current_position
│   ├── franka_get_current_position.cpp
│   ├── franka_move_to_absolute
│   ├── franka_move_to_absolute.cpp
│   ├── franka_move_to_relative
│   └── franka_move_to_relative.cpp
├── my_modules
│   ├── module1.py
│   ├── module2.py
│   ├── module3.py
│   ├── __init__.py
└── test_script.py