Skip to main content

Public warehouse-bot domain for DYNOS

Project description

dynos-warehouse-domain

A small, deliberately-toy domain and a bit of a tutorial. This represents a robot that moves between rooms, picks up boxes, and puts them down. It is the simplest interesting domain that exercises every part of the symbolic planning stack (preconditions, effects, typed objects, goals) without any of the AUV-specific machinery the Sentry domain layers on top.

If you have never used a task planner before, this is the package to read first. This is sort of a sibling package to dynos-sentry-domain. They both depend on dynos-client, but neither depends on the other; pick whichever fits your problem. You probably want to learn the concepts here and then move to dynos-sentry-domain.

Install

pip install dynos-warehouse-domain

Pulls in dynos-client and dynos-core transitively.


Symbolic planning in five minutes

DYNOS is a task planner. You hand it a description of the world and a goal; it hands you back a sequence of actions that, executed in order, will make the goal true. There are three pieces.

1. The world as a set of facts

DYNOS describes the world as a set of named, typed facts called fluents. A fluent is just a labeled question with a true/false answer:

  • robot_at(room_one) -> "is the robot in room one?"
  • holding(box_a) -> "is the robot holding box A?"
  • hands_free() -> "are the robot's hands empty?"

The set of fluents that are currently true is the world state. Anything not in that set is false. This is called a closed-world model, and it's why you only have to list what's true. It's also an approximation, but we work around it pretty effectively by constantly re-planning and re-assessing what goes on in the world.

World right now:
  { robot_at(room_robot_home), hands_free(), box_at(room_one, box_a) }

That's the entire description of the situation: robot is at home, hands are empty, box A sits in room one. No coordinates, no images, no continuous sensor data, just a set of true facts. Symbolic planning works on these boolean facts. DYNOS does extend this by having a separate channel for continuous values like coordinates and altitudes; that's ValueField on object types that will get explored more later.

2. Actions described as before/after

A transition describes what an action looks like symbolically. It does not run any code. It declares:

  • preconditions: facts that must already be true for the action to be legal
  • adds: facts that become true after the action runs
  • removes: facts that stop being true

The pick transition in this package, for example, says: "to pick up a box, your hands must be free, you must be in the room with the box, and the box must be in that room. Afterwards you're holding the box, the box is no longer in the room, and your hands are no longer free."

We represent this in python, which aids with introspection and debug:

pick.define(
    preconditions=[hands_free(),
                   robot_at(pick.params.room()),
                   box_at(pick.params.room(), pick.params.box())],
    adds=[holding(pick.params.box())],
    removes=[box_at(pick.params.room(), pick.params.box()), hands_free()],
)

The DYNOS backend reads the data when it plans, and there's a separate piece of code (an @Action method, not in this package) that actually moves the robot. The strict separation is what lets the planner reason about long sequences without knowing anything about hardware.

3. Goals are desired states

A goal is a set of facts you want to be true. You don't tell the planner what to do; you tell it what should be true at the end. This way, the planner can figure out the optimization and missing steps for you, and can re-plan to re-solve when things change. For example:

Goal:  { box_at(room_two, box_a) }

"I want box A to end up in room two." The planner searches over transitions to find a sequence whose combined effect changes the current state into one that satisfies the goal. For the world above, against this goal, the planner returns:

1. move(start=room_robot_home, end=room_one)
2. pick(room=room_one, box=box_a)
3. move(start=room_one, end=room_two)
4. place(room=room_two, box=box_a)

You did not write that sequence, the planner derived it from the preconditions and effects you wrote. If the situation changes (e.g., an obstacle blocks room_one) you describe the change as a fact the planner sees, set the same goal, and you get a new plan. This is the dynos call goal "..." + dynos call execute workflow you'll see in the cross-package walkthrough, or that you can trigger from the orchestrator (as the mission executive will do during operation).

That's it. Everything else in DYNOS, like coverage surveys, lifecycle phases, multi-stage missions, and replanning on failure, is built on these three principles.


The warehouse domain concretely

This package ships everything you need to give the planner the example above.

Object types

class Box(ObjectType):
    weight = ValueField(float)

class Room(ObjectType):
    capacity = ValueField(int)

Box and Room are typed entities. Fluent argument types are checked against them: box_at(room=Room, box=Box) will reject box_at(room_one, room_two) because the second argument has the wrong type. The weight and capacity ValueField descriptors hang continuous values off each instance — useful if you want to later add a "robot can only carry boxes lighter than X kg" constraint.

Pre-built objects

The package creates eight specific instances at import time, ready for goals:

  • Boxes: box_a, box_b, box_c
  • Rooms: room_robot_home, room_loading_bay, room_one, room_two, room_three

This saves you from writing make_new_object(Box) for the toy examples; the names are just stable handles into the numeric database.

Fluents

Fluent Meaning
hands_free() True iff the robot is not currently holding anything. (Defaults to True, so the initial world has it true unless you explicitly remove it.)
robot_at(room) The robot is in room.
box_at(room, box) box is sitting in room.
holding(box) The robot is holding box.

Transitions (the robot's verbs)

Transition Parameters Meaning
pick(room, box) PickPlaceParams Pick up a box that's in the same room as the robot.
place(room, box) PickPlaceParams Put down a held box in the room the robot is in.
move(start, end) MoveParams Move from start to end. (No connectivity graph: every room is reachable from every other room. This is intentional for the toy.)

Read warehouse.py for the full preconditions / adds / removes.


Use it

Against a running backend

Same flow as the Sentry domain (see dynos-client's README for the session/login basics). Once you have a session:

from dynos_client import RemoteOrchestrator
from dynos_warehouse import box_a, room_one, room_robot_home, room_two, box_at, robot_at, hands_free

orch = RemoteOrchestrator.from_config()

# Tell the backend the initial world
orch.set_start([
    robot_at(room_robot_home),
    hands_free(),
    box_at(room_one, box_a),
])

# Set the goal
orch.set_goal([box_at(room_two, box_a)])

# Inspect the plan before running it
print(orch.get_plan())

# Run it
orch.execute_plan()

The CLI equivalent uses string-form goals:

dynos call goal "box_at(room_two, box_a)"
dynos call plan
dynos call execute

Offline (no backend at all)

Because Transition is inert data in dynos-core, you can introspect it without any backend or network:

from dynos_warehouse import pick

for p in pick.preconditions:
    print(p)
# Output:
#   hands_free()
#   robot_at(room)
#   box_at(room, box)

This is the fastest way to confirm you've understood a domain: print the preconditions and effects of every transition and check that the resulting before/after picture matches your mental model.

Public API

Symbol Kind Purpose
Box, Room object type Typed entities.
box_a, box_b, box_c, room_robot_home, room_loading_bay, room_one, room_two, room_three object Pre-built instances.
hands_free, robot_at, box_at, holding fluent Boolean facts about the world.
PickPlaceParams, MoveParams parameter dataclass Transition argument types.
pick, place, move transition The robot's verbs.

What's NOT here

  • No executable behaviour. The transitions are symbolic specs; nothing in this package moves a real or simulated robot. Pair it with a backend that has registered @Action methods bound to pick / place / move.
  • No room connectivity graph. move(start, end) is unconditional. If you want a topology where some rooms are only reachable from others, add a connected(a, b) fluent and put it in move's preconditions.
  • No payload constraints. pick doesn't check Box.weight against Room.capacity. Add a numeric precondition to pick.define(...) if you want one — that's exactly the kind of extension this domain is meant for.

Next

  • dynos-core: the data-layer types (Transition, ObjectType, ValueField, make_new_fluent) you'll reach for when extending or replacing this domain.
  • dynos-client: the HTTP client and dynos CLI for talking to a backend.
  • dynos-sentry-domain: the same machinery applied to a real underwater vehicle, with surveys and lifecycle phases.
  • user_guide.md: install + auth + first mission, end-to-end.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dynos_warehouse_domain-0.1.2.tar.gz (6.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dynos_warehouse_domain-0.1.2-py3-none-any.whl (6.6 kB view details)

Uploaded Python 3

File details

Details for the file dynos_warehouse_domain-0.1.2.tar.gz.

File metadata

  • Download URL: dynos_warehouse_domain-0.1.2.tar.gz
  • Upload date:
  • Size: 6.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.10

File hashes

Hashes for dynos_warehouse_domain-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5e7d931b00254adee143c84a9f4620c7df934705126ff275eac0c61b65ceb326
MD5 3c525d86d47558321d46f89a592d8b67
BLAKE2b-256 dec2971a0c1d46828f824b0fc4b87bb3b494f7c5d24f4e03423e97236e9a7d9b

See more details on using hashes here.

File details

Details for the file dynos_warehouse_domain-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for dynos_warehouse_domain-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e50f68efa513e13f6b19940dbc0e9f7cc6da33041bb8dae384337e00989362d1
MD5 d54d542c3cd12ce66444d18d22a3dab5
BLAKE2b-256 7a649a46fe0c71640241cf081c780aa6a22f9d6ae69482ea431ce204c350b64a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page