Skip to content

AshWan13/jerk-computation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Jerk Computation — Velocity-Profile Sandbox

License: BSD 3-Clause Python 3.9+ Status

Reproducible study of motion-jerk outcomes — explore how STEP, RAMP, and S-velocity profiles trade smoothness for responsiveness on a simulated omnidirectional waiter robot.

Hero — STEP / RAMP / SPLINE profiles compared on the same waiter robot

New to motion-jerk control? Run python demo.py — the interactive sandbox is designed for students, roboticists, and generalists to learn, build on, and experiment with the four velocity profiles in a unified scene.


Profiles

Profile What it does Smoothness class
STEP Snap each axis to the commanded velocity on the next tick. Discontinuous v — high jerk.
RAMP Linear-rate ramp on linear axes; yaw snaps. Continuous v, jumpy a.
SPLINE_X Jerk-bounded concave-then-convex S-curve on linear_x only; yaw snaps with a CRUISE-only cap. Continuous a, bounded j.
SPLINE_PLANAR Same S-curve on the resultant planar speed magnitude; direction tracks cmd_vel. Continuous a, bounded j; spillage-safe.

Cycle order in the sandbox: press M → STEP → RAMP → SPLINE_X → SPLINE_PLANAR.

The SPLINE_X and SPLINE_PLANAR profiles implement the jerk-limited S-velocity profile from Wan et al., Waiter Robots Conveying Drinks, Technologies 8(3):44, MDPI, 2020. SPLINE_PLANAR is an engineering extension developed by Alis Lin during her SIT capstone project. See smoovel/README.md for the full paper citation, BibTeX, and funding details.


Disclaimer — Simplified simulation

This codebase is a simplified simulation adaptation of the original work performed at Singapore Institute of Technology — Newcastle University (SIT-NU) on physical waiter robot platforms. The simulation is intended as a reference implementation of the algorithms; some aspects of the deployed system are abstracted, simplified, or omitted entirely.

In particular, the simulation may not fully represent:

  • Behavioural recovery — failure detection, fallback strategies, and re-planning under fault are not represented.
  • Empirical jerk-spill tolerance — the literature offers limited study on the exact jerk magnitudes that cause spills for a given liquid, container, or conveyor geometry. The original work focused on mitigating jerk rather than characterising spill tolerance; this sim uses a single configurable threshold (JERK_RED_THRESHOLD = 99 m/s³) as a stand-in.
  • Hardware dynamics — chattering from omniwheel rollers, rolling friction, motor torque limits, caster physics, sensor noise, body-damping behaviour, and other real-world effects are not modelled. The sim uses a single first-order body-damping time constant (body_tau = 0.10 s) as a coarse stand-in.

Treat this codebase as the algorithmic core of the published work — useful for understanding, replicating, and building on the algorithms and the computational-dynamics problem — but not as a faithful representation of the deployed hardware system.


Prerequisites

  • Python 3.9 or newer — check with python3 --version
  • pip — bundled with modern Python
  • git — for cloning the repository

The algorithm class (SmoothServer) itself depends only on the Python standard library. The interactive demo additionally needs pygame.


Installation

git clone https://github.com/AshWan13/jerk-computation.git
cd jerk-computation
pip install -e ".[pygame]"

Other install variants:

  • pip install -e . — algorithm class only. Use this if you just want to import SmoothServer into your own project.
  • pip install -e ".[pygame]" — adds pygame for the interactive teleop sandbox.
  • pip install -e ".[dev]" — adds pytest, ruff, black for development.

Running the demo

From the repository root:

python demo.py

This launches the interactive pygame sandbox. You'll see one waiter robot in the centre of a tiled floor; drop a Bar Set from the right-hand toolbar, place a Human or two, and drive the robot through the bar workflow using the controls below. The HUD across the top shows live state (selected robot, velocity scale, motion-state bars, peak jerk).

Importing classes into your own code

from smoovel.smooth_run import SmoothServer, Twist, VelocityProfile

s = SmoothServer(robot_id=1, profile=VelocityProfile.SPLINE_PLANAR)
s.ingest_cmd_vel(Twist(linear_x=0.30, angular_z=0.10))
xfm, state = s.step()

Platform-specific notes

macOS (Apple Silicon and Intel)

Tested on macOS 12+ with Python 3.9–3.12. The cleanest setup uses a virtualenv inside the cloned repo so pip is fresh enough for PEP 660 editable installs:

cd jerk-computation
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -e ".[pygame]"
python demo.py

To leave the venv: deactivate. To re-enter next time: source .venv/bin/activate from the repo root.

Anaconda users: the conda (base) env often ships with an older pip that fails on PEP 660 editable installs. Use a dedicated conda env instead:

conda create -n jerk-comp python=3.11 -y
conda activate jerk-comp
pip install -e ".[pygame]"
python demo.py

If pygame fails to load with an SDL error, install the system SDL2 dependency via Homebrew:

brew install sdl2 sdl2_image sdl2_ttf
pip install --force-reinstall pygame
Windows (10 / 11)

Tested with Python 3.9–3.12 installed from python.org. pygame installs cleanly via pip wheels — no extra system packages needed.

In PowerShell:

python --version
pip install -e ".[pygame]"
python demo.py

If the demo window doesn't appear, confirm you're not running inside WSL without a display server (use a native Windows Python install, or set up an X server like VcXsrv if you must use WSL).

Linux (Ubuntu / Debian)

Install Python tooling, the venv module, and SDL2 display libraries in one go:

sudo apt update
sudo apt install -y python3 python3-pip python3-venv python-is-python3 \
                    libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev

Then create a virtualenv inside the repo and install:

cd jerk-computation
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -e ".[pygame]"
python demo.py

If running over SSH or in a container, enable X11 forwarding (ssh -X user@host) or use a virtual display (xvfb-run python demo.py).

Quick sanity check

Without launching pygame, verify the package is importable:

python -c "from smoovel.smooth_run import SmoothServer; print('OK')"

Integration with your nav stack

SmoothServer is a transport-free Python object — it has no dependency on pygame, ROS, or restaurant_objects. Drop it between your existing velocity-command source (joystick / planner / move_base) and your base controller to get jerk-bounded output without changing anything else in your pipeline.

Per-tick pattern

One SmoothServer instance per robot. Each tick, push the latest inputs through ingest_* callbacks and read back the smoothed twist from step():

from smoovel.smooth_run import SmoothServer, Twist, Pose, VelocityProfile

# Construct once
s = SmoothServer(
    robot_id=1,
    dt=1/30.0,                              # match your control loop rate
    profile=VelocityProfile.SPLINE_PLANAR,  # or STEP / RAMP / SPLINE_X
    max_jerk_si=1.0,                        # Smoovel jerk cap, m/s^3
    body_tau=0.10,                          # drivetrain damping, s
)

# Per tick (e.g. in a ROS2 timer at 30 Hz)
def on_tick():
    s.ingest_cmd_vel(Twist(linear_x=cmd.vx,
                           linear_y=cmd.vy,
                           angular_z=cmd.wz))
    s.ingest_pose(Pose(x=amcl.x, y=amcl.y, yaw=amcl.yaw))  # optional
    s.ingest_goal(Pose(x=goal.x, y=goal.y))                # optional

    xfm, state = s.step()
    publish_base_controller(linear_x=xfm.linear_x,
                            linear_y=xfm.linear_y,
                            angular_z=xfm.angular_z)

Which callbacks are required vs optional

Call Required? Effect if omitted
ingest_cmd_vel(twist) required Nothing to smooth — output stays at zero.
ingest_pose(pose) optional Skip if you don't use ingest_goal either. Pose is only consulted for the TERMINAL approach.
ingest_goal(pose) optional Without a goal the FSM never enters TERMINAL — the controller stays in CRUISE / THROTTLE / BRAKE around your cmd_vel. Pass None to clear.
set_payload(mode) optional Purely informational unless you bind profile-by-payload via set_profile_for_payload.
set_profile(profile) optional Defaults to SPLINE_PLANAR. Toggle at runtime to compare profiles.
ingest_collision_event(blocked_dv) optional Feed in depth / dt when your collision resolver pushes the robot back; the jerk readout will reflect it.
reset() optional Zeros all internal ramps and returns to DOCK. Use on E-stop, teleop-mode-switch, or robot re-localisation.

ROS2 adapter

Twist and Pose carry built-in lazy adapters for the standard geometry_msgs types — the ROS imports only happen when you call the methods, so the rest of the algorithm runs anywhere:

from smoovel.smooth_run import Twist, Pose

# geometry_msgs.msg.Twist <-> smoovel.Twist
cmd_smoovel = Twist.from_ros2(cmd_ros)
cmd_ros_out = xfm_smoovel.to_ros2()

# geometry_msgs.msg.Pose2D <-> smoovel.Pose
pose_smoovel = Pose.from_ros2(pose2d_ros)
pose2d_ros   = pose_smoovel.to_ros2()

# geometry_msgs.msg.Pose (3D, quaternion) <-> smoovel.Pose
pose_smoovel = Pose.from_ros2_pose(pose_ros)
pose_ros     = pose_smoovel.to_ros2_pose()

A minimal rclpy node skeleton then looks like:

import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist as RosTwist, Pose2D
from smoovel.smooth_run import SmoothServer, Twist, Pose, VelocityProfile

class SmoovelNode(Node):
    def __init__(self):
        super().__init__("smoovel_wm1")
        self.s = SmoothServer(robot_id=1, dt=1/30.0,
                              profile=VelocityProfile.SPLINE_PLANAR)
        self.create_subscription(RosTwist, "/wm1/cmd_vel",
                                 self._on_cmd, 10)
        self.create_subscription(Pose2D, "/wm1/amcl_pose",
                                 self._on_pose, 10)
        self.pub = self.create_publisher(RosTwist, "/wm1/xfm_vel", 10)
        self.create_timer(1/30.0, self._tick)

    def _on_cmd(self, msg):  self.s.ingest_cmd_vel(Twist.from_ros2(msg))
    def _on_pose(self, msg): self.s.ingest_pose(Pose.from_ros2(msg))

    def _tick(self):
        xfm, _ = self.s.step()
        self.pub.publish(xfm.to_ros2())

Logging

When you construct SmoothServer(verbose=True), FSM transitions and profile / payload changes are emitted through the standard library logger at INFO level under the name "smoovel". Opt in via:

import logging
logging.basicConfig(level=logging.INFO)            # or configure the "smoovel" logger

By default the messages are silently dropped — importing this package produces no stdout output.

SimBus is sandbox-only

The SimBus class in smoovel.smooth_run is an in-process bus used by the pygame demo to step many SmoothServer instances against a toy pose integrator. It is not part of the integration surface and should not be wired into a real nav stack — instantiate SmoothServer directly instead.


Using the demo

Once demo.py is launched, the interactive sandbox accepts the keyboard and mouse controls below.

Active robot selection

Number keys 15 select which robot is currently active for control. Up to five robots may operate simultaneously in the same scene; all share the same control set.

Manual driving

Input Action
W A S D Drive forward / rotate left / reverse / rotate right (differential)
(arrow keys) Drive forward / reverse / strafe left / strafe right (holonomic)
Q Increase speed scale
E Decrease speed scale
LMB-click (empty floor) Set point-to-point nav goal (HYBRID autopilot)

Combine WASD and the arrow keys to compose a hybrid differential + holonomic command in a single chord.

Velocity profile

  • M — cycle the active velocity profile: STEPRAMPSPLINE_XSPLINE_PLANAR.

Path planner

  • P — toggle pathfinding algorithm between A* and Dijkstra's.

Obstacles and operations

The right-hand toolbar is split into two palettes:

  • OperationsBar Set (drops a complete bar counter + worker + 3 spawn / despawn tables) and Human (consumer agent that picks up filled cups from any robot in range).
  • ObstaclesTable, Chair, Wall, Pillar, S.Door, P.Door.

Spawning rules:

  • Click an obstacle button, then click in the scene for fixed-size obstacles, or click-and-drag for variable-size obstacles (walls, pillars) and drag-orientation obstacles (Bar Set — drag direction sets the bar's facing direction, snapped to 0° / 90° / 180° / 270°).
  • Double-click any obstacle to despawn it. Double-clicking any bar-set component (bar, worker, or one of the three back-row tables) despawns the whole set.
  • Single-click a coffee / cocktail spawn table within a Bar Set to spawn a fresh drink on top of it; the bar worker will pick it up automatically and deliver to a robot parked in front of the bar.

Cancelling and exiting

  • SPACE — emergency stop the selected robot.
  • X — cancel the current navigation goal for the selected robot.
  • C — clear all obstacles from the scene.
  • R — reset the scenario (back to one robot, empty scene).
  • Esc — quit.

Troubleshooting

  • ModuleNotFoundError: No module named 'smoovel' — Run from the repository root after pip install -e ".[pygame]". The python you invoke must be the same interpreter where you ran pip.
  • pygame window won't open / No available video device on Linux — Install libsdl2-dev, then either run python demo.py from a desktop session or enable X11 forwarding (ssh -X user@host) over SSH.
  • Slow rendering / unresponsive demo — Close inactive windows, reduce the robot count, or shrink the bar-set count.
  • pip install -e . fails on Apple Silicon — Update pip first (pip install -U pip setuptools wheel), then re-run.

Citation

Machine-readable citation metadata is in CITATION.cff. The per-module BibTeX for the underlying paper lives in smoovel/README.md.

License

Released under the BSD 3-Clause License. Copyright © 2026 Singapore Institute of Technology — Newcastle University and Ash Wan Yaw Sang.


Repository layout

jerk-computation/
├── README.md                ← you are here
├── LICENSE                  BSD 3-Clause
├── CITATION.cff
├── pyproject.toml
├── requirements.txt
├── .gitignore
│
├── demo.py                  unified pygame teleop sandbox
│
├── assets/
│   └── hero.png             sandbox screenshot used at the top of this README
│
├── common/                  shared utilities
│   ├── __init__.py
│   └── restaurant_objects.py    obstacle palette + drink-bar workflow + human AI
│
└── smoovel/                 Jerk-Bounded S-Velocity FSM (Technologies 2020)
    ├── __init__.py
    ├── smooth_run.py        SmoothServer + SVelocityProfile + SimBus
    └── README.md            paper details + BibTeX + DOI

Acknowledgements

This work has been adapted into a simplified simulation. The original work was carried out at Singapore Institute of Technology — Newcastle University (SIT-NU) under the supervision of Dr. Michael Lau Wai Shing. The original platform development was undertaken as part of the SIT Capstone Project; no external funding supported this codebase.

The SPLINE_PLANAR profile and the smoothed planar-motion behaviour it enables were developed by Alis Lin as part of her SIT capstone project, extending the published S-velocity profile to the planar-magnitude axis with live direction tracking.

The codebase builds on the open-source scientific Python community — pygame in particular.

Contact

Dr. Ash Wan Yaw Sang — yaw_sang94@hotmail.com · LinkedIn

About

Reproducible jerk outcomes via different velocity profiles — a pygame sandbox for studying motion-jerk trade-offs.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages