Category Archives: How-To

URDF for Darwin Mini robot

robotis-darwin-mini-humanoid-robot

URDF + Darwin Mini

URDF (Unified Robot Description Format) is an XML-based DSL to describe robots, commonly used in ROS (Robot Operating System).  In this post, I describe how I wrote the URDF description of the ROBOTIS Mini humanoid robot (previously known as Darwin Mini) by ROBOTIS Co. Ltd.

The great thing about ROS is the availability of plenty of Tutorials to get started, and this is true for URDF.  I will therefore not go through all the details, but rather try to give an overview of the approach I took, as it could be applied to other robots as well.

ROBOTIS has kindly made available the 3D model (in STL format) for Darwin-Mini, which comes handy when it comes to describe the robot.

Visualising the model

ros3djs-darwin-miniIt is very important when building the URDF description, to constantly visualise it, to make sure we are on the right track.  The most common approach to visualise an robot in ROS is through RViz.  However, being on Mac OS X (where it is a pain to build ROS graphical tools like RViz), I chose another way: render the 3D model in my browser, using the very cool ros3djs ROS package, based on three.js.

As you can see, I have a little Jetty server (actually a Clojure ring server!) running on port 3000, which serves a static HTML page displaying the 3D view.  The browser connects to a WebSocket interface (see rosbridge_suite package) to obtain coordinate frames of all 3D objects in real-time (see TF package).

Building our model

OK, now that we have our infrastructure in place to visualise a model, we need to create it.

I actually built it progressively, one piece after another.  An URDF description is in fact a tree, were the root is the base link (which is normally attached to the world), and other links attached to the base link and to each other to form branches.  For example, the body structure has multiple branches: the head, 2 arms and 2 legs.  Pretty straightforward.

Right hand of Darwin Mini robotIn order to build the tree, I started with just one link, displayed it in the Web Viewer, tweaked its orientation, then attaching another link to it.  And so on.

I started by building the hand.  As you can see, all pieces are tight to each other, so the links are attached to each other through what is called a "fixed" joint (as opposed to moving joints).

Defining joints

So, for example, here is what we have:

    <joint name="body_torso_joint" type="fixed">
      <origin xyz="0 0 0" rpy="0 0 0" />
      <parent link="body_skeleton_link"/>
      <child link="body_torso_link"/>
    </joint>
    <link name="body_torso_link">
      <visual>
        <origin xyz="0 0 0" rpy="0 0 0" />
        <geometry>
          <mesh filename="package://darwin_description/meshes/DMF-B01(W).stl" scale="0.001 0.001 0.001" />
        </geometry>
        <material name="White" />
      </visual>
    </link>

Typically, a part (body_torso_link) is attached to the parent part (body_skeleton_link) through a "fixed" joint.  The <visual> tag refers to the STL mesh of the part being described, and <material> applies the color.

xl320-angle-rangeLet us look at moving joints now.  In URDF, there are multiple kinds of moving joint: floating, revolute or prismatic.  For Darwin Mini, we only have revolute joints.

When defining the "revolute" joints, we need to take into account the acceptable angle range of the XL-320 servos, and the fact that the “normal” (rest) position of our robot is at 150°.

Also, there are 2 situations: (1) the body of the servo is fixed and the rotating axis is connected to the child link; (2) the rotating axis is attached to the parent link and the body of the servo is rotating.  Abstracting away the geometry of the servos, here is what we get for case (1):

    <joint name="neck_servo_joint" type="fixed">
      <origin xyz="0 0 0" rpy="0 0 0" />
      <parent link="body_link"/>
      <child link="neck_servo_link"/>
    </joint>
    <link name="neck_servo_link">
      <visual><!-- ... --></visual>
    </link>
    <joint name="neck_joint" type="revolute">
      <axis xyz="0 0 1" />
      <limit lower="0" upper="${300*M_PI/180}" effort="${XL320_MAX_TORQUE}" velocity="${XL320_MAX_VELOCITY}" />
      <origin xyz="0 0 0" rpy="0 0 ${-150*M_PI/180}" />
      <parent link="neck_servo_link"/>
      <child link="neck_link"/>
    </joint>
    <link name="neck_link" />

Notice the body of the servo (neck_servo_link) is fixed to the parent link through neck_servo_joint, and we define a “dummy” link (neck_link) attached to the revolute joint (neck_joint).  Child links will then be attached to this dummy link.

Parametrise and modularise the robot model

When starting to build up our model, the code quickly becomes very long and verbose.  A common way to address this complexity in URDF descriptions is to make use of xacro (XML macro system) to define a model in a modular way.

We can define each basic part as a xacro block, with a few parameters.  Each block has a ${name} (which will be used as prefix for the joint and link names) and a ${parent} to which the child link will be attached.  Moreover, to describe symmetric parts, a nice trick I found (in PR2 description) is to pass a ${side} (“l” or “r” for “left” / “right”) and a ${reflect} parameter which takes a value of “1” for left side and “-1” for right side.  This ${reflect} comes handy for example when rotating the part in opposite directions for left and right sides.

Here is an example:

  <xacro:macro name="darwin_spu5" params="name parent xyz rpy">
    <joint name="${name}_joint" type="fixed">
      <origin xyz="${xyz}" rpy="${rpy}" />
      <parent link="${parent}"/>
      <child link="${name}_link"/>
    </joint>
    <link name="${name}_link">
      <visual><!-- ... --></visual>
    </link>
  </xacro:macro>

Putting it all together

Here are the xacro files I end up with:

materials.urdf.xacro # materials (colors) used in basic blocks
common.urdf.xacro    # basic blocks (1 per 3D part)
servo.urdf.xacro     # servo motor & revolute joints
hand.urdf.xacro      # hands
arm.urdf.xacro       # arms to which hands are attached
leg.urdf.xacro       # legs and foots
body.urdf.xacro      # body to which arms & legs are attached
base.urdf.xacro      # base where the body is attached
darwin.urdf.xacro    # main file --includes all the files above

Next steps

So far, I explained how I built the URDF description for Darwin Mini.  The next step will be to “gazebo-ise” the model (make it an SDF) so that it can be simulated in Gazebo, and eventually used to control the real Darwin Mini robot.

rosclj – ROS node in Clojure

Playing with robots, and learning ROS (robot operating system), I was happy to find out about rosclj, Clojure bindings for ROS.  I would be able to control robots from the REPL; how nice!

However, I quickly discovered that the only thing remaining from rosclj is its documentation: the code (originally in a SVN repo of Berkeley) has disappeared.  But never mind.  Clojure can do Java interoperop, right?  So I gave it a shot, and it turned out pretty well, so I thought I’d publish my findings because there is not much up-to-date information out there.

I started by familiarising myself with rosjava and create a pub-sub sample project following the nice tutorial here.  But don’t worry, you don’t really need to fiddle out with catkin to get Clojure talk to a ROS node.  This is actually simpler.

 

Your first ROS node in Clojure

Here are the steps:

1. Create a lein project (I called mine roscljtest), and add rosjava repository and dependencies to your project.clj.  Here is mine:

(defproject roscljtest "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.7.0"]
                 [org.ros.rosjava_core/rosjava "0.2.1"]
                 [org.ros.rosjava_messages/geometry_msgs "1.11.7"]]
  :repositories [["rosjava" "https://raw.githubusercontent.com/rosjava/rosjava_mvn_repo/master"]]
  :aot :all)

2. Write a ROS node in Clojure.  I simply translated the Listener from the rosjava tutorial to clojure:

(ns roscljtest.core
  (:import [org.apache.commons.logging Log]
           [org.ros.message MessageListener]
           [org.ros.namespace GraphName]
           [org.ros.node AbstractNodeMain ConnectedNode NodeMain]
           [org.ros.node.topic Subscriber]))

(gen-class
  :name "roscljtest.core.CljListener"
  :extends org.ros.node.AbstractNodeMain
  :prefix "clist-")

(defn clist-getDefaultNodeName [this]
  (GraphName/of "rosjava/listener"))

(defn clist-onStart [this connectedNode]
  (let [log (.getLog connectedNode)]
    (doto (.newSubscriber connectedNode "chatter" std_msgs.String/_TYPE)
      (.addMessageListener
        (proxy [MessageListener] []
          (onNewMessage [msg]
            (.info log (str "I heard: \"" (.getData msg) "\""))))))))

3. Build the Clojure code, and create a uberjar, which will be useful to avoid messing up with the classpath:

> lein uberjar

If everything goes well, the following jar file should be generated, and (notice the :aot :all in our project.clj) contain all .class files: roscljtest-0.1.0-SNAPSHOT-standalone.jar

4. Start ROS core and the Talker from the Java tutorial (don’t start the Listener, since we will start the one we just wrote in Clojure)

> roscore &
> cd src/rosjava_catkin_package_a/my_pub_sub_tutorial
> cd build/install/my_pub_sub_tutorial/bin
> ./my_pub_sub_tutorial com.github.rosjava.rosjava_catkin_package_a.my_pub_sub_tutorial.Talker &

5. Finally, start the Clojure node, as follows:

> java -cp target/roscljtest-0.1.0-SNAPSHOT-standalone.jar org.ros.RosRun roscljtest.core.CljListener

Once the connection is established, you should see the following output flow, at a rate of about 1 message per second:

Oct 17, 2015 8:28:18 PM org.ros.internal.node.RosoutLogger info
INFO: I heard: "Hello world! 26"
Oct 17, 2015 8:28:19 PM org.ros.internal.node.RosoutLogger info
INFO: I heard: "Hello world! 27"

Next Steps

OK, this is great.  And the thing I like the most, is that we don’t even need our project to be “catkinized”: we can just use Leiningen as usual (provided we specify the correct repo in our project.clj).

I was actually even able to run the CljListener on a separate machine (provided I set ROS_MASTER_URI and ROS_IP correctly on both machines): I did not even have to install ROS on the machine running the CljListener!

Next step will be to make this a little more idiomatic Clojure, because extending Java classes and overriding methods is no fun.  And I want to be able to run commands from the REPL, which I haven’t tried yet.

But all in all, this looks very promising.