Pick and Place / minimal.cpp

Create a New Package

ros2 pkg create --build-type ament_cmake --node-name mtc_tutorial mtc_tutorial

package.xml

    <?xml version="1.0"?>
    <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
    <package format="3">
    <name>mtc_tutorial</name>
    <version>0.0.0</version>
    <description>TODO: Package description</description>
    <maintainer email="youremail@domain.com">user</maintainer>
    <license>TODO: License declaration</license>

    <buildtool_depend>ament_cmake</buildtool_depend>

    <depend>moveit_task_constructor_core</depend>
    <depend>rclcpp</depend>

    <test_depend>ament_lint_auto</test_depend>
    <test_depend>ament_lint_common</test_depend>

    <export>
        <build_type>ament_cmake</build_type>
    </export>
    </package>

CMakeLists.txt

    cmake_minimum_required(VERSION 3.8)
    project(mtc_tutorial)

    if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    add_compile_options(-Wall -Wextra -Wpedantic)
    endif()

    # find dependencies
    find_package(ament_cmake REQUIRED)
    find_package(moveit_task_constructor_core REQUIRED)
    find_package(rclcpp REQUIRED)
    # uncomment the following section in order to fill in
    # further dependencies manually.
    # find_package(<dependency> REQUIRED)

    add_executable(mtc_tutorial src/mtc_tutorial.cpp)
    ament_target_dependencies(mtc_tutorial moveit_task_constructor_core rclcpp)
    target_include_directories(mtc_tutorial PUBLIC
    $<BUILD_INTERFACE:${
   
   CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>)
    target_compile_features(mtc_tutorial PUBLIC c_std_99 cxx_std_17)  # Require C99 and C++17

    install(TARGETS mtc_tutorial
    DESTINATION lib/${
   
   PROJECT_NAME})

    if(BUILD_TESTING)
    find_package(ament_lint_auto REQUIRED)
    # the following line skips the linter which checks for copyrights
    # uncomment the line when a copyright and license is not present in all source files
    #set(ament_cmake_copyright_FOUND TRUE)
    # the following line skips cpplint (only works in a git repo)
    # uncomment the line when this package is not in a git repo
    #set(ament_cmake_cpplint_FOUND TRUE)
    ament_lint_auto_find_test_dependencies()
    endif()

    ament_package()

MoveIt Task Constructor

include

  • rclcpp/rclcpp.hpp includes core ROS2 functionality
  • moveit/planning_scene/planning_scene.h and moveit/planning_scene_interface/planning_scene_interface.h includes functionality to interface with the robot model and collision objects
  • moveit/task_constructor/task.h, moveit/task_constructor/solvers.h, and moveit/task_constructor/stages.h include different components of MoveIt Task Constructor that are used in the example
  • tf2_geometry_msgs/tf2_geometry_msgs.hpp and tf2_eigen/tf2_eigen.hpp won’t be used in this initial example, but they will be used for pose generation when we add more stages to the MoveIt Task Constructor task.
    #include <rclcpp/rclcpp.hpp>
    #include <moveit/planning_scene/planning_scene.h>
    #include <moveit/planning_scene_interface/planning_scene_interface.h>
    #include <moveit/task_constructor/task.h>
    #include <moveit/task_constructor/solvers.h>
    #include <moveit/task_constructor/stages.h>
    #if __has_include(<tf2_geometry_msgs/tf2_geometry_msgs.hpp>)
    #include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
    #else
    #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
    #endif
    #if __has_include(<tf2_eigen/tf2_eigen.hpp>)
    #include <tf2_eigen/tf2_eigen.hpp>
    #else
    #include <tf2_eigen/tf2_eigen.h>
    #endif

logger

The next line gets a logger for your new node. We also create a namespace alias for moveit::task_constructor for convenience.

    static const rclcpp::Logger LOGGER = rclcpp::get_logger("mtc_tutorial");
    namespace mtc = moveit::task_constructor;

class

We start by defining a class that will contain the main MoveIt Task Constructor functionality. We also declare the MoveIt Task Constructor task object (task_) as a member variable for our class: this isn’t strictly necessary for a given application, but it helps save the task for later visualization purposes. We will explore each function individually below.

    class MTCTaskNode
    {
   
   
    public:
      MTCTaskNode(const rclcpp::NodeOptions& options);

      rclcpp::node_interfaces::NodeBaseInterface::SharedPtr getNodeBaseInterface();

      void doTask();

      void setupPlanningScene();

    private:
      // Compose an MTC task from a series of stages.
      mtc::Task createTask();
      mtc::Task task_;
      rclcpp::Node::SharedPtr node_;
    };

getter

These lines define a getter function to get the node base interface, which will be used for the executor later.

    rclcpp::node_interfaces::NodeBaseInterface::SharedPtr MTCTaskNode::getNodeBaseInterface()
    {
   
   
      return node_->get_node_base_interface();
    }

node

These next lines initialize the node with specified options.

    MTCTaskNode::MTCTaskNode(const rclcpp::NodeOptions& options)
      : node_{
   
    std::make_shared<rclcpp::Node>("mtc_node", options) }
    {
   
   
    }

PlanningScene

This class method is used to set up the planning scene that is used in the example. It creates a cylinder with dimensions specified by object.primitives[0].dimensions and position specified by pose.position.z and pose.position.x. You can try changing these numbers to resize and move the cylinder around. If you move the cylinder out of the robot’s reach, planning will fail.

    void MTCTaskNode::setupPlanningScene()
    {
   
   
      moveit_msgs::msg::CollisionObject object;
      object.id = "object";
      object.header.frame_id = "world";
      object.primitives.resize(1);
      object.primitives[0].type = shape_msgs::msg::SolidPrimitive::CYLINDER;
      object.primitives[0].dimensions = {
   
    0.1, 0.02 };

      geometry_msgs::msg::Pose pose;
      pose.position.x = 0.5;
      pose.position.y = -0.25;
      object.pose = pose;

      moveit::planning_interface::PlanningSceneInterface psi;
      psi.applyCollisionObject(object);
    }

doTask

This function interfaces with the MoveIt Task Constructor task object. It first creates a task, which includes setting some properties and adding stages. This will be discussed further in the createTask function definition. Next, task.init() initializes the task and task.plan(5) generates a plan, stopping after 5 successful plans are found. The next line publishes the solution to be visualized in RViz - this line can be removed if you don’t care for visualization. Finally, task.execute() executes the plan. Execution occurs via an action server interface with the RViz plugin.

    void MTCTaskNode::doTask()
    {
   
   
      task_ = createTask();

      try
      {
   
   
        task_.init();
      }
      catch (mtc::InitStageException& e)
      {
   
   
        RCLCPP_ERROR_STREAM(LOGGER, e);
        return;
      }

      if (!task_.plan(5))
      {
   
   
        RCLCPP_ERROR_STREAM(LOGGER, "Task planning failed");
        return;
      }
      task_.introspection().publishSolution(*task_.solutions().front());

      auto result = task_.execute(*task_.solutions().front());
      if (result.val != moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
      {
   
   
        RCLCPP_ERROR_STREAM(LOGGER, "Task execution failed");
        return;
      }

      return;
    }

CreateTask

As mentioned above, this function creates a MoveIt Task Constructor object and sets some initial properties. In this case, we set the task name to “demo_task”, load the robot model, define the names of some useful frames, and set those frame names as properties of the task with task.setProperty(property_name, value). The next few code blocks will fill out this function body.

    mtc::Task MTCTaskNode::createTask()
    {
   
   
      moveit::task_constructor::Task task;
      task.stages()->setName("demo task");
      task.loadRobotModel(node_);

      const auto& arm_group_name = "panda_arm";
      const auto& hand_group_name = "hand";
      const auto& hand_frame = "panda_hand";

      // Set task properties
      task.setProperty("group", arm_group_name);
      task.setProperty("eef", hand_group_name);
      task.setProperty("ik_frame", hand_frame);

AddStage

Now, we add an example stage to the node. The first line sets current_state_ptr to nullptr; this creates a pointer to a stage such that we can re-use stage information in specific scenarios. This line is not used at this moment, but will be used later when more stages are added to the task. Next, we make a current_state stage (a generator stage) and add it to our task - this starts the robot off in its current state. Now that we’ve created the CurrentState stage, we save a pointer to it in the current_state_ptr for later use.

      mtc::Stage* current_state_ptr = nullptr;  // Forward current_state on to grasp pose generator
      auto stage_state_current = std::make_unique<mtc::stages::CurrentState>("current");
      current_state_ptr = stage_state_current.get();
      task.add(std::move(stage_state_current));

solvers

In order to plan any robot motions, we need to specify a solver. MoveIt Task Constructor has three options for solvers:

  • PipelinePlanner uses MoveIt’s planning pipeline, which typically defaults to OMPL.
    auto sampling_planner = std::make_shared<mtc::solvers::PipelinePlanner>(node_);
    
  • CartesianPath is used to move the end effector in a straight line in Cartesian space.
    auto cartesian_planner = std::make_shared<mtc::solvers::CartesianPath>();
    
  • JointInterpolation is a simple planner that interpolates between the start and goal joint states. It is typically used for simple motions as it computes quickly but doesn’t support complex motions.
    auto interpolation_planner = std::make_shared<mtc::solvers::JointInterpolationPlanner>();
    

We also set some properties specific for to the Cartesian planner.

      auto sampling_planner = std::make_shared<mtc::solvers::PipelinePlanner>(node_);
      auto interpolation_planner = std::make_shared<mtc::solvers::JointInterpolationPlanner>();

      auto cartesian_planner = std::make_shared<mtc::solvers::CartesianPath>();
      cartesian_planner->setMaxV
<think>我们遇到了头文件包含错误:`pthash/pthash.hpp` 找不到。这通常是因为编译器在指定的头文件搜索路径中找不到该文件。 我们已经在编译命令中通过 `-I/home/pthash/include` 指定了头文件搜索路径。因此,我们需要确保在该路径下确实存在 `pthash/pthash.hpp` 文件。 解决方案: 1. 检查头文件实际路径:确认 `/home/pthash/include` 目录下是否有 `pthash` 子目录,并且子目录中有 `pthash.hpp` 文件。 2. 如果路径结构不一致,调整编译命令中的 `-I` 参数,使其能够正确包含头文件目录。 具体步骤: 步骤1:验证头文件路径 在终端运行: ls /home/pthash/include/pthash/pthash.hpp 如果这个文件存在,那么可能是其他问题(比如权限),但通常错误信息会不同。如果不存在,则可能是安装路径不对。 步骤2:调整包含路径 如果头文件的实际路径是 `/home/pthash/include/pthash.hpp`(没有中间的pthash子目录),那么应该修改源代码中的包含指令为: #include <pthash.hpp> 但根据错误信息,源代码中写的是 `#include <pthash/pthash.hpp>`,所以我们需要确保头文件目录结构匹配。 步骤3:调整安装路径 如果头文件被安装在 `/home/pthash/include` 的子目录下(比如 `/home/pthash/include/pthash/...`),那么编译命令中的 `-I` 参数应该指向包含 `pthash` 目录的父目录,即 `/home/pthash/include` 本身。这样,在代码中写 `#include <pthash/pthash.hpp>` 就会在 `/home/pthash/include/pthash/pthash.hpp` 找到文件。 步骤4:如果验证发现头文件不在指定位置,可能需要重新安装PTHash库,或者将头文件复制到正确位置。 步骤5:如果头文件路径正确,但仍有问题,检查文件权限: ls -l /home/pthash/include/pthash/pthash.hpp 确保当前用户有读取权限。 步骤6:如果以上都正确,可以尝试在编译命令中添加 `-v` 选项来查看详细的头文件搜索路径: g++ -v -std=c++11 -O3 -lpthread -I/home/pthash/include pthash.cpp -o pthash 在输出中,你可以看到所有的头文件搜索路径,确认 `/home/pthash/include` 是否在其中,并且在该路径下是否有 `pthash` 子目录。 示例调整: 假设我们发现头文件实际在 `/home/pthash/include/pthash.hpp`,那么我们可以: 1. 修改源代码:将 `#include <pthash/pthash.hpp>` 改为 `#include <pthash.hpp>` 2. 或者,创建一个符号链接(如果不方便修改源代码): cd /home/pthash/include mkdir pthash cd pthash ln -s ../pthash.hpp . 这样,`#include <pthash/pthash.hpp>` 就会找到 `/home/pthash/include/pthash/pthash.hpp`(即链接到`../pthash.hpp`)。 但是,最好的方法是按照库的约定来安装。如果库默认安装头文件在 `include/pthash` 目录下,那么我们应该确保安装过程正确创建了这个目录结构。 如果用户没有正确安装库,我们可以尝试从源码安装: 通常,PTHash库的安装步骤可能如下: git clone https://github.com/jermp/pthash.git cd pthash mkdir build cd build cmake .. -DCMAKE_INSTALL_PREFIX=/home/pthash make -j make install 这样,头文件会被安装到 `/home/pthash/include/pthash` 目录下。 如果以上步骤都无效,我们可以尝试在编译命令中直接使用头文件所在的确切目录(如果头文件散落在其他位置)。 但是,根据错误信息,问题很可能是头文件目录结构不符合预期。 因此,我们首先需要检查头文件路径。 如果用户已经确认头文件在正确的位置,那么我们可以考虑以下代码示例来测试一个简单的程序,以确认编译器设置: 创建一个简单的测试程序(test_pthash.cpp): ```cpp #include <pthash/pthash.hpp> #include <iostream> int main() { std::cout << "PTHASH_VERSION: " << PTHASH_VERSION << std::endl; return 0; } ``` 然后编译: g++ -std=c++11 -I/home/pthash/include test_pthash.cpp -o test_pthash 如果这个简单测试通过,说明原项目代码可能有其他问题。如果不通过,则说明头文件配置问题。 最后,如果用户无法解决安装问题,可以考虑使用环境变量来设置包含路径: export CPLUS_INCLUDE_PATH=/home/pthash/include:$CPLUS_INCLUDE_PATH g++ -std=c++11 -O3 -lpthread pthash.cpp -o pthash 这样就不需要在命令行中指定 `-I` 了。 但是,根据错误信息,最直接的原因还是头文件路径不对,所以请用户先按照步骤1进行验证。</think>### 解决 `pthash/pthash.hpp` 头文件找不到的问题 #### 问题原因分析 这个错误表明编译器在指定的包含路径 `/home/pthash/include` 下找不到 `pthash/pthash.hpp` 文件。可能的原因包括: 1. **路径结构不匹配**:头文件实际位置可能是 `/home/pthash/include/pthash.hpp` 而非 `/home/pthash/include/pthash/pthash.hpp` 2. **安装不完整**:PTHash 库未正确安装或文件被误删除 3. **版本差异**:不同版本的 PTHash 可能有不同的头文件组织方式 4. **环境问题**:文件权限或符号链接问题 --- #### 解决方案 **步骤1:验证头文件实际位置** ```bash # 检查头文件是否存在 find /home/pthash -name pthash.hpp # 检查目录结构 ls -R /home/pthash/include ``` **步骤2:根据检查结果选择解决方案** **情况A:头文件在 `/home/pthash/include/pthash.hpp`** 修改源代码中的包含指令: ```cpp // 修改前 #include <pthash/pthash.hpp> // 修改后 #include <pthash.hpp> ``` **情况B:头文件在子目录中** ```bash # 如果头文件实际在 /home/pthash/include/pthash/pthash.hpp # 但编译器找不到,可能是权限问题 ls -l /home/pthash/include/pthash/pthash.hpp sudo chmod -R a+r /home/pthash/include # 添加读取权限 ``` **情况C:头文件不存在(需要重新安装)** ```bash # 1. 克隆仓库 git clone https://github.com/jermp/pthash.git cd pthash # 2. 创建构建目录 mkdir build cd build # 3. 配置安装路径 cmake .. -DCMAKE_INSTALL_PREFIX=/home/pthash # 4. 编译并安装 make -j$(nproc) sudo make install ``` **步骤3:替代解决方案(不修改代码)** ```bash # 创建符号链接匹配预期结构 sudo mkdir -p /home/pthash/include/pthash sudo ln -s /home/pthash/include/pthash.hpp /home/pthash/include/pthash/pthash.hpp # 或者添加额外包含路径 g++ -std=c++11 -O3 -lpthread -I/home/pthash -I/home/pthash/include pthash.cpp -o pthash ``` --- #### 验证安装的完整代码 ```cpp #include <iostream> #include <vector> // 根据实际情况选择包含方式 // #include <pthash.hpp> #include <pthash/pthash.hpp> int main() { std::vector<uint64_t> keys = {123456789, 987654321}; pthash::build_configuration config; config.c = 6.0; config.alpha = 0.94; config.minimal_output = true; config.verbose_output = true; pthash::single_phf<pthash::murmurhash2_64> f; f.build_in_internal_memory(keys.begin(), keys.size(), config); std::cout << "PTHash 测试成功! 哈希大小: " << f.num_bits() << " bits" << std::endl; return 0; } ``` --- #### 预防措施 1. **使用 CMake 管理依赖** ```cmake find_package(PkgConfig REQUIRED) pkg_check_modules(PTHASH REQUIRED pthash) add_executable(pthash_app pthash.cpp) target_include_directories(pthash_app PRIVATE ${PTHASH_INCLUDE_DIRS}) target_link_libraries(pthash_app PRIVATE ${PTHASH_LIBRARIES} pthread) ``` 2. **环境变量配置** ```bash # 在 ~/.bashrc 中添加 export PTHASH_ROOT=/home/pthash export CPLUS_INCLUDE_PATH=$PTHASH_ROOT/include:$CPLUS_INCLUDE_PATH export LIBRARY_PATH=$PTHASH_ROOT/lib:$LIBRARY_PATH export LD_LIBRARY_PATH=$PTHASH_ROOT/lib:$LD_LIBRARY_PATH ``` 3. **编译检查脚本** ```bash #!/bin/bash HEADER_PATH="/home/pthash/include/pthash/pthash.hpp" if [ ! -f "$HEADER_PATH" ]; then echo "错误: PTHash 头文件未找到!尝试重新安装..." ./install_pthash.sh # 假设的安装脚本 fi g++ -std=c++11 -O3 -lpthread -I/home/pthash/include pthash.cpp -o pthash ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值