Migrate NEEMs

Migrate NEEMs#

In this tutorial we will go through the process of migrating locally stored PyCRORM NEEMs to an already existing PyCRORM NEEM-Hub.

In some cases it my occur that you want to record data from a pycram controlled robot locally and perform some local actions before migrating your data to a big database server. In such cases, you can easily make a local database and connect your pycram process to it.

After you recorded your data locally you can migrate the data using the migrate_neems function.

First, lets create an in-memory database engine called source_engine where we record our current process.

import sqlalchemy.orm
import pycram

source_engine: sqlalchemy.engine.Engine
source_engine = sqlalchemy.create_engine("sqlite+pysqlite:///:memory:", echo=False)
source_session_maker = sqlalchemy.orm.sessionmaker(bind=source_engine)
pycram.orm.base.Base.metadata.create_all(source_engine) #create all Tables

Next, create an engine called destination_engine for the destination database where you want to migrate your NEEMs to. Note: This is just an example configuration.

destination_engine: sqlalchemy.engine.Engine
destination_engine = sqlalchemy.create_engine("postgresql+psycopg2://alice:alice123@localhost:5433/pycram", echo=False) # example values
destination_session_maker = sqlalchemy.orm.sessionmaker(bind=destination_engine)

If you already have some data in your local database you can skip the next block, otherwise we will quickly create some example data

from pycram.designators.action_designator import *
from pycram.designators.location_designator import *
from pycram.process_module import simulated_robot
from pycram.tasktree import with_tree
from pycram.worlds.bullet_world import BulletWorld
from pycram.world_concepts.world_object import Object
from pycram.designators.object_designator import *
from pycrap.ontologies import Robot, Kitchen, Milk, Cereal


class ExamplePlans:
    def __init__(self):
        self.world = BulletWorld("DIRECT")
        self.pr2 = Object("pr2", Robot, "pr2.urdf")
        self.kitchen = Object("kitchen", Kitchen, "kitchen.urdf")
        self.milk = Object("milk", Milk, "milk.stl", pose=PoseStamped.from_list([1.3, 1, 0.9]))
        self.cereal = Object("cereal", Cereal, "breakfast_cereal.stl", pose=PoseStamped.from_list([1.3, 0.7, 0.95]))
        self.milk_desig = ObjectDesignatorDescription(names=["milk"])
        self.cereal_desig = ObjectDesignatorDescription(names=["cereal"])
        self.robot_desig = ObjectDesignatorDescription(names=["pr2"]).resolve()
        self.kitchen_desig = ObjectDesignatorDescription(names=["kitchen"])

    @with_tree
    def pick_and_place_plan(self):
        with simulated_robot:
            ParkArmsAction([Arms.BOTH]).resolve().perform()
            MoveTorsoAction([0.3]).resolve().perform()
            pickup_pose = CostmapLocation(target=self.cereal_desig.resolve(), reachable_for=self.robot_desig).resolve()
            pickup_arm = pickup_pose.reachable_arm
            NavigateAction(target_locations=[pickup_pose.pose]).resolve().perform()
            PickUpAction(object_designator_description=self.cereal_desig, arms=[pickup_arm],
                         grasps=["front"]).resolve().perform()
            ParkArmsAction([Arms.BOTH]).resolve().perform()

            place_island = SemanticCostmapLocation("kitchen_island_surface", self.kitchen_desig.resolve(),
                                                   self.cereal_desig.resolve()).resolve()

            place_stand = CostmapLocation(place_island.pose, reachable_for=self.robot_desig,
                                          reachable_arm=pickup_arm).resolve()

            NavigateAction(target_locations=[place_stand.pose]).resolve().perform()

            PlaceAction(self.cereal_desig, target_locations=[place_island.pose], arms=[pickup_arm]).resolve().perform()

            ParkArmsAction([Arms.BOTH]).resolve().perform()

import pycram.orm.utils           
import pycram.tasktree
            
with source_session_maker() as session:
    example_plans = ExamplePlans()
    for i in range(3):
        try:
            print("ExamplePlans run {}".format(i))
            example_plans.pick_and_place_plan()
            example_plans.world.reset_bullet_world()
            process_meta_data = pycram.orm.base.ProcessMetaData()
            process_meta_data.description = "Example Plan {}".format(i)
            process_meta_data.insert(session)
            pycram.tasktree.task_tree.root.insert(session)
            process_meta_data.reset()
        except Exception as e:
            print("Error: {}\n{}".format(type(e).__name__, e))
    session.commit()
    example_plans.world.exit()

Now that we have some example data or already had some example data all we need to do it migrate it over to the already existing PyCRORM NEEM-Hub.

pycram.orm.utils.migrate_neems(source_session_maker,destination_session_maker)

If the command ran successful the content of the source database should now be copied within the destination database. For example if we query for all the different meta_data, the previously defined instance come up.

with destination_session_maker() as session:
    statement = sqlalchemy.select('*').select_from(pycram.orm.base.ProcessMetaData)
    result = session.execute(statement).all()
    for item in result:
        print(item)

Looking at all the output, we can clearly see that the PyCRORM NEEM-Hub now contains our Example Plans 0 - 2.