Friday Facts 3: Sixi 3 Java GUI

This week I’ve done a lot to make driving the Sixi 3 arm easier.

You’ll recall from FF1 that I had build a Panel to talk to a robot in Javax Swing.

TextInterfaceToListeners (at the bottom) was the starting point. Then I made a ConversationHistoryList (in the middle). The two are tied togeter in a TextInterfaceWithHistory, such that hitting send copies the message to the history and clicking a line in the history copies it to the input field. Next I made a ChooseConnectionPanel (at the top) and attached that to the TextInterfaceWithHistory inside a TextInterfaceToNetworkSession. Sure, it could have all been in one giant class… but that’s hard to manage, debug, or reuse.

Having made all that, I found it was no better than the existing Arduino serial interface for talking to the robot. My biggest worry is that I make a typo and send the robot crashing through the table before I can hit the emergency stop. So to address this pain point, I needed a way to drive more intuitively.

The Dial

The Dial is drawn to scale whatever size you need. It listens for scrolling of the mouse wheel. Other classes can subscribe to get ActionEvents when the dial moves. This way the dial is loosely coupled and can be reused all over the place. For example,

Angle Driving

Using the dial I built a panel that is initialized with a virtual sixi3 robot.

The radio buttons on the left are pulled from the robot model. The AngleDriving system listens to the dial. When the Dial moves then AngleDriving looks at the selected button, finds the robot joint, and tweaks it by 1 degree.

Cartesian Driving

Moving the arm one joint at a time is fine some of the time, but sometimes I need to move in a straight line. I improved the look of the Dial a little bit and made this tool to move the end effector (finger tip) of the robot arm.

XYZ are straight line moves. Roll is a twist around Z, pitch a twist around X, and yaw a twist around Y. Each of these moves happens relative to the reference frame. The options for now are world, the first joint of the robot, and the end effector itself.

Read-only panels

Once I had that I needed more ways to visualize what the system was doing. The two types I made are the AngleReportPanel,

And the various matrix reports.

Each of these listens to the robot reporting a change to the end effector position.

Cartesian Driving with Jacobians

Big shout out to https://akintokinematics.com/ for the excellent Jupyter notebooks that helped me improve cartesian driving to work. For some time now I’ve been telling everyone how much I love Gradient Descent for moving the robot arm. Well… it turns out Gradient Descent is hard to tune and slow AF to converge on a solution, sometimes taking 30 seconds per millimeter. So, instead, based on Greer’s notes, I used the approximate Jacobian.

The approximate Jacobian is a matrix describing the relationship between joint velocity and cartesian velocity at a position. So from position A to position B have the cartesian difference {x,y,z,roll,pitch,yaw}, dAB.

  • I get the approximate Jacobian at A, aj.
  • I get the inverse or pseudoinverse of the Jacobian, aji,
  • Multiply aji * dAB to get is the amount to move each joint in the arm.
  • Apply the joint change and measure the error term.

I set up a loop to run (at most) 20 times. In practical terms it never seems to run more than 2 or 3 per step, and feels blazing fast.

Putting it all together

If you run the development version of Robot Overlord today and use Demos > Sixi 3 you’ll get this view and be able to drive the virtual robot by playing with the controls. Tweaking the dials moves the virtual robot. Sixi 3 UI listens for those changes and sends them through the RobotUI.chatInterface so they show up in the history and they move the real machine (if connected).

My next Thing is figuring out a nice way to run programs: loops, sequences, patterns, wait for signal, send signal, conditionals, and so on. The virtual robot does not know anything about gcode and my gut says it would be a really big mess to spread gcode around the app. I would love to jazz with you about this and find a Good Way to achieve the Thing.