We recently updated the RobotGeek Snapper Arm with a new gripper, so I've been off in documentation land, getting everything happy for the new change. This inevitable led me to doing some work on the Arm Link Software. I have a love hate relationship with my little arm link program, but it works, so why not?
So first up didn't actually have a whole lot to do with the software, but the Snapper firmware. Andrew wrote all of the IK code for the Snapper, but never implemented Cylindrical or Backhoe modes. Backhoe mode is obviously pretty easy - just map the arm link packets to the servo joints. Cylindrical wasn't bad either, as Andrew had done all the IK work (the code is very similar to the code for the Cartesian X/Y/Z IK, only you ignore the X axis). The pain was going through the code and making it ready for multiple modes. A tedious hour later, I had everything working smoothly.
On the Arm Link side, it didn't take much to get things working. I had disabled cylindrical and backhoe mode on the snapper, so I quickly re-enabled them and added in all of the limits.
Of course an update like this turns into a black hole of updates. I had to update the ArmLink reference page for the new features, commands, and limits. Then I had to add the cylindrical IK engine into the main joystick IK software. And while I was at it I added the backhoe to joystick (which had previously been its own sketch). And then I updated that documentation. It never ends.
We make binary executables available for ArmLink, so making updates can be a little bit of a pain. It's nothing herculean, but to get java embedded with the app I need to build it on each target platform (once on Mac, once on Linux, once on Windows). So I try to wrap up multiple updates in one release when possible. So I decided to move onto a couple of things I've wanted to fix/change in the software.
Too Many Updates!
There are two ways to send positional updates to the arms - you can hit the
Update button to send the current values, or you can check the
Auto Update box. If you check the box, the positions will automatically be sent to the arm. If you lower the transition time (the delta) then you can get the arm to react in real time with your sliders and knobs. This feature works, but I found out that under certain positions that you could start to have problems. I'll go into more details in a later post, but with our Arm Link packet, if you send the same packet multiple times, and the packet has too many '0xff'/255 bytes, it is possible to read the last half of one packet and the first half of the next as a 'valid' packet. This can lead to some bad situations like arms repeatedly pounding the table. I'm still ruminating on ways to fix this on the packet side, but I decided that an easy fix on the software side would be to only send positional packets if a position was actually going to change. So every loop I check the current values against the last values - if there's a change, I send a packet. If not, I go on with my life. Either way I store the packets away to check against next time. This has fixed most my problems, though I'm still investigating an issue where two many '0xff' can freeze the arm temporarily.
Reading Registers and More
Finally I got to add something fun that I've wanted to add for a while. For the InterbotiX arms that use DYNAMIXEL I've gotten a couple of questions about accessing the servos directly. Basically each DYNAMIXEL serveo is a smart servo with a micro controller on board. There's all sorts of data that you can poll the servo for like position, temperature torque, and more. You can also set parameters like compliance on AX servos and PID settings on MX servos. But to get at any of this you need to work at the firmware/arbotix level. After another request for the feature last week I finally decided to implement the future.
On the firmware side I added two new instructions in the
inputContro.h file. The first will get data from the servo / register that you request from (instruction 0x81). The second instruction(0x82) will set data to a servo/register that you set. To pass the data I'm just using the packets normally reserved for X/Y/Z/Wrist for the parameters Id/RegisterNumber/Length/value.
So before I started integration into ArmLink, I wanted to do some testing. The easiest way would probably have been to fire up Cool Term and write out the packets to send to the arm, but I'm a masochist so I started ANOTHER project- Arm Link Barebones. Arm Link started as a basic demo both Interface wise and code wise. And while the code is readable, it jumps through a ton of hoops, so there's a lot to wade through if you're a developer and you just want the minimum example to get going. So Arm Link Barebones is just that, a really basic example of how to control the arm. There's no GUI, just some functions to talk to the arm over serial. Eventually I'll wrap it up in a nice library, but it's a decent stop gap.
Really starting Arm Link Barebones wasn't a big deal, I just ripped up a copy of Arm Link proper. So another hour later I had Arm Link Barebones sending commands to the arm. A few more functions added and there I was blinking servo LEDs and reading firmware versions from my computer. Huzzah!
When I started working on the get/set registers I didn't even plan to integrate it into Arm Link, but I took it that far, so I went just a little further. Really the biggest pain was integrating everything into the GUI. It's kinda cramped as is, and I really didn't want to re-arrange the whole gui. But after some 'creative' moving I finally got all of my fields in. I'm at home right now, and I did a lot of testing by putting some Arm firmware on a spare Geekduino, but I need to actually test it on a real arm. So keep your fingers crossed, hopefully I'll have a release tommorow.
Now keep in mind that I really want to move the Arm Link software over to a chrome app. I think for a demo that chrome apps have everything I need, are cross platform, and super easy to update/do gui stuff. Maybe next time