$25
we will implement a physics-based planner for nonprehensile tabletop manip
ulation. Specififically, we consider manipulation tasks where the robot needs to rearrange some
surrounding movable objects by pushing so that certain task goals will be achieved. An example
task environment is illustrated in Figure 1. For this, among other possibilities, we will implement
the algorithm of Kinodynamic Rapidly-exploring Random Tree (Kinodynamic RRT) .
We will use a 7-DoF Franka Emika Panda robot simulated in PyBullet. A code framework,
hosted on github (https://github.com/robotpilab/COMP462/tree/main/project1), is pro
vided to facilitate the implementation. . The kinodynamic motion planning problems considered
in this project are modeled by three major components:
1. State space: Under the quasi-static assumption (i.e., the motion of the robot and the objects
are slow enough such that the inertial forces are neglectable), the state space of the problem
is defifined by the Cartesian product of the robot’s joint space and the state space of all the
movable objects in SE(2). For example, if there are two movable objects in the workspace,
the state space will be 7 + 2 × 3 = 13 dimensional, since the robot has 7 joints and each
object adds 3 more dimensions for its position and orientation in SE(2) (i.e., x, y, and θ).
2. Control space: We defifine the control in the Cartesian space of the robot end-effffector. Specif
ically, the control consists of the end-effffector’s linear velocity (
˙
x
, ˙
y), and angular velocity
about the z-axis θ˙ , associated with the duration of the control d. We represent a control by
the vector [ ˙x,
˙
y,
˙
θ, d
]. To execute such a control on the robot manipulator, we need to project
it onto the robot’s joint space, as will be described in Task 1.
3. Physics law: The physics of the entire robot-object-environment system is commonly repre
sented by a propagation function. The propagation function takes the current system state
and a control as inputs and will infer the state at the next time step. In this project, rather
than analytically deriving the propagation function, we will use the physics engine in the
simulator as our propagation function.
Figure 1: A 7-DoF robot manipulator rearranging cubic objects in PyBullet simulator.
Task 1: Jacobian-based Control Projection
To more effffectively represent and plan pushing-based manipulation motions, the control is defifined
in the Cartesian space of the end-effffector as stated above. As such, the robot’s motion is constrained
such that its end-effffector only moves parallel to the plane where manipulation happens. To execute
1such end-effffector motions with a robot arm, one needs to iteratively project the Cartesian controls
to the robot’s joint space and command the robot with the projected joint velocities.
Instead of analytically calculating the time derivatives of the forward kinematics, the fifirst task
in this project is to numerically calculate the Jacobian matrix of the robot and use it to project
the Cartesian velocity controls of the end-effffector to the robot’s joint velocities that can be used
to move the robot arm. Major steps for this task are detailed below.
1. Implement the following member method of the JacSolver class in jac.py for calculating
the jacobian matrix of the robot:
def get_jacobian_matrix(self, joint_values)
"""
Numerically calculate the Jacobian matrix based on joint angles.
args: joint_values: The joint angles of the query configuration.
Type: numpy.ndarray of shape (7,)
returns: J: The calculated Jacobian matrix.
Type: numpy.ndarray of shape (6, 7)
"""
Given that the robot has 7 degrees of freedom, the Jacobian matrix should be 6 × 7 and
relate the Cartesian velocities (the twist of the end-effffector) and the robot’s joint velocities
by the following equation:
v
ω
= J(q)
˙
q
where the notations are
(a) v = [vx, vy, vz]⊤ is the linear velocity of the end-effffector in 3D space;
(b) ω = [ωx, ωy, ωz]⊤ is the angular velocity of the end-effffector, which can be interpreted
as rotating about the axis ∥ω
ω∥ at a rate of ∥ω∥;
(c) q is a 7-dimensional vector of the robot’s joint angles, and
˙
q
is a 7-dimensional vector
of the robot’s joint velocities;
(d) J(q) is the 6 × 7 Jacobian matrix when the robot is at the confifiguration q.
The Jacobian matrix should be computed column-wise by fifinite difffferences. Remember that
each column of the Jacobian matrix corresponds to one robot joint. The provided member
function JacSolver.forward kinematics() for the robot’s forward kinematics can be used
in this implementation if needed.
For implementing this part, it might be useful to do kinematics-related calculations, e.g.,
transformations, conversions between difffferent orientation representations, etc. Feel free to
use libraries like PyKDL (http://docs.ros.org/en/diamondback/api/kdl/html/python),
or transformation-related functions provided by pybullet (https://docs.google.com/do
cument/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA/edit#heading=h.y6v0hy5
2u8fg).
2. Next, given a control [ ˙x,
˙
y,
˙
θ, d
] for the end-effffector ( ˙x and ˙
y for x- and y- linear velocities
respectively, θ˙ for angular velocity about z-axis, and d for the duration), iteratively evaluate
the Jacobian matrix and use it to calculate the projected joint velocities for executing this
control on the 7-DoF robot arm. In theory, the Jacobian needs to be updated as often as
possible, i.e., with high update resolution, to ensure smooth execution of the constrained
motions. Please read the code to understand how often is the Jacobian updated in the
provided framework.
It is worth noting that this control only specififies values for some dimensions of the desired
Cartesian velocity, not all dimensions. Therefore, it is needed to construct the complete
desired Cartesian velocity (twist of the end-effffector) by setting the unspecifified dimensions to
zero, i.e., [ ˙x,
˙
y,
0, 0, 0, θ˙]⊤.
For this, you need to implement the TODO in the following function PandaSim.execute() in
sim.py:
2def execute(self, ctrl, sleep_time=0.0):
"""
Control the robot by Jacobian-based projection.
args: ctrl: The robot’s Cartesian velocity in 2D and its
duration - [x_dot, y_dot, theta_dot, duration]
Type: numpy.ndarray of shape (4,)
sleep_time: sleep time for slowing down the simulation
rendering. (you don’t need to worry about this
parameter)
returns: wpts: Intermediate waypoints of the Cartesian trajectory
in the 2D space.
Type: numpy.ndarray of shape (# of waypoints, 3)
"""
Basically, the Jacobian matrix of the robot needs to be evaluated iteratively by calling
self.get jacobian matrix(), and be used to calculate the projected joint velocities. The
joint velocities should be represented by a numpy.ndarray of shape (7,), and stored in the
variable vq.
Besides, feel encouraged to try additional tricks in this function that might be helpful for
more stably and effiffifficiently planning and controlling the robot motions, as will be seen in the
other tasks that follow. For example, the tricks can be about:
(a) avoiding singularity of the robot;
(b) avoiding the robot to reach its joint limits;
(c) monitoring the end-effffector’s position and stopping moving the robot when the end
effffector is too far away from the workspace, etc.
After completing this part, the following command can be invoked in the terminal to test the
program: python main.py --task 1
If both the Jacobian calculation and the control projection are implemented correctly, you
should see the robot’s end-effffector moving along a square path parallel to the ground plane while
rotating itself about the z-axis for 10 times, as illustrated in Figure 2. The quality of robot motion,
defifined by the accuracy of the Jacobian-based control, will be evaluated by the Cartesian difffferences
between the executed and the desired motion trajectories. The averaged Cartesian motion errors
are printed in the terminal standard output.
Figure 2: An illustration of the expected robot motions in Task 1. The end-effffector moves along
a square path shown by black arrows while rotating itself about the z-axis.
Task 2: Kinodynamic Motion Planning
In this part, we will implement the main algorithm of a Kinodynamic RRT. The task of the robot
is to push the yellow cube into the red goal region.
In the provided code framework, the state of the robot-object system is represented by a
dictionary consisting of 2 key-value pairs: 1) "stateID" maps to an unique ID (int) of a state;
2) "stateVec" maps to the state values (numpy.ndarray). For a state, the fifirst 7 values of
3state["stateVec"] (i.e., state["stateVec"][0:7]) are the joint angles of the robot, and the
rest values are the poses of all objects in SE(2). Major steps for this task are detailed below.
1. A class ProblemDefinition is provided in pdef.py. This class can be used to access any
information relevant to the manipulation problem, including, for example, the simulation in
stance, the goal, the bounds for state and control, etc. Finish the following member method of
ProblemDefinition for the state validity checker that will later be used by the manipulation
planner:
def is_state_valid(self, state)
"""
Check if a state is valid or not.
args: state: The query state of the system.
Type: dict, {"stateID": int, "stateVec": numpy.ndarray}
returns: Ture or False
"""
Hints: self.bounds state.is satisfied(state) can be called to check if a state satisfifies
the bounds of the state space. self.panda sim.is collision(state) can be called to check
if the simulation instance has any collision. Feel free to add any other state validity criterion
that are potentially going to facilitate the planner.
2. Implement the main algorithm of the Kinodynamic RRT. Please fifirst read and understand
the provided classes Tree and Node in rrt.py. They relate to the data structure that will
be used by the Kinodynamic RRT planner. Below is a quick example of how to declare Node
instances, set its associated controls, set its parent node, and add nodes to an instance of
Tree, as illustrated in Figure 3.
Figure 3: A basic example of how to use Node and Tree.
Now, implement the following method of KinodynamicRRT class in rrt.py. It should return
True and the motion plan (a list of Node) if the planner fifinds the solution within the given
time budget (in seconds), otherwise, it should return False and None.
def solve(self, time_budget)
"""
The main algorithm of Kinodynamic RRT.
args: time_budget: The planning time budget (in seconds).
returns: solved: True or False.
plan: The motion plan found by the planner,
represented by a sequence of tree nodes.
Type: a list of rrt.Node
"""
4It is strongly recommended to read the provided code of other relevant classes (Node, Tree,
StateSampler, ControlSampler, etc) that might be called. Some hints for implementing
the planner:
(a) self.state sampler.sample() can be used to sample a state vector within the bounds,
and self.control sampler.sample to(node, stateVec, k) can be called to sample
k candidate controls from node towards stateVec. The latter has two returns: 1)
the best control among candidates whose outcome state is nearest to stateVec; 2) the
outcome state associated with this best control.
(b) self.pdef.goal.is satisfied(node) can be called to check if a node satisfifies the
goal.
After completing this part, following command can be invoked in the terminal to test the
implementation: python main.py --task 2
You will be able to see the robot fast simulate its motions for fifinding a solution. After a
solution plan has been found, you will see the robot slowly execute the solution plan. Meanwhile,
the end-effffector’s trajectory will be drawn by red lines, as illustrated in Figure 4.
Figure 4: An example showing the robot executing a solution plan to push the yellow target object
into the red goal region. The end-effffector’s trajectory is drawn by red lines.
Task 3: Grasping in Clutter
In this part, we will implement the goal criterion function for a grasping task. As a reference, the
relocating goal in the previous Task 2 is implemented by RelocateGoal in goal.py
Complete the following method of class GraspGoal in the same fifile. The GoalGrasp has been
provided with a member variable self.jac solver of the type jac.JacSolver() to help with
necessary kinematics calculation.
def is_satisfied(self, motion):
"""
Check if the state satisfies the GraspGoal or not.
args: state: The state to check.
Type: dict, {"stateID": int, "stateVec": numpy.ndarray}
returns: True or False.
"""
Hint: For a grasp to be feasible, the end-effffector should be close enough to the target object,
and the orientation of the end-effffector should be well aligned with the target object. In a state,
the pose of the target object in SE(2) (i.e., x, y and θ of the target object) can be accessed by
state["stateVec"][7:10].
The position of the robot base is [−0.4, −0.2, 0], and the orientation of the robot base is zero.
After completing this part, the following command can be invoked in the terminal to test the
implementation: python main.py --task 3. This command will run the algorithm implemented
in Task 2 for the new grasping task. If the grasping goal is implemented correctly, you should
5be able to see the end-effffector moving towards the target object while the solution plan is being
executed. The robot should successfully grasp the target object with its fifingers.
Figure 5: An example of the robot executing a solution plan to approach the yellow target object
for grasping. In the end, the end-effffector will grasp the target object by closing its fifingers. The
end-effffector’s path is drawn by red lines.
Task 4: Trajectory Optimization (Optional)
In this task we will implement some trajectory optimization techniques for a relocating or grasping
task. Feel free to implement any functions in opt.py and call the function under TODO in main.py to
run the implemented methods. Anything relevant to the optimization of the manipulation motion
trajectory will be of interest. For example, the length of the solution path can be minimized, or the
total motion of non-target objects can be minimized. Stochastic trajectory optimization [1] can be
a potential approach for this task. Note that the solution generated by the planner implemented
in Task 2 can be used to generate an initial solution to be optimized. Show the method and the
relevant fifindings in the report.
References
[1] Wisdom C Agboh and Mehmet R Dogar. Real-time online re-planning for grasping under
clutter and uncertainty. In 2018 IEEE-RAS 18th International Conference on Humanoid Robots
(Humanoids), pages 1–8. IEEE, 2018.
6