In the first part of this lab you’ll assemble the manipulator arm and gripper on your robot. This arm has three rotating joints and a gripper, all actuated by Robotis AX12 “Dynamixel” robot servos (doc). These receive battery power via the org and are controlled by a serial communications interface also on the org. Monitor commands are provided (and their Java and Scheme correspondents) to move the arm and to query its state.
In the second part of the lab you’ll write high level code with the Java or Scheme interface to move the gripper to commanded locations in world frame, using the robot’s turn-in-place capability to add a fourth rotating degree-of-freedom (DoF) to the arm workspace. In the third part you will program the robot to drive towards the location of an object on the ground, deploy the arm, and grasp the object.
We have prepared an archive file of sourcecode that you’ll use in this lab. Follow similar instructions as for lab 0 to download and unpack it (on the panda). Make sure that the unpacked lab3
directory is a sibling to your existing lab?
directories that were unpacked from the prior lab tarballs.
If you are running the panda headless, use the following command to download a copy of the lab tarball:
> wget http://www.ccs.neu.edu/course/cs4610/LAB3/lab3.tar.gz
We ask you not to modify the files you unpack from the lab tarball. You will write code that refers to these files and that links to their generated libraries. Please do not work directly in the provided files, in part because we will likely be posting updates to the lab tarball.
lab3/src/org/libpololu-avr
run make
to build the Pololu AVR library.In lab3/src/org/monitor
run
> make
> make program
to build the OHMM monitor and flash the new monitor code to the org.In lab3/src/host/ohmm
run
> make
> make jar
to build OHMM.jar
. (In the event that we distribute an updated lab tarball, you will need to re-make
in org/libpololu-avr
, org/monitor
, and host/ohmm
, re-program
in org/monitor
, and re-jar
in host/ohmm
.)Runing
> make project-javadoc
in lab3/src/host/ohmm
will generate documentation for the OHMM Java library in lab3/src/host/ohmm/javadoc-OHMM
(the top level file is index.html
); or you can view it online here.
The lab 3 monitor program includes a set of ax*
commands to interact directly with the AX12 servos (documented in monitor/ohmm/ax12.h
). It also includes a set of a*
commands to interact with the servos in the context of the OHMM manipulator arm (documented in monitor/ohmm/arm.h
). It is strongly recommended to use only the higher-level arm commands except for debugging purposes.
The Java OHMM library and the Scheme OHMMShell also provide access to the AX12 and arm module commands.
You may wish to review the instructions in lab 2 on how to run OHMMShell and how to compile your own Java code against OHMM.jar
.
Follow similar instructions as for lab 2 to make a checkout of your group svn repository on your panda as a sibling directory to the lab3
directory you unpacked from the lab tarball.
Change directory so that you are in the base directory of your svn repository checkout (i.e. you are in the g?
root directory of the svn checkout), then run the commands
> mkdir lab3
> d=../lab3/src/host/ohmm
> cp $d/makefile $d/run-class ./lab3/
> cp $d/makefile-lab ./lab3/makefile.project
> sed -e "s/package ohmm/package lab3/" < $d/OHMMShellDemo.java > ./lab3/OHMMShellDemo.java
> svn add lab3
> svn commit -m "added lab3 skeleton"
This sets up the directory g?/lab3
in the SVN repository in which you will write all code for this lab. The makefile should not need to be modified: it is pre-configured to find the OHMM Interface library in ../../lab3/src/host/ohmm
. It also will automatically compile all .java
files you create in the same directory.
Bring up an OHMMShell and run the following commands to enable the arm and send it to the calibration pose:
> (ae #t)
> (ac)
The calibration pose is intended to have the arm pointing straight forward with the gripper closed. Since you were directed above to assemble the arm in this pose while the servos were at the middle of their range of motion (with the white marks lined up), in theory this pose should be reached by setting each servo to the goal position 512 in AX12 counts (the AX12 servos have a range of motion of 0 to 300 degrees, with 0 degrees corresponding to 0 counts and 300 degrees corresponding to 1023 counts). However, various sources of error will cause each arm to reach a slightly different pose when all servos are commanded to 512.
Very carefully using commands like
> (axsg i c)
where i
is a servo index (0 = shoulder, 1 = elbow, 2 = wrist, 3 = gripper) and c
is the goal counts (start with 512 and work in increments of about +/- 10 counts at a time), try to adjust your arm so that it appears to be in the correct straight-forward calibration pose. You may also judiciously tension the gripper to close with a little bit of force here. Try adding and subtracting 10 counts from the gripper servo first to understand which direction closes and which direction opens the gripper. Then open the gripper to a small gap, followed by closing it in small increments until the fingers are just touching. Continue closing by 10 or 20 further counts to tension the gripper a bit. (Note: the gripper state actually is set by the difference between servos 2 and 3, so you may also need to fiddle with servo 2 to maintain the calibration pose.)
Once you are satisfied with the calibration, read out the current goal locations of each servo:
> (axrd16 0 ax-goal-position)
> (axrd16 1 ax-goal-position)
> (axrd16 2 ax-goal-position)
> (axrd16 3 ax-goal-position)
Record the values on paper as c0, c1, c2, c3
. Then set them as the new arm calibration values like this:
> (asac c0 c1 c2 c3)
where you substitue the actual numbers for each calibration value. The arm should not move when you do this, but if you then test the calibration by running
> (ah)
> (ac)
the arm should move to the home pose and then back to the correct calibration pose. The calibration values will be stored on the org in nonvolatile EEPROM so so that you should not have to re-calibrate unless you re-flash the org (in which case the EEPROM will be erased).
Using the inverse kinematics method of your choice, implement a program that runs on the panda (this is a requirement), homes the arm, and then responds to keypresses as follows, with initially:
w — move the gripper +mm in the world-frame
direction
s — move the gripper -mm in the world-frame
direction
a — move the gripper +mm in the world-frame
direction
d — move the gripper -mm in the world-frame
direction
r — move the gripper +mm in the world-frame
direction
f — move the gripper -mm in the world-frame
direction
q — z —
Assume that the robot is at world frame pose initially. Use turn-in-place wheel motions (only) to add a “yaw” DoF to the arm kinematics. Use the wrist DoF to keep the gripper horizontal (parallel to the ground, as it is in arm home pose) at all times.
If the target location is not reachable, your program must emit a message. However, it is up to you to decide how to move the arm in the case of unreachable targets. For example, you could make a best-effort motion to reach towards the target. However you do it, you must maintain the following property: any sequence of keypresses followed by the reverse sequence, e.g. “wwrrffss”, must return the arm to the home pose. This effectively establishes the set of possible target points as a rectilinear lattice centered at the gripper location in home pose and axis-aligned in world frame.
You may find that reading a single keypress from the console is not easy in Java; in fact, technically, it’s not possible to do in a portable way using the current standard Java API. However, here we will accept a solution which runs on Unix; for that see the provided code in ohmm.ConsoleNonblocking
. Alternatively, we will accept solutions which open a graphics window and then respond to KeyEvent
s there.
The notes for Lecture 9 give details of the arm kinematics, including the link lengths. They also present an analytic IK approach for this arm.
Retrieving objects on the ground is a common task in mobile manipulation. In this part, you will implement a basic method to approach an object, grasp it, and carry it.
Fashion a small object from paper. The object should sit on the ground and have a narrow upwards protrusion tall enough so that the gripper can engage it when lowered to within 5mm of ground clearance. You may want to have the protrusion expand a bit at its top to help prevent the object slipping out of the gripper.
Using your horizontal-gripper IK solution from above, write a program to produce a yaw-free grasp sequence starting from home pose:
The robot chassis should remain in place at all times. Calculate the robot frame offset distance
from the robot frame origin where an object on the ground should be grippable at step d. Practice picking up the object; tune the sequence as you see fit to maximize grip success.
Extend your program so that it can take the coordinates of the object on the ground as command line arguments in world frame millimeters (if no command line arguments are given, then the program should revert to keyboard control inverse kinematics as above). For example, if your Java class to solve this part is called Grasp, you should be able to invoke it like this
> ./run-class Grasp 30 40
for a goal at mm in world frame. Assuming the robot starts at pose
in world frame, have your program
Note: you may need to re-calibrate the robot wheel-to-wheel baseline distance to improve the accuracy of turn-in-place motions. You may optionally take a third command line parameter giving the robot baseline distance in mm (thus allowing it to be adjusted at the beginning of each run).
You will be asked to demonstrate your code for the course staff in lab on the due date for this assignment. We will try out code; 30% of your grade for the lab will be based on the observed behavior. Mainly want to see that your code works and is as bug-free as possible.
The remaining 70% of your grade will be based on your code, which you will hand in following the instructions on the assignments page by 11:59pm on the due date for this assignment. We will consider the code completeness, lack of bugs, architecture and organization, documentation, syntactic style, and efficiency, in that order of priority. You must also clearly document, both in your README and in code comments, the contributions of each group member. We want to see roughly equal contributions from each member. If so, the same grade will be assigned to all group members. If not, we will adjust the grades accordingly.