EECS / BioE / MechE C106A / 206A · Spring 2026 · Final Project

RoboMath

A UR7e arm that sees an unfinished equation, solves it with a vision-language model, and writes the answer back.

1. Introduction

Goal

Our goal is to build an end-to-end robotic system that observes an unfinished mathematical equation on the desk, determines the missing solution, and physically writes the answer back to the answer area. Concretely, the robot must (1) perceive the equation and the relevant objects in the scene, (2) reason about the mathematical content of the equation using an external vision-language model, (3) locate and grasp a whiteboard marker, and (4) execute a writing motion that places the solution in the correct location on the board. The whole system is autonomous and does not require any manual intervention.

Why this is interesting

The task looks simple from the outside, but it reqires all perception, planning, and actuation. To make it work, we have to:

Real-world applications

The pipeline is a small instance of a much larger class of problems: visually-grounded manipulation on flat surfaces driven by a reasoning model. The same building blocks transfer to:

2. Design

Design criteria

Before choosing an architecture we fixed the criteria the system had to meet:

Architecture

We split the system into four ROS 2 packages that communicate over topics and services. Each module has a single responsibility, so we could develop and test them in parallel:

System architecture diagram showing perception, planning, ArUco, and visual servoing modules connected through ROS 2 topics.
Figure 1. System architecture. The RealSense feeds both the perception node (point cloud + VLM) and the ArUco node. Perception publishes the marker pose on /cube_pose; ArUco publishes the reference frame of the answer sheet; visual_servoing consumes both and commands MoveIt to plan and execute the grasp and writing motions.
  1. Perception — processes RealSense depth + RGB, filters the point cloud to the workspace, isolates the marker as a cluster, and runs a vision-language model on the RGB image to read the equation and produce the missing digit.
  2. ArUco detection — provides a stable reference frame for the answer sheet. An ArUco marker on the sheet lets us express stroke coordinates in the sheet's frame rather than the camera's.
  3. Planning & IK — wraps MoveIt's GetPositionIK and GetMotionPlan services so the high-level pipeline can ask for "go to this Cartesian pose" without managing joint constraints itself.
  4. Visual servoing — the unified pipeline that sequences sense → grasp → lift → move to answer sheet → draw, and that converts each digit 0–9 into a hard-coded sequence of waypoints in the answer sheet frame.

Trade-offs

Impact on robustness, durability, and efficiency

These choices shape how the system performs in a real engineering setting:

3. Implementation

Hardware

UR7e workspace with whiteboard and marker.
Figure 2. The UR7e arm.
Close-up of the parallel gripper holding the marker.
Figure 3. 3D-printed maker box.

Parts list

PartPurpose
Universal Robots UR7e6-DoF arm performing all reaching, grasping, and writing motions.
Parallel gripperEnd-effector that grasps the whiteboard marker with the marker box.
RealSense CameraRGB-D camera providing both color frames for the VLM and point clouds for marker localization.
Marker and answer sheetWriting substrate and the object to be grasped.
ArUco tagStable 6-DoF reference frame on the answer sheet for the writing pose.
Maker box3D-printed box that holds the marker.
Maker stand3D-printed stand that holds the maker.

Software

The codebase is organized as four ROS 2 packages plus a small interfaces package. The entire stack is launched by ros2 launch planning project_stack.launch.py, which brings up the RealSense, the perception node, the planning/IK node, the visual_servoing TF broadcaster, the ArUco recognition pipeline, and MoveIt.

Software flowchart showing ROS 2 topics and services between modules.
Figure 4. ROS 2 topic/service graph. process_pointcloud publishes the marker centroid on /cube_pose and the VLM result on /answer; aruco_node broadcasts the ArUco marker as a TF frame consumed via the orchestrator's TF buffer; project_pipeline calls MoveIt's /compute_ik and /plan_kinematic_path services, toggles the gripper through /toggle_gripper, and dispatches joint trajectories to /scaled_joint_trajectory_controller/follow_joint_trajectory.

perception

process_pointcloud.py subscribes to /camera/camera/depth/color/points, transforms the cloud into base_link, crops to the workspace bounds, and filters the surviving points to publish a PointStamped on /cube_pose. The same node also receives the latest RGB frame, encodes it as base64, and calls a vision-language model (OpenAI API) with a prompt that asks for the missing digit in the equation. The VLM's answer is republished on a std_msgs/String topic so the orchestrator knows which glyphs to draw.

planning

Wraps MoveIt's IK and motion-plan services into a node (ik.py) that downstream code can call without owning joint state itself. static_tf_transform.py publishes a fixed transform from the UR7e wrist to the color optical frame so depth points register correctly with the arm's frame tree.

visual_servoing

project_main.py is the entry point. It runs the unified pipeline:

  1. Sense. Wait for a /cube_pose message and cache the latest ArUco transform.
  2. Grasp. Open the gripper, plan a pre-grasp pose above the marker via IK, descend, close the gripper, and lift.
  3. Approach the board. Plan a motion to a "ready-to-write" pose expressed in the ArUco frame.
  4. Write. Convert the VLM's digit string into a sequence of pre-defined stroke waypoints (digit 0–9), transform each waypoint into the robot base frame, and dispatch a FollowJointTrajectory action.
  5. Retract. Lift off the writing area.
# Launch the full stack
ros2 launch planning lab5_bringup.launch.py

# Run the unified pipeline
ros2 run visual_servoing project_main --ar_marker 1

# Draw 42 without using the answer from the VLM, used for debugging
ros2 run visual_servoing project_main --ar_marker 1 --digit 42.

How the complete system works (step-by-step)

  1. The RealSense camera streams synchronized color + depth information.
  2. perception filters the point cloud to the workspace bounding box, computes the centroid of the remaining points, and publishes it as the marker pose on /cube_pose.
  3. In parallel, perception sends the latest RGB frame to the VLM with a prompt asking for the missing digit; the answer is cached.
  4. ros2_aruco detects the ArUco maker on the whiteboard and publishes its pose; planning exposes IK and motion-plan services backed by MoveIt.
  5. visual_servoing receives the cube pose, plans a pre-grasp pose ~40 cm above the marker, descends to the grasp pose, closes the gripper, and lifts.
  6. The visual_servoing node transforms each stroke waypoint from the answer sheet (ArUco) frame into the base frame, plans a motion to it, and executes via FollowJointTrajectory.
  7. After the final stroke the arm retracts to a home pose, completing the loop.

4. Results

What the system did

The system was able to solve math expressions with answers being integers between 0 and 99. Below are some examples of the system's performance. The video demonstration is at the top of the page.

Result example 1.
Figure 5.
Result example 2.
Figure 6.
Result example 3.
Figure 7.
Result example 4.
Figure 8.
Result example 5.
Figure 9.
Result example 6.
Figure 10.

5. Conclusion

How well did we meet our design criteria?

Difficulties

Flaws, hacks, and what we'd do with more time

6. Team

Alex Aney

Alex Aney

Undergraduate in EECS and Math. Loves how robotics lets theory come to life and builds things in his free time.

Contributions: Designed and hard-coded the straight-line stroke sequences for digits 0–9 in the answer sheet frame, tuned the writing waypoints so the marker tip traces legible glyphs.

Shu Yuan

Shu Yuan

Senior in CS and Applied Mathematics. Researches LLM agents and post-training, and is interested in applying deep learning to robotics.

Contributions: Integrated the vision-language model into the perception node — the RGB-to-equation prompt, the API call, and publishing the parsed result on /answer.

Natalie Wang

Natalie Wang

Second-year in Mechanical Engineering, interested in surgical robotics.

Contributions: Hardware mounting and 3D-printed parts: the spring-loaded marker holder that absorbs vertical error during writing.

Yolanda Wei

Yolanda Wei

Undergraduate in ECE and Math, interested in applying robotics and ML to societal problems.

Contributions: ArUco integration, camera-to-base calibration, and the visual_servoing orchestrator that ties perception, MoveIt planning, and trajectory execution into the end-to-end pipeline.

7. Additional Materials