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.3.tar.gz (6.5 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.3-py3-none-any.whl (6.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dynos_warehouse_domain-0.1.3.tar.gz
  • Upload date:
  • Size: 6.5 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.3.tar.gz
Algorithm Hash digest
SHA256 c4388c0b720ce437ba0e03163596f8c7ca3a3a44cd0a8448818b694fe73cdd3a
MD5 555be11a7488dc9c3b5a7aa983db3304
BLAKE2b-256 5f09650bece80c7404b3187bfe63a6ad2dc6962adc3735388dc76b4d3225b4a4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for dynos_warehouse_domain-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e6bdd0bb16c2dac5562bb6c669c96367ef58668784eb845e9cab4000d21e4069
MD5 50d734df007c10f47ec5cb7a82d20a52
BLAKE2b-256 abaf75b65be72daa1cd8a62a9c252b320368cd068a8d74039feee4c16f0bdd19

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