diff --git a/CMakeLists.txt b/CMakeLists.txt
index cdbaa0a7b3e4daf5ed315551a187d20d7331f7fc..92945cf0dfae6d5a618821fbd29701da1265b399 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,7 +39,9 @@ set(dependencies
 
 add_library(air_navigation SHARED
         src/python_controller.cpp
-        src/python_interpreter.cpp)
+        src/python_interpreter.cpp
+        src/python_trajectory_critic.cpp
+        src/python_trajectory_generator.cpp)
 target_compile_definitions(air_navigation PUBLIC "PLUGINLIB__DISABLE_BOOST_FUNCTIONS")
 target_link_libraries(air_navigation ${PYTHON_LIBRARY}  )
 ament_target_dependencies(air_navigation
@@ -70,5 +72,6 @@ ament_export_libraries(air_navigation)
 ament_export_dependencies(${dependencies})
 
 pluginlib_export_plugin_description_file(nav2_core air_navigation_plugins.xml)
+pluginlib_export_plugin_description_file(dwb_core air_navigation_plugins.xml)
 
 ament_package()
diff --git a/air_navigation_plugins.xml b/air_navigation_plugins.xml
index 100dc8e85516757f629c9a302ef3d498fcc164f0..e0abdcd8275a1eeaf11576b2eadb686cc39777ee 100644
--- a/air_navigation_plugins.xml
+++ b/air_navigation_plugins.xml
@@ -5,5 +5,11 @@
                 air_navigation_python_controller
             </description>
         </class>
-    </library>
+    <class type="air_navigation::PythonTrajectoryGenerator" base_class_type="dwb_core::TrajectoryGenerator">
+      <description></description>
+    </class>
+    <class type="air_navigation::PythonTrajectoryCritic" base_class_type="dwb_core::TrajectoryCritic">
+      <description></description>
+    </class>
+  </library>
 </class_libraries>
diff --git a/include/air_navigation/py_interface.h b/include/air_navigation/py_interface.h
index c48013cb40f15ae34d32c72fc4ffafc73215a34f..53816a6f3b3cf0b0542014b5fa7a163de2304be5 100644
--- a/include/air_navigation/py_interface.h
+++ b/include/air_navigation/py_interface.h
@@ -29,6 +29,10 @@ namespace air_navigation::py_interface
   struct Twist { Vector3 linear; Vector3 angular; };
   struct TwistStamped { Header header; Twist twist; };
   struct Path { Header header; std::vector<PoseStamped> poses; };
+  struct Pose2D { double x, y, theta; };
+  struct Twist2D { double x, y, theta; };
+  struct Path2D { Header header;  std::vector<Pose2D> poses; };
+  struct Trajectory2D { Twist2D velocity; std::vector<Time> time_offsets; std::vector<Pose2D> poses; };
 
   template<typename _TS_, typename _TD_>
   inline void copy_header(const _TS_& s, _TD_* d)
@@ -80,6 +84,46 @@ namespace air_navigation::py_interface
     }
   }
 
+  template<typename _TS_, typename _TD_>
+  inline void copy_pose_2d(const _TS_& s, _TD_* d)
+  {
+    d->x = s.x;
+    d->y = s.y;
+    d->theta = s.theta;
+  }
+  template<typename _TS_, typename _TD_>
+  inline void copy_twist_2d(const _TS_& s, _TD_* d)
+  {
+    copy_pose_2d(s, d);
+  }
+  template<typename _TPS_, typename _TS_, typename _TD_>
+  inline void copy_path_2d(const _TS_& s, _TD_* d)
+  {
+    copy_header(s.header, &d->header);
+    for(auto p : s.poses)
+    {
+      _TPS_ dp;
+      copy_pose_2d(p, &dp);
+      d->poses.push_back(dp);
+    }
+  }  template<typename _TPS_, typename _TPT_, typename _TS_, typename _TD_>
+  inline void copy_trajectory_2d(const _TS_& s, _TD_* d)
+  {
+    copy_twist_2d(s.velocity, &d->velocity);
+    for(auto t : s.time_offsets)
+    {
+      _TPT_ dt;
+      dt.sec = t.sec;
+      dt.nanosec = t.nanosec;
+      d->time_offsets.push_back(dt);
+    }
+    for(auto p : s.poses)
+    {
+      _TPS_ dp;
+      copy_pose_2d(p, &dp);
+      d->poses.push_back(dp);
+    }
+  }
   class GoalChecker
   {
   public:
@@ -148,4 +192,32 @@ namespace air_navigation::py_interface
       std::cout << _text << std::endl;
     }
   };
+
+
+  class TrajectoryCritic
+  {
+  public:
+    TrajectoryCritic() = default;
+    virtual ~TrajectoryCritic() = default;
+
+    virtual void onInit() = 0;    
+    virtual void reset() = 0;    
+    virtual bool prepare(const Pose2D&, const Twist2D&, const Pose2D&, const Path2D&) = 0;
+    virtual double scoreTrajectory(const Trajectory2D & traj) = 0;
+    virtual void debrief(const Twist2D &) = 0;
+  };
+
+  class TrajectoryGenerator
+  {
+  public:
+    TrajectoryGenerator() = default;
+    virtual ~TrajectoryGenerator() = default;
+    virtual void initialize(const std::string& name) = 0;
+    virtual void reset() = 0;    
+    virtual void startNewIteration(const Twist2D & current_velocity) = 0;
+    virtual bool hasMoreTwists() = 0;
+    virtual Twist2D nextTwist() = 0;
+    virtual Trajectory2D generateTrajectory(const Pose2D & start_pose, const Twist2D & start_vel, const Twist2D & cmd_vel) = 0;
+    virtual void setSpeedLimit(double speed_limit, bool percentage) = 0;
+  };
 }
diff --git a/include/air_navigation/python_controller.h b/include/air_navigation/python_controller.h
index 22df1b84e485031bf4b147be8eaa9b9d69e25178..ceaf903b7aed9ca86045430eed6e4e2d88c34e5f 100644
--- a/include/air_navigation/python_controller.h
+++ b/include/air_navigation/python_controller.h
@@ -5,8 +5,7 @@
 #include <memory>
 
 #include "nav2_core/controller.hpp"
-#include "pluginlib/class_loader.hpp"
-#include "pluginlib/class_list_macros.hpp"
+
 
 namespace air_navigation
 {
@@ -41,9 +40,7 @@ public:
   void setSpeedLimit(const double & speed_limit, const bool & percentage) override;
 
 protected:
-void* wtf = nullptr;
   py_interface::Controller* m_python_controller_interface = nullptr;
-
 };
 
 }  // namespace nav2_pure_pursuit_controller
diff --git a/include/air_navigation/python_interpreter.h b/include/air_navigation/python_interpreter.h
index 02d831109094d72a2237db8f3d3667ab45d1e4d9..c5946a0233e8e19a1a21c8c08e79e8278cd18ec8 100644
--- a/include/air_navigation/python_interpreter.h
+++ b/include/air_navigation/python_interpreter.h
@@ -5,6 +5,8 @@ namespace air_navigation
   namespace py_interface
   {
     class Controller;
+    class TrajectoryCritic;
+    class TrajectoryGenerator;
   }
   class python_interpreter
   {
@@ -15,6 +17,8 @@ namespace air_navigation
     ~python_interpreter();
   public:
     py_interface::Controller* create_controller(const std::string& _module, const std::string& _class);
+    py_interface::TrajectoryCritic* create_trajectory_critic(const std::string& _module, const std::string& _class);
+    py_interface::TrajectoryGenerator* create_trajectory_generator(const std::string& _module, const std::string& _class);
     void release_controller(py_interface::Controller* _controller);
     void acquire_lock();
     void release_lock();
diff --git a/include/air_navigation/python_trajectory_critic.h b/include/air_navigation/python_trajectory_critic.h
new file mode 100644
index 0000000000000000000000000000000000000000..603fca3c7b6d82334c2a0bc203b0f9619536c8f1
--- /dev/null
+++ b/include/air_navigation/python_trajectory_critic.h
@@ -0,0 +1,23 @@
+#include <dwb_core/trajectory_critic.hpp>
+
+namespace air_navigation
+{
+  namespace py_interface
+  {
+    class TrajectoryCritic;
+  }
+
+  class PythonTrajectoryCritic : public dwb_core::TrajectoryCritic
+  {
+  public:
+    PythonTrajectoryCritic() = default;
+    ~PythonTrajectoryCritic() = default;
+    void onInit() override;
+    void reset() override;
+    bool prepare(const geometry_msgs::msg::Pose2D & pose, const nav_2d_msgs::msg::Twist2D & vel, const geometry_msgs::msg::Pose2D & goal, const nav_2d_msgs::msg::Path2D & global_plan) override;
+    double scoreTrajectory(const dwb_msgs::msg::Trajectory2D & traj) override;
+    void debrief(const nav_2d_msgs::msg::Twist2D &) override;
+  private:
+    py_interface::TrajectoryCritic* m_python_trajectory_generator_interface = nullptr;
+  };
+}
diff --git a/include/air_navigation/python_trajectory_generator.h b/include/air_navigation/python_trajectory_generator.h
new file mode 100644
index 0000000000000000000000000000000000000000..555d26de1cf8eae9ea939473dcd8993a14872bc6
--- /dev/null
+++ b/include/air_navigation/python_trajectory_generator.h
@@ -0,0 +1,25 @@
+#include <dwb_core/trajectory_generator.hpp>
+
+namespace air_navigation
+{
+  namespace py_interface
+  {
+    class TrajectoryGenerator;
+  }
+
+  class PythonTrajectoryGenerator : public dwb_core::TrajectoryGenerator
+  {
+  public:
+    PythonTrajectoryGenerator() = default;
+    ~PythonTrajectoryGenerator() = default;
+    void initialize(const nav2_util::LifecycleNode::SharedPtr & nh, const std::string & plugin_name) override;
+    void reset() override;
+    void startNewIteration(const nav_2d_msgs::msg::Twist2D & current_velocity) override;
+    bool hasMoreTwists() override;
+    nav_2d_msgs::msg::Twist2D nextTwist() override;
+    dwb_msgs::msg::Trajectory2D generateTrajectory(const geometry_msgs::msg::Pose2D & start_pose, const nav_2d_msgs::msg::Twist2D & start_vel, const nav_2d_msgs::msg::Twist2D & cmd_vel) override;
+    void setSpeedLimit(const double & speed_limit, const bool & percentage) override;
+  private:
+    py_interface::TrajectoryGenerator* m_python_trajectory_generator_interface = nullptr;
+  };
+}
diff --git a/python/air_navigation/__init__.py b/python/air_navigation/__init__.py
index 0a62cbb66520ad04255b17c03dddd5420522ac35..724b17be1586530af0c1b06e07910272e1708d80 100644
--- a/python/air_navigation/__init__.py
+++ b/python/air_navigation/__init__.py
@@ -1,4 +1,9 @@
 import air_navigation_
 
 Controller = air_navigation_.air_navigation.py_interface.Controller
+TrajectoryCritic = air_navigation_.air_navigation.py_interface.TrajectoryCritic
+TrajectoryGenerator = air_navigation_.air_navigation.py_interface.TrajectoryGenerator
 TwistStamped = air_navigation_.air_navigation.py_interface.TwistStamped
+Twist2D = air_navigation_.air_navigation.py_interface.Twist2D
+Pose2D = air_navigation_.air_navigation.py_interface.Pose2D
+Trajectory2D = air_navigation_.air_navigation.py_interface.Trajectory2D
diff --git a/python/air_navigation/py_interface.sip b/python/air_navigation/py_interface.sip
index 3b64e4e9685594934dcb1f01bb03c2531488c9ee..8497272f226f3bbd507999b1f3cfe1dd08c4cef0 100644
--- a/python/air_navigation/py_interface.sip
+++ b/python/air_navigation/py_interface.sip
@@ -30,6 +30,10 @@ namespace air_navigation
     struct Twist { Vector3 linear; Vector3 angular; };
     struct TwistStamped { Header header; Twist twist; };
     struct Path { Header header; std::vector<air_navigation::py_interface::PoseStamped> poses; };
+    struct Pose2D { double x; double y; double theta; };
+    struct Twist2D { double x; double y; double theta; };
+    struct Path2D { Header header;  std::vector<air_navigation::py_interface::Pose2D> poses; };
+    struct Trajectory2D { Twist2D velocity; std::vector<air_navigation::py_interface::Time> time_offsets; std::vector<air_navigation::py_interface::Pose2D> poses; };
 
     class GoalChecker /NoDefaultCtors/
     {
@@ -65,5 +69,31 @@ namespace air_navigation
 
       void print(const std::string& _text);
     };
+    class TrajectoryCritic
+    {
+    public:
+      TrajectoryCritic();
+      virtual ~TrajectoryCritic();
+
+      virtual void onInit() = 0;    
+      virtual void reset() = 0;    
+      virtual bool prepare(const Pose2D&, const Twist2D&, const Pose2D&, const Path2D&) = 0;
+      virtual double scoreTrajectory(const Trajectory2D & traj) = 0;
+      virtual void debrief(const Twist2D &) = 0;
+    };
+
+    class TrajectoryGenerator
+    {
+    public:
+      TrajectoryGenerator();
+      virtual ~TrajectoryGenerator();
+      virtual void initialize(const std::string& name) = 0;
+      virtual void reset() = 0;    
+      virtual void startNewIteration(const Twist2D & current_velocity) = 0;
+      virtual bool hasMoreTwists() = 0;
+      virtual Twist2D nextTwist() = 0;
+      virtual Trajectory2D generateTrajectory(const Pose2D & start_pose, const Twist2D & start_vel, const Twist2D & cmd_vel) = 0;
+      virtual void setSpeedLimit(double speed_limit, bool percentage) = 0;
+    };
   };
 };
diff --git a/src/python_controller.cpp b/src/python_controller.cpp
index c8369f4882ad7c202fc187feb9606fd856e34e80..5961d31b5defbf05e4676f3b2bcd9ada029ec519 100644
--- a/src/python_controller.cpp
+++ b/src/python_controller.cpp
@@ -4,8 +4,6 @@
 #include <memory>
 #include <iostream>
 
-#include "Python.h"
-
 #include "nav2_util/node_utils.hpp"
 #include "air_navigation/python_controller.h"
 #include "air_navigation/py_interface.h"
@@ -105,5 +103,8 @@ void PythonController::setSpeedLimit(const double & speed_limit, const bool & pe
   }
 }
 
+#include "pluginlib/class_loader.hpp"
+#include "pluginlib/class_list_macros.hpp"
+
 // Register this controller as a nav2_core plugin
 PLUGINLIB_EXPORT_CLASS(air_navigation::PythonController, nav2_core::Controller)
diff --git a/src/python_interpreter.cpp b/src/python_interpreter.cpp
index 8df356e8bf675ead8e9ba2ec21c2ab634e7f5cdd..e4491a0e32304c18ff0b421118b2e4daccdc3811 100644
--- a/src/python_interpreter.cpp
+++ b/src/python_interpreter.cpp
@@ -22,6 +22,9 @@ struct python_interpreter::Private
   // PyThreadState* state = 0;
   PyGILState_STATE state;
   bool self_initialise = false;
+
+  template<typename _T_>
+  _T_* create_object(const std::string& _module, const std::string& _class, const char* _cpp_name);
 };
 
 python_interpreter* python_interpreter::instance()
@@ -56,9 +59,10 @@ python_interpreter::~python_interpreter()
   delete d;
 }
 
-py_interface::Controller* python_interpreter::create_controller(const std::string& _module, const std::string& _class)
+template<typename _T_>
+_T_* python_interpreter::Private::create_object(const std::string& _module, const std::string& _class, const char* _cpp_name)
 {
-  acquire_lock();
+  python_lock pl;
   // PyRun_SimpleString("import air_navigation");
   PyObject *pModule = PyImport_Import(PyUnicode_DecodeFSDefault(_module.c_str()));
   if(pModule)
@@ -73,10 +77,9 @@ py_interface::Controller* python_interpreter::create_controller(const std::strin
       Py_DECREF(pFunc);
       int isErr = 0;
       int state;
-      const sipTypeDef *td = get_sip_api()->api_find_type("air_navigation::py_interface::Controller");
-      py_interface::Controller* controller = reinterpret_cast<py_interface::Controller*>(get_sip_api()->api_convert_to_type(pValue, td, NULL, SIP_NOT_NONE, &state, &isErr));
+      const sipTypeDef *td = get_sip_api()->api_find_type(_cpp_name);
+      _T_* controller = reinterpret_cast<_T_*>(get_sip_api()->api_convert_to_type(pValue, td, NULL, SIP_NOT_NONE, &state, &isErr));
       get_sip_api()->api_transfer_to(pValue, Py_None);
-      release_lock();
       return controller;
     } else {
       PyErr_Print();
@@ -87,8 +90,24 @@ py_interface::Controller* python_interpreter::create_controller(const std::strin
     PyErr_Print();
     RCLCPP_ERROR_STREAM(rclcpp::get_logger("python_interpreter"), "Failed to load module '" << _module << "'");
   }
-  release_lock();
   return nullptr;
+
+}
+
+py_interface::Controller* python_interpreter::create_controller(const std::string& _module, const std::string& _class)
+{
+  return d->create_object<py_interface::Controller>(_module, _class, "air_navigation::py_interface::Controller");
+}
+
+py_interface::TrajectoryCritic* python_interpreter::create_trajectory_critic(const std::string& _module, const std::string& _class)
+{
+  return d->create_object<py_interface::TrajectoryCritic>(_module, _class, "air_navigation::py_interface::TrajectoryCritic");
+
+}
+
+py_interface::TrajectoryGenerator* python_interpreter::create_trajectory_generator(const std::string& _module, const std::string& _class)
+{
+  return d->create_object<py_interface::TrajectoryGenerator>(_module, _class, "air_navigation::py_interface::TrajectoryGenerator");
 }
 
 void python_interpreter::release_controller(py_interface::Controller* )
diff --git a/src/python_trajectory_critic.cpp b/src/python_trajectory_critic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ecd1aaec4a1fb5ed90bd1c8d0a03bc487ee48af8
--- /dev/null
+++ b/src/python_trajectory_critic.cpp
@@ -0,0 +1,86 @@
+#include "air_navigation/python_trajectory_critic.h"
+
+#include "air_navigation/py_interface.h"
+#include "air_navigation/python_interpreter.h"
+#include "nav_2d_utils/parameters.hpp"
+
+using namespace air_navigation;
+
+void PythonTrajectoryCritic::onInit()
+{
+  auto node = node_.lock();
+  if (!node) {
+    throw std::runtime_error{"Failed to lock node"};
+  }
+
+  std::string module_name = nav_2d_utils::searchAndGetParam(
+    node,
+    dwb_plugin_name_ + "." + name_ + ".module_name", std::string());
+  std::string class_name = nav_2d_utils::searchAndGetParam(
+    node,
+    dwb_plugin_name_ + "." + name_ + ".class_name", std::string());
+
+  RCLCPP_INFO_STREAM(node->get_logger(), "Python critic will use: " << module_name << "." << class_name);
+  m_python_trajectory_generator_interface = air_navigation::python_interpreter::instance()->create_trajectory_critic(module_name, class_name);;
+  if(not m_python_trajectory_generator_interface)
+  {
+    RCLCPP_ERROR_STREAM(node->get_logger(), "Failed to construct critic!");
+  } else {
+    python_lock pl;
+    m_python_trajectory_generator_interface->onInit();
+  }
+
+}
+
+void PythonTrajectoryCritic::reset()
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface) m_python_trajectory_generator_interface->reset();
+}
+
+bool PythonTrajectoryCritic::prepare(const geometry_msgs::msg::Pose2D & pose, const nav_2d_msgs::msg::Twist2D & vel, const geometry_msgs::msg::Pose2D & goal, const nav_2d_msgs::msg::Path2D & global_plan)
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface)
+  {
+    py_interface::Pose2D py_pose;
+    py_interface::Twist2D py_vel;
+    py_interface::Pose2D py_goal;
+    py_interface::Path2D py_global_plan;
+
+    py_interface::copy_pose_2d(pose, &py_pose);
+    py_interface::copy_twist_2d(vel, &py_vel);
+    py_interface::copy_pose_2d(goal, &py_goal);
+    py_interface::copy_path_2d<py_interface::Pose2D>(global_plan, &py_global_plan);
+
+    return m_python_trajectory_generator_interface->prepare(py_pose, py_vel, py_goal, py_global_plan);
+  }
+  return false;
+}
+double PythonTrajectoryCritic::scoreTrajectory(const dwb_msgs::msg::Trajectory2D & traj)
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface)
+  {
+    py_interface::Trajectory2D py_traj;
+    py_interface::copy_trajectory_2d<py_interface::Pose2D, py_interface::Time>(traj, &py_traj);
+    return m_python_trajectory_generator_interface->scoreTrajectory(py_traj);
+  }
+  return 0.0;
+}
+void PythonTrajectoryCritic::debrief(const nav_2d_msgs::msg::Twist2D & vel)
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface)
+  {
+    py_interface::Twist2D py_vel;
+    py_interface::copy_twist_2d(vel, &py_vel);
+    return m_python_trajectory_generator_interface->debrief(py_vel);
+  }
+
+}
+
+#include "pluginlib/class_loader.hpp"
+#include "pluginlib/class_list_macros.hpp"
+
+PLUGINLIB_EXPORT_CLASS(air_navigation::PythonTrajectoryCritic, dwb_core::TrajectoryCritic)
diff --git a/src/python_trajectory_generator.cpp b/src/python_trajectory_generator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..309fdda8281857602e0b241072738c16447dafd2
--- /dev/null
+++ b/src/python_trajectory_generator.cpp
@@ -0,0 +1,98 @@
+#include "air_navigation/python_trajectory_generator.h"
+
+#include "air_navigation/py_interface.h"
+#include "air_navigation/python_interpreter.h"
+#include "nav_2d_utils/parameters.hpp"
+
+using namespace air_navigation;
+
+void PythonTrajectoryGenerator::initialize(const nav2_util::LifecycleNode::SharedPtr & nh, const std::string & plugin_name)
+{
+  std::string module_name = nav_2d_utils::searchAndGetParam(
+    nh,
+    plugin_name + ".air_navigation::PythonTrajectoryGenerator.module_name", std::string());
+  std::string class_name = nav_2d_utils::searchAndGetParam(
+    nh,
+    plugin_name + ".air_navigation::PythonTrajectoryGenerator.class_name", std::string());
+
+  RCLCPP_INFO_STREAM(nh->get_logger(), "Python trajectory generator will use: " << plugin_name);
+
+  RCLCPP_INFO_STREAM(nh->get_logger(), "Python trajectory generator will use: " << module_name << "." << class_name);
+  m_python_trajectory_generator_interface = air_navigation::python_interpreter::instance()->create_trajectory_generator(module_name, class_name);;
+  if(not m_python_trajectory_generator_interface)
+  {
+    RCLCPP_ERROR_STREAM(nh->get_logger(), "Failed to trajectory generator critic!");
+  } else {
+    python_lock pl;
+    m_python_trajectory_generator_interface->initialize(plugin_name);
+  }
+
+
+}
+
+void PythonTrajectoryGenerator::reset()
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface) m_python_trajectory_generator_interface->reset();
+
+}
+
+void PythonTrajectoryGenerator::startNewIteration(const nav_2d_msgs::msg::Twist2D & current_velocity)
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface)
+  {
+    py_interface::Twist2D py_current_velocity;
+    py_interface::copy_twist_2d(current_velocity, &py_current_velocity);
+    m_python_trajectory_generator_interface->startNewIteration(py_current_velocity);
+  }
+}
+
+bool PythonTrajectoryGenerator::hasMoreTwists()
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface) return m_python_trajectory_generator_interface->hasMoreTwists();
+  return false;
+}
+
+nav_2d_msgs::msg::Twist2D PythonTrajectoryGenerator::nextTwist()
+{
+  python_lock pl;
+  nav_2d_msgs::msg::Twist2D twist;
+  if(m_python_trajectory_generator_interface)
+  {
+    py_interface::Twist2D py_twist = m_python_trajectory_generator_interface->nextTwist();
+    py_interface::copy_twist_2d(py_twist, &twist);
+  }
+  return twist;
+}
+
+dwb_msgs::msg::Trajectory2D PythonTrajectoryGenerator::generateTrajectory(const geometry_msgs::msg::Pose2D & start_pose, const nav_2d_msgs::msg::Twist2D & start_vel, const nav_2d_msgs::msg::Twist2D & cmd_vel)
+{
+  python_lock pl;
+  dwb_msgs::msg::Trajectory2D trajectory;
+  if(m_python_trajectory_generator_interface)
+  {
+    py_interface::Pose2D py_start_pose;
+    py_interface::Twist2D py_start_vel, py_cmd_vel;
+
+    py_interface::copy_pose_2d(start_pose, &py_start_pose);
+    py_interface::copy_twist_2d(start_vel, &py_start_vel);
+    py_interface::copy_twist_2d(cmd_vel, &py_cmd_vel);
+    
+    py_interface::Trajectory2D py_trajectory = m_python_trajectory_generator_interface->generateTrajectory(py_start_pose, py_start_vel, py_cmd_vel);
+    py_interface::copy_trajectory_2d<geometry_msgs::msg::Pose2D, builtin_interfaces::msg::Duration>(py_trajectory, &trajectory);
+  }
+  return trajectory;
+}
+
+void PythonTrajectoryGenerator::setSpeedLimit(const double & speed_limit, const bool & percentage)
+{
+  python_lock pl;
+  if(m_python_trajectory_generator_interface) m_python_trajectory_generator_interface->setSpeedLimit(speed_limit, percentage);
+}
+
+#include "pluginlib/class_loader.hpp"
+#include "pluginlib/class_list_macros.hpp"
+
+PLUGINLIB_EXPORT_CLASS(air_navigation::PythonTrajectoryGenerator, dwb_core::TrajectoryGenerator)