鱼香ROS社区
    • 版块
    • 最新
    • 未解决
    • 已解决
    • 群组
    • 注册
    • 登录
    紧急通知:禁止一切关于政治&VPN翻墙等话题,发现相关帖子会立马删除封号
    提问前必看的发帖注意事项: 社区问答规则(小鱼个人)更新 | 高质量帖子发布指南

    相机调用

    已定时 已固定 已锁定 已移动
    机器人学
    opencv 摄像头
    2
    14
    626
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • 小伊小
      机器人小伊
      最后由 编辑

      在ROS 2 Humble和OpenCV 4.5.5的环境下使用C语言编写一个调用摄像头并发布图像的程序,确实是一个复杂的任务,因为ROS 2本身主要使用C++和Python,对C语言的支持有限。不过,我们可以借助一些C++代码桥接到C语言。

      下面是一个基本的示例,它展示了如何在ROS 2 Humble中使用C++代码来调用摄像头并发布图像,同时提供一个简单的C接口来初始化ROS 2节点和发布图像。由于OpenCV在C语言中支持有限,我们主要使用C++来处理图像捕获和发布,并通过extern "C"提供一个简单的C接口。

      1. CMakeLists.txt

      首先,我们需要一个CMakeLists.txt文件来构建我们的项目。

      cmake_minimum_required(VERSION 3.5)
      project(camera_publisher)
      
      # 设置C++标准
      set(CMAKE_CXX_STANDARD 17)
      
      # 查找ROS 2组件
      find_package(REQUIRED COMPONENTS rclcpp sensor_msgs cv_bridge std_msgs)
      
      # 添加可执行文件
      add_executable(camera_publisher src/camera_publisher.cpp)
      ament_target_dependencies(camera_publisher rclcpp sensor_msgs cv_bridge std_msgs)
      
      # 包含OpenCV
      find_package(OpenCV REQUIRED)
      include_directories(${OpenCV_INCLUDE_DIRS})
      target_link_libraries(camera_publisher ${OpenCV_LIBS})
      
      install(TARGETS
        camera_publisher
        DESTINATION lib/${PROJECT_NAME})
      
      ament_package()
      

      2. camera_publisher.cpp

      这是主要的C++代码,它初始化ROS 2节点,调用摄像头,并发布图像。同时,我们提供一个简单的C接口。

      #include <rclcpp/rclcpp.hpp>
      #include <sensor_msgs/msg/image_raw.hpp>
      #include <cv_bridge/cv_bridge.h>
      #include <opencv2/opencv.hpp>
      #include <iostream>
      
      // 声明一个简单的C接口
      extern "C" {
          void init_ros_node(const char* node_name);
          void shutdown_ros_node();
          void publish_image(uint8_t* img_data, int img_width, int img_height, int img_step);
      }
      
      class CameraPublisherNode : public rclcpp::Node
      {
      public:
          CameraPublisherNode()
              : Node("camera_publisher_node"), image_pub_(this->create_publisher<sensor_msgs::msg::Image>("image_topic", 10))
          {
              cap_ = cv::VideoCapture(0);
              if (!cap_.isOpened()) {
                  RCLCPP_ERROR(this->get_logger(), "Failed to open camera");
                  rclcpp::shutdown();
              }
              
              RCLCPP_INFO(this->get_logger(), "Camera Publisher Node has started");
          }
      
          void publish_image_cpp(cv::Mat& frame)
          {
              sensor_msgs::msg::Image img_msg;
              cv_bridge::CvBridge bridge;
              img_msg = bridge.cv2rosMsg(frame, "bgr8");
              img_msg.header.stamp = this->now();
              image_pub_->publish(img_msg);
          }
      
      private:
          rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr image_pub_;
          cv::VideoCapture cap_;
      };
      
      CameraPublisherNode* g_node = nullptr;
      
      extern "C" {
          void init_ros_node(const char* node_name)
          {
              rclcpp::init(0, nullptr);
              g_node = new CameraPublisherNode(node_name);
              std::thread spin_thread([&]() {
                  rclcpp::spin(g_node);
              });
              // 分离线程,以便主线程可以继续执行
              spin_thread.detach();
          }
      
          void shutdown_ros_node()
          {
              if (g_node) {
                  delete g_node;
                  g_node = nullptr;
                  rclcpp::shutdown();
              }
          }
      
          void publish_image(uint8_t* img_data, int img_width, int img_height, int img_step)
          {
              if (!g_node) {
                  return;
              }
      
              cv::Mat frame(img_height, img_width, CV_8UC3, img_data, img_step);
              g_node->publish_image_cpp(frame);
          }
      }
      

      3. main.c

      这是一个简单的C程序,它调用上面定义的C接口来初始化ROS 2节点,从摄像头捕获图像,并发布图像。

      #include <stdio.h>
      #include <stdlib.h>
      #include <opencv2/opencv.hpp>
      
      extern void init_ros_node(const char* node_name);
      extern void shutdown_ros_node();
      extern void publish_image(uint8_t* img_data, int img_width, int img_height, int img_step);
      
      int main(int argc, char *argv[])
      {
          init_ros_node("camera_publisher_c_node");
      
          cv::VideoCapture cap(0);
          if (!cap.isOpened()) {
              fprintf(stderr, "Failed to open camera\n");
              shutdown_ros_node();
              return -1;
          }
      
          cv::Mat frame;
          while (true) {
              cap >> frame;
              if (frame.empty()) {
                  break;
              }
      
              publish_image(frame.data, frame.cols, frame.rows, frame.step);
      
              // 显示图像(可选)
              cv::imshow("Camera", frame);
              if (cv::waitKey(1) >= 0) {
                  break;
              }
          }
      
          shutdown_ros_node();
          return 0;
      }
      

      注意事项

      1. 编译:确保你已经安装了ROS 2 Humble和OpenCV 4.5.5,然后使用colcon来编译这个项目。
      2. 权限:确保你的用户有权访问摄像头。
      3. 环境:在运行程序之前,确保你已经激活了ROS 2环境。

      这个示例展示了如何通过C++代码桥接到C语言,在ROS 2中调用摄像头并发布图像。尽管这不是一个纯粹的C语言实现,但它提供了一个可行的解决方案。


      以上为生成回答,仅供参考~

      我是小伊,已接入ChatGpt,所有回复,仅供参考~

      1 条回复 最后回复 回复 引用 0
      • 2
        2251752108
        最后由 编辑

        @小伊 用C++编写

        1 条回复 最后回复 回复 引用 0
        • 小伊小
          机器人小伊
          最后由 编辑

          当然,我可以为你提供一个简单的C++程序示例。这是一个基本的“Hello, World!”程序,它是学习任何编程语言时的经典入门示例。

          #include <iostream>  // 包含输入输出流的头文件
          
          int main() {
              std::cout << "Hello, World!" << std::endl;  // 输出 "Hello, World!" 到控制台
              return 0;  // 返回0,表示程序正常结束
          }
          

          解释

          1. #include <iostream>: 这一行包含了输入输出流的头文件。iostream库提供了输入输出功能,比如std::cout用于向控制台输出。
          2. int main() { ... }: 这是程序的主函数,C++程序从这里开始执行。
          3. std::cout << "Hello, World!" << std::endl;: 这行代码使用std::cout对象向控制台输出字符串"Hello, World!",<<是插入操作符,std::endl是换行符,它还会刷新输出缓冲区。
          4. return 0;: 主函数返回0,表示程序正常结束。在操作系统中,返回0通常表示程序成功执行。

          编译和运行

          1. 将上述代码保存到一个文件中,例如hello.cpp。
          2. 打开命令行或终端,导航到保存hello.cpp文件的目录。
          3. 使用C++编译器(如g++)编译程序:
            g++ -o hello hello.cpp
            
            这会生成一个名为hello(在Windows上可能是hello.exe)的可执行文件。
          4. 运行生成的可执行文件:
            ./hello  # 在Unix/Linux/macOS上
            hello.exe  # 在Windows上
            

          你应该会在控制台中看到输出:

          Hello, World!
          

          如果你有其他特定的需求或想要一个更复杂的示例,请告诉我!


          以上为生成回答,仅供参考~

          我是小伊,已接入ChatGpt,所有回复,仅供参考~

          1 条回复 最后回复 回复 引用 0
          • 2
            2251752108
            最后由 编辑

            @2251752108 在 相机调用 中说:

            请基于ros的humble和opencv4.5.5版本写一份摄像头调用代码,并发布图像(C语言编写)

            @小伊 > 请基于ros的humble和opencv4.5.5版本写一份摄像头调用代码,并发布图像(C++编写)

            2 1 条回复 最后回复 回复 引用 0
            • 小伊小
              机器人小伊
              最后由 编辑

              要在ROS Humble中使用C++编写摄像头调用代码并发布图像,可以使用OpenCV 4.5.5。以下是一个完整的示例,它展示了如何使用OpenCV从摄像头捕获图像,并通过ROS发布这些图像。

              首先,确保你已经安装了ROS Humble和OpenCV 4.5.5。然后,创建一个新的ROS包,例如camera_publisher。

              1. 创建一个新的ROS包:
              mkdir -p ~/catkin_ws/src
              cd ~/catkin_ws/src
              ros2 pkg create --build-type ament_cmake camera_publisher
              
              1. 在camera_publisher包中,创建以下目录和文件:
              cd ~/catkin_ws/src/camera_publisher
              mkdir src
              cd src
              touch camera_publisher_node.cpp
              
              1. 编辑camera_publisher_node.cpp文件,添加以下代码:
              #include <chrono>
              #include <memory>
              #include <opencv2/opencv.hpp>
              #include <rclcpp/rclcpp.hpp>
              #include <sensor_msgs/msg/image.hpp>
              #include <cv_bridge/cv_bridge.h>
              
              class CameraPublisherNode : public rclcpp::Node
              {
              public:
                  CameraPublisherNode()
                      : Node("camera_publisher_node"), cap_(0) // 0表示默认摄像头
                  {
                      if (!cap_.isOpened())
                      {
                          RCLCPP_ERROR(this->get_logger(), "Error: Could not open camera");
                          rclcpp::shutdown();
                          return;
                      }
              
                      image_pub_ = this->create_publisher<sensor_msgs::msg::Image>(
                          "camera_image", rclcpp::QoS(10));
              
                      timer_ = this->create_wall_timer(
                          std::chrono::milliseconds(33),
                          std::bind(&CameraPublisherNode::timer_callback, this));
                  }
              
              private:
                  void timer_callback()
                  {
                      cv::Mat frame;
                      cap_ >> frame; // Capture frame-by-frame
              
                      if (frame.empty())
                      {
                          RCLCPP_ERROR(this->get_logger(), "Empty frame grabbed");
                          return;
                      }
              
                      sensor_msgs::msg::Image::SharedPtr msg = cv_bridge::CvBridge().cv2rosMsg(frame, "bgr8");
                      msg->header.stamp = this->now();
                      msg->header.frame_id = "camera_frame";
              
                      RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", msg->header.frame_id.c_str());
                      image_pub_->publish(msg);
                  }
                  rclcpp::TimerBase::SharedPtr timer_;
                  rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr image_pub_;
                  cv::VideoCapture cap_;
              };
              
              int main(int argc, char *argv[])
              {
                  rclcpp::init(argc, argv);
                  rclcpp::spin(std::make_shared<CameraPublisherNode>());
                  rclcpp::shutdown();
                  return 0;
              }
              
              1. 在CMakeLists.txt中添加以下内容,以便编译上述代码。编辑~/catkin_ws/src/camera_publisher/CMakeLists.txt文件:
              cmake_minimum_required(VERSION 3.5)
              project(camera_publisher)
              
              find_package(REQUIRED COMPONENTS
                rclcpp
                sensor_msgs
                std_msgs
                cv_bridge
                opencv4
              )
              
              add_executable(camera_publisher_node src/camera_publisher_node.cpp)
              ament_target_dependencies(camera_publisher_node rclcpp sensor_msgs std_msgs cv_bridge opencv4)
              
              install(TARGETS
                camera_publisher_node
                DESTINATION lib/${PROJECT_NAME})
              
              ament_package()
              
              1. 编译你的ROS包:
              cd ~/catkin_ws
              colcon build --packages-select camera_publisher
              
              1. 运行你的节点:
              source install/setup.bash
              ros2 run camera_publisher camera_publisher_node
              
              1. 在另一个终端中,你可以使用ros2 topic list和ros2 topic echo来查看发布的图像数据:
              ros2 topic list
              ros2 topic echo /camera_image sensor_msgs/msg/Image --raw
              

              注意:由于ros2 topic echo --raw可能不会直接显示图像,你可能需要编写另一个ROS节点或使用其他工具(如rqt_image_view)来可视化发布的图像。

              以上就是在ROS Humble中使用C++和OpenCV 4.5.5从摄像头捕获图像并发布的完整示例。


              以上为生成回答,仅供参考~

              我是小伊,已接入ChatGpt,所有回复,仅供参考~

              2 1 条回复 最后回复 回复 引用 0
              • 2
                2251752108 @小伊
                最后由 编辑

                @小伊 在 相机调用 中说:

                colcon build

                @小伊 zztg@zztg:~/桌面/zztg_robot$ colcon build
                Starting >>> zztg_robot
                --- stderr: zztg_robot
                /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp: In member function ‘void CameraPublisherNode::timer_callback()’:
                /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:41:61: error: ‘CvBridge’ is not a member of ‘cv_bridge’
                41 | sensor_msgs::msg::Image::SharedPtr msg = cv_bridge::CvBridge().cv2rosMsg(frame, "bgr8");
                | ^~~~~~~~
                /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:46:28: error: no matching function for call to ‘rclcpp::Publisher<sensor_msgs::msg::Image_<std::allocator<void> > >::publish(sensor_msgs::msg::Image_<std::allocator<void> >::SharedPtr&)’
                46 | image_pub_->publish(msg);
                | ~~~~~~~~~~~~~~~^

                1 条回复 最后回复 回复 引用 0
                • 小伊小
                  机器人小伊
                  最后由 编辑

                  从错误信息来看,你的 ROS 2 项目在编译时遇到了两个问题,主要涉及 cv_bridge 和 rclcpp::Publisher 的使用。这里是针对每个错误的详细分析和解决方案:

                  1. 关于 CvBridge 不是 cv_bridge 的成员的错误:

                    • 错误信息:error: ‘CvBridge’ is not a member of ‘cv_bridge’
                    • 原因:在 ROS 2 中,cv_bridge 库(用于在 OpenCV 图像和 ROS 消息之间转换)与 ROS 1 中的有所不同。ROS 2 中没有直接提供 cv_bridge 的等价物,但你可以使用 image_transport 和 cv_bridge 的 ROS 1 实现通过 rclpy 或 rclcpp 的桥接来间接实现。然而,更常见的是在 ROS 2 中直接使用 OpenCV 和 sensor_msgs/Image 消息类型进行转换。
                    • 解决方案:如果你需要在 ROS 2 中使用 OpenCV 图像,你可以自己编写转换函数,或者使用第三方库如 image_geometry 和 sensor_msgs 直接处理图像数据。这里是一个简单的转换示例,不依赖于 cv_bridge:
                      #include <opencv2/opencv.hpp>
                      #include <sensor_msgs/msg/image.hpp>
                      #include <memory>
                      
                      sensor_msgs::msg::Image::SharedPtr cvMatToRosMsg(const cv::Mat& frame, const std::string& encoding = "bgr8") {
                          sensor_msgs::msg::Image::SharedPtr msg = std::make_shared<sensor_msgs::msg::Image>();
                          msg->height = frame.rows;
                          msg->width = frame.cols;
                          msg->encoding = encoding;
                          msg->is_bigendian = 0;
                          msg->step = frame.step;
                          msg->data.resize(frame.total() * frame.elemSize());
                          std::memcpy(msg->data.data(), frame.data, frame.total() * frame.elemSize());
                          return msg;
                      }
                      
                  2. 关于 rclcpp::Publisher 的 publish 方法不匹配的错误:

                    • 错误信息:no matching function for call to ‘rclcpp::Publisher<sensor_msgs::msg::Image_<std::allocator<void>> >::publish(sensor_msgs::msg::Image_<std::allocator<void>>::SharedPtr&)’
                    • 原因:这个错误通常是因为 publish 方法期望的参数类型与提供的参数类型不匹配。在 ROS 2 中,rclcpp::Publisher 的 publish 方法确实接受一个 SharedPtr,但是可能由于类型定义错误或头文件包含不正确导致编译器无法识别。
                    • 解决方案:确保你已经正确包含了所有必要的头文件,并且 msg 的类型是正确的。如果你已经按照上面的方式定义了转换函数,确保 msg 是通过该函数正确创建的 sensor_msgs::msg::Image::SharedPtr 类型。此外,检查是否有其他类型定义冲突或编译环境问题。

                  最后,确保你的项目正确设置了 ROS 2 的依赖,并且在 CMakeLists.txt 和 package.xml 文件中正确声明了这些依赖。如果你是在 ROS 1 环境中尝试使用 ROS 2 代码,这将不会工作,因为两者在 API 和库依赖上有显著不同。


                  以上为生成回答,仅供参考~

                  我是小伊,已接入ChatGpt,所有回复,仅供参考~

                  1 条回复 最后回复 回复 引用 0
                  • 2
                    2251752108 @2251752108
                    最后由 编辑

                    @2251752108 在 相机调用 中说:

                    @小伊 >
                    请基于ros的humble和opencv4.5.5版本写一份摄像头调用代码,并发布图像(C++编写)
                    不要使用sensor_msgs和cv_bridge
                    @小伊

                    1 条回复 最后回复 回复 引用 0
                    • 小伊小
                      机器人小伊
                      最后由 编辑

                      在ROS 2 Humble中调用摄像头并使用OpenCV 4.5.5处理图像,然后发布图像数据而不使用sensor_msgs和cv_bridge,可以通过创建一个自定义的消息类型来实现。下面是一个完整的示例,展示如何做到这一点。

                      1. 创建ROS 2工作空间

                      首先,创建一个新的ROS 2工作空间并初始化:

                      mkdir -p ~/ros2_ws/src
                      cd ~/ros2_ws
                      colcon build
                      

                      2. 创建自定义消息包

                      在~/ros2_ws/src目录下创建一个新的ROS 2包:

                      cd ~/ros2_ws/src
                      ros2 pkg create --build-type ament_cmake my_image_publisher
                      

                      3. 定义自定义消息类型

                      在my_image_publisher/msg目录下创建一个新的消息文件ImageMessage.msg:

                      # File: my_image_publisher/msg/ImageMessage.msg
                      
                      # Header (optional, for timestamping)
                      std_msgs/msg/Header header
                      
                      # Image data
                      uint8[] data
                      uint32 width
                      uint32 height
                      uint8 channels
                      

                      确保在CMakeLists.txt和package.xml中添加对消息文件的依赖。

                      修改CMakeLists.txt

                      在CMakeLists.txt中添加以下内容以生成消息:

                      find_package(ament_cmake REQUIRED)
                      find_package(rosidl_default_generators REQUIRED)
                      find_package(builtin_interfaces REQUIRED)
                      find_package(std_msgs REQUIRED)
                      
                      add_message_files(
                        FILES
                        ImageMessage.msg
                      )
                      
                      generate_messages(
                        DEPENDENCIES
                        std_msgs
                      )
                      
                      install(TARGETS
                        ${PROJECT_NAME}_msgs
                        DESTINATION lib/${PROJECT_NAME})
                      
                      ament_package()
                      

                      修改package.xml

                      在package.xml中添加对message_generation的依赖:

                      <build_depend>message_generation</build_depend>
                      <exec_depend>message_runtime</exec_depend>
                      <member_of_group>rosidl_interface_packages</member_of_group>
                      <export>
                        <build_type>ament_cmake</build_type>
                      </export>
                      

                      4. 编写节点代码

                      在my_image_publisher/src目录下创建一个C++源文件,例如image_publisher_node.cpp:

                      #include <chrono>
                      #include <memory>
                      #include <opencv2/opencv.hpp>
                      #include <rclcpp/rclcpp.hpp>
                      #include <my_image_publisher/msg/image_message.hpp>
                      
                      using namespace std::chrono_literals;
                      
                      class ImagePublisherNode : public rclcpp::Node
                      {
                      public:
                          ImagePublisherNode()
                              : Node("image_publisher_node"), count_(0)
                          {
                              video_capture_.open(0);  // Open default camera
                              if (!video_capture_.isOpened()) {
                                  RCLCPP_ERROR(this->get_logger(), "Failed to open camera");
                                  rclcpp::shutdown();
                                  return;
                              }
                      
                              publisher_ = this->create_publisher<my_image_publisher::msg::ImageMessage>(
                                  "image_topic", 10);
                      
                              timer_ = this->create_wall_timer(
                                  500ms, std::bind(&ImagePublisherNode::timerCallback, this));
                          }
                      
                      private:
                          void timerCallback()
                          {
                              cv::Mat frame;
                              video_capture_ >> frame;
                              if (frame.empty()) {
                                  RCLCPP_WARN(this->get_logger(), "Empty frame grabbed");
                                  return;
                              }
                      
                              auto message = my_image_publisher::msg::ImageMessage();
                              message.header.stamp = this->now();
                              message.width = frame.cols;
                              message.height = frame.rows;
                              message.channels = frame.channels();
                      
                              // Convert cv::Mat to uint8_t array
                              message.data.resize(frame.total() * frame.elemSize());
                              std::memcpy(message.data.data(), frame.data, message.data.size());
                      
                              RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.data());
                              publisher_->publish(message);
                              count_++;
                          }
                          cv::VideoCapture video_capture_;
                          rclcpp::TimerBase::SharedPtr timer_;
                          rclcpp::Publisher<my_image_publisher::msg::ImageMessage>::SharedPtr publisher_;
                          size_t count_;
                      };
                      
                      int main(int argc, char *argv[])
                      {
                          rclcpp::init(argc, argv);
                          rclcpp::spin(std::make_shared<ImagePublisherNode>());
                          rclcpp::shutdown();
                          return 0;
                      }
                      

                      5. 编译和运行

                      回到工作空间根目录并编译:

                      cd ~/ros2_ws
                      colcon build --packages-select my_image_publisher
                      

                      编译完成后,运行节点:

                      source install/setup.bash
                      ros2 run my_image_publisher image_publisher_node
                      

                      6. 订阅图像数据

                      你可以编写另一个节点或使用ros2 topic echo命令来查看发布的图像数据。由于我们直接发布了原始图像数据,解析这些数据可能需要一些额外的处理。

                      ros2 topic echo /image_topic my_image_publisher/msg/ImageMessage
                      

                      注意:这个命令输出的将是原始数据,你需要自己解析这些数据以重新构建图像。

                      这个示例展示了如何在不使用sensor_msgs和cv_bridge的情况下,通过ROS 2发布图像数据。不过,通常建议使用标准消息类型(如sensor_msgs/Image)和现成的工具(如cv_bridge),以便更好地与其他ROS工具和库兼容。


                      以上为生成回答,仅供参考~

                      我是小伊,已接入ChatGpt,所有回复,仅供参考~

                      1 条回复 最后回复 回复 引用 0
                      • 2
                        2251752108
                        最后由 编辑

                        @小伊 /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp: In member function ‘void CameraPublisherNode::timer_callback()’:
                        /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:41:61: error: ‘CvBridge’ is not a member of ‘cv_bridge’
                        41 | sensor_msgs::msg::Image::SharedPtr msg = cv_bridge::CvBridge().cv2rosMsg(frame, "bgr8");
                        | ^~~~~~~~
                        /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:46:28: error: no matching function for call to ‘rclcpp::Publisher<sensor_msgs::msg::Image_<std::allocator<void> > >::publish(sensor_msgs::msg::Image_<std::allocator<void> >::SharedPtr&)’
                        46 | image_pub_->publish(msg);
                        | ~^
                        In file included from /opt/ros/humble/include/rclcpp/rclcpp/topic_statistics/subscription_topic_statistics.hpp:31,
                        from /opt/ros/humble/include/rclcpp/rclcpp/subscription.hpp:50,
                        from /opt/ros/humble/include/rclcpp/rclcpp/any_executable.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategy.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategies.hpp:18,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor_options.hpp:20,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor.hpp:37,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors/multi_threaded_executor.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors.hpp:21,
                        from /opt/ros/humble/include/rclcpp/rclcpp/rclcpp.hpp:155,
                        from /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:4:
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:251:3: note: candidate: ‘template<class T> std::enable_if_t<(rosidl_generator_traits::is_message<T>::value && std::is_same<T, typename rclcpp::TypeAdapter<MessageT>::ros_message_type>::value)> rclcpp::Publisher<MessageT, AllocatorT>::publish(std::unique_ptr<T, typename std::conditional<std::is_same<typename std::allocator_traits<typename std::allocator_traits<_Allocator>::rebind_traits<typename rclcpp::TypeAdapter<MessageT, void, void>::ros_message_type>::allocator_type>::rebind_alloc<typename rclcpp::TypeAdapter<MessageT, void, void>::ros_message_type>, std::allocator<typename rclcpp::TypeAdapter<MessageT>::ros_message_type> >::value, std::default_delete<typename rclcpp::TypeAdapter<MessageT>::ros_message_type>, rclcpp::allocator::AllocatorDeleter<typename std::allocator_traits<Allocator>::rebind_traits<typename rclcpp::TypeAdapter<MessageT, void, void>::ros_message_type>::allocator_type> >::type>) [with T = T; MessageT = sensor_msgs::msg::Image<std::allocator<void> >; AllocatorT = std::allocator<void>]’
                        251 | publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
                        | ^

                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:251:3: note: template argument deduction/substitution failed:
                        /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:46:28: note: ‘std::shared_ptr<sensor_msgs::msg::Image_<std::allocator<void> > >’ is not derived from ‘std::unique_ptr<T, std::default_delete<sensor_msgs::msg::Image_<std::allocator<void> > > >’
                        46 | image_pub_->publish(msg);
                        | ~^
                        In file included from /opt/ros/humble/include/rclcpp/rclcpp/topic_statistics/subscription_topic_statistics.hpp:31,
                        from /opt/ros/humble/include/rclcpp/rclcpp/subscription.hpp:50,
                        from /opt/ros/humble/include/rclcpp/rclcpp/any_executable.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategy.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategies.hpp:18,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor_options.hpp:20,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor.hpp:37,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors/multi_threaded_executor.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors.hpp:21,
                        from /opt/ros/humble/include/rclcpp/rclcpp/rclcpp.hpp:155,
                        from /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:4:
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:292:3: note: candidate: ‘template<class T> std::enable_if_t<(rosidl_generator_traits::is_message<T>::value && std::is_same<T, typename rclcpp::TypeAdapter<MessageT>::ros_message_type>::value)> rclcpp::Publisher<MessageT, AllocatorT>::publish(const T&) [with T = T; MessageT = sensor_msgs::msg::Image_<std::allocator<void> >; AllocatorT = std::allocator<void>]’
                        292 | publish(const T & msg)
                        | ^

                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:292:3: note: template argument deduction/substitution failed:
                        In file included from /usr/include/c++/11/ratio:39,
                        from /usr/include/c++/11/chrono:39,
                        from /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:1:
                        /usr/include/c++/11/type_traits: In substitution of ‘template<bool _Cond, class Tp> using enable_if_t = typename std::enable_if::type [with bool Cond = false; Tp = void]’:
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:292:3: required by substitution of ‘template<class T> std::enable_if_t<(rosidl_generator_traits::is_message<T>::value && std::is_same<T, sensor_msgs::msg::Image
                        <std::allocator<void> > >::value), void> rclcpp::Publisher<sensor_msgs::msg::Image
                        <std::allocator<void> > >::publish<T>(const T&) [with T = std::shared_ptr<sensor_msgs::msg::Image
                        <std::allocator<void> > >]’
                        /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:46:28: required from here
                        /usr/include/c++/11/type_traits:2579:11: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
                        2579 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
                        | ^

                        In file included from /opt/ros/humble/include/rclcpp/rclcpp/topic_statistics/subscription_topic_statistics.hpp:31,
                        from /opt/ros/humble/include/rclcpp/rclcpp/subscription.hpp:50,
                        from /opt/ros/humble/include/rclcpp/rclcpp/any_executable.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategy.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategies.hpp:18,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor_options.hpp:20,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor.hpp:37,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors/multi_threaded_executor.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors.hpp:21,
                        from /opt/ros/humble/include/rclcpp/rclcpp/rclcpp.hpp:155,
                        from /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:4:
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:322:3: note: candidate: ‘template<class T> std::enable_if_t<(typename rclcpp::TypeAdapter<MessageT>::is_specialized::value && std::is_same<T, typename rclcpp::TypeAdapter<MessageT>::custom_type>::value)> rclcpp::Publisher<MessageT, AllocatorT>::publish(std::unique_ptr<T, typename std::conditional<std::is_same<typename std::allocator_traits<typename std::allocator_traits<_Allocator>::rebind_traits<typename rclcpp::TypeAdapter<MessageT, void, void>::custom_type>::allocator_type>::rebind_alloc<typename rclcpp::TypeAdapter<MessageT, void, void>::custom_type>, std::allocator<typename rclcpp::TypeAdapter<MessageT>::custom_type> >::value, std::default_delete<typename rclcpp::TypeAdapter<MessageT>::custom_type>, rclcpp::allocator::AllocatorDeleter<typename std::allocator_traits<Allocator>::rebind_traits<typename rclcpp::TypeAdapter<MessageT, void, void>::custom_type>::allocator_type> >::type>) [with T = T; MessageT = sensor_msgs::msg::Image<std::allocator<void> >; AllocatorT = std::allocator<void>]’
                        322 | publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
                        | ^

                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:322:3: note: template argument deduction/substitution failed:
                        /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:46:28: note: ‘std::shared_ptr<sensor_msgs::msg::Image_<std::allocator<void> > >’ is not derived from ‘std::unique_ptr<T, std::default_delete<sensor_msgs::msg::Image_<std::allocator<void> > > >’
                        46 | image_pub_->publish(msg);
                        | ~~~^
                        In file included from /opt/ros/humble/include/rclcpp/rclcpp/topic_statistics/subscription_topic_statistics.hpp:31,
                        from /opt/ros/humble/include/rclcpp/rclcpp/subscription.hpp:50,
                        from /opt/ros/humble/include/rclcpp/rclcpp/any_executable.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategy.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/memory_strategies.hpp:18,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor_options.hpp:20,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executor.hpp:37,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors/multi_threaded_executor.hpp:25,
                        from /opt/ros/humble/include/rclcpp/rclcpp/executors.hpp:21,
                        from /opt/ros/humble/include/rclcpp/rclcpp/rclcpp.hpp:155,
                        from /home/zztg/桌面/zztg_robot/src/Robot_SeeWorld.cpp:4:
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:364:3: note: candidate: ‘template<class T> std::enable_if_t<(typename rclcpp::TypeAdapter<MessageT>::is_specialized::value && std::is_same<T, typename rclcpp::TypeAdapter<MessageT>::custom_type>::value)> rclcpp::Publisher<MessageT, AllocatorT>::publish(const T&) [with T = T; MessageT = sensor_msgs::msg::Image_<std::allocator<void> >; AllocatorT = std::allocator<void>]’
                        364 | publish(const T & msg)
                        | ^

                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:364:3: note: template argument deduction/substitution failed:
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:383:3: note: candidate: ‘void rclcpp::Publisher<MessageT, AllocatorT>::publish(const rcl_serialized_message_t&) [with MessageT = sensor_msgs::msg::Image_<std::allocator<void> >; AllocatorT = std::allocator<void>; rcl_serialized_message_t = rcutils_uint8_array_s]’
                        383 | publish(const rcl_serialized_message_t & serialized_msg)
                        | ^

                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:383:44: note: no known conversion for argument 1 from ‘sensor_msgs::msg::Image_<std::allocator<void> >::SharedPtr’ {aka ‘std::shared_ptr<sensor_msgs::msg::Image_<std::allocator<void> > >’} to ‘const rcl_serialized_message_t&’ {aka ‘const rcutils_uint8_array_s&’}
                        383 | publish(const rcl_serialized_message_t & serialized_msg)
                        | ~~~~~~~~~~~~~~~^~
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:389:3: note: candidate: ‘void rclcpp::Publisher<MessageT, AllocatorT>::publish(const rclcpp::SerializedMessage&) [with MessageT = sensor_msgs::msg::Image_<std::allocator<void> >; AllocatorT = std::allocator<void>]’
                        389 | publish(const SerializedMessage & serialized_msg)
                        | ^

                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:389:37: note: no known conversion for argument 1 from ‘sensor_msgs::msg::Image_<std::allocator<void> >::SharedPtr’ {aka ‘std::shared_ptr<sensor_msgs::msg::Image_<std::allocator<void> > >’} to ‘const rclcpp::SerializedMessage&’
                        389 | publish(const SerializedMessage & serialized_msg)
                        | ~~~~~~~~^~
                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:403:3: note: candidate: ‘void rclcpp::Publisher<MessageT, AllocatorT>::publish(rclcpp::LoanedMessage<typename rclcpp::TypeAdapter<MessageT>::ros_message_type, AllocatorT>&&) [with MessageT = sensor_msgs::msg::Image_<std::allocator<void> >; AllocatorT = std::allocator<void>; typename rclcpp::TypeAdapter<MessageT>::ros_message_type = sensor_msgs::msg::Image_<std::allocator<void> >]’
                        403 | publish(rclcpp::LoanedMessage<ROSMessageType, AllocatorT> && loaned_msg)
                        | ^

                        /opt/ros/humble/include/rclcpp/rclcpp/publisher.hpp:403:64: note: no known conversion for argument 1 from ‘sensor_msgs::msg::Image_<std::allocator<void> >::SharedPtr’ {aka ‘std::shared_ptr<sensor_msgs::msg::Image_<std::allocator<void> > >’} to ‘rclcpp::LoanedMessage<sensor_msgs::msg::Image_<std::allocator<void> >, std::allocator<void> >&&’
                        403 | publish(rclcpp::LoanedMessage<ROSMessageType, AllocatorT> && loaned_msg)
                        | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
                        gmake[2]: *** [CMakeFiles/ROBOT_SeeWorld.dir/build.make:76:CMakeFiles/ROBOT_SeeWorld.dir/src/Robot_SeeWorld.cpp.o] 错误 1
                        gmake[1]: *** [CMakeFiles/Makefile2:137:CMakeFiles/ROBOT_SeeWorld.dir/all] 错误 2
                        gmake: *** [Makefile:146:all] 错误 2

                        Failed <<< zztg_robot [2.95s, exited with code 2]

                        Summary: 0 packages finished [3.10s]
                        1 package failed: zztg_robot
                        1 package had stderr output: zztg_robot

                        1 条回复 最后回复 回复 引用 0
                        • 小伊小
                          机器人小伊
                          最后由 编辑

                          从错误信息来看,你在使用 ROS 2 和 OpenCV 时遇到了几个问题。这些问题主要涉及 cv_bridge 库的使用以及 ROS 2 消息发布的方式。下面我将逐一解释并提供可能的解决方案:

                          1. CvBridge 不是 cv_bridge 的成员

                          错误信息:

                          error: ‘CvBridge’ is not a member of ‘cv_bridge’
                          

                          这个问题通常是因为缺少了 cv_bridge 库的包含或者命名空间的使用不正确。cv_bridge 是 ROS 1 中用于在 OpenCV 图像和 ROS 消息之间转换的库,但在 ROS 2 中,这个功能被 image_transport 和 cv_bridge 的 ROS 2 版本(如果有的话)或者直接使用 OpenCV 和 ROS 2 消息类型的手动转换所取代。

                          解决方案:

                          • 对于 ROS 2,通常不使用 cv_bridge,而是直接操作 sensor_msgs::msg::Image 类型。你需要手动将 OpenCV 的 cv::Mat 转换为 ROS 2 的 sensor_msgs::msg::Image 类型。这可以通过创建一个新的 sensor_msgs::msg::Image 对象并填充其字段来完成。

                          2. 发布消息时类型不匹配

                          错误信息:

                          no matching function for call to ‘rclcpp::Publisher<sensor_msgs::msg::Image_<std::allocator<void> > >::publish(sensor_msgs::msg::Image_<std::allocator<void> >::SharedPtr&)’
                          

                          这个问题是因为你试图使用一个 std::shared_ptr 来发布消息,但 ROS 2 的 Publisher 通常期望一个 std::unique_ptr 或者直接的消息对象。

                          解决方案:

                          • 修改你的代码,使用 std::make_unique 来创建一个 std::unique_ptr,或者使用 rclcpp::Publisher 的 publish 方法直接接受的消息对象(如果你不需要管理消息的生命周期)。
                          • 例如,如果你已经有了 sensor_msgs::msg::Image 的一个实例 img,你可以这样发布:
                            auto img_ptr = std::make_unique<sensor_msgs::msg::Image>(img);
                            image_pub_->publish(std::move(img_ptr));
                            
                            或者如果 img 是局部变量且你不需要保留它,可以直接:
                            image_pub_->publish(rclcpp::create_message<sensor_msgs::msg::Image>(img));
                            

                          总结

                          你需要调整你的代码以适应 ROS 2 的 API,特别是关于消息发布和 OpenCV 图像转换的部分。ROS 2 和 ROS 1 在这些方面有所不同,因此直接从 ROS 1 代码迁移到 ROS 2 可能需要一些修改。如果你正在寻找 ROS 2 中处理图像的具体示例,ROS 2 的官方文档和教程是很好的资源。


                          以上为生成回答,仅供参考~

                          我是小伊,已接入ChatGpt,所有回复,仅供参考~

                          2 1 条回复 最后回复 回复 引用 0
                          • 2
                            2251752108 @小伊
                            最后由 编辑

                            @小伊 在 相机调用 中说:

                            对于 ROS 2,通常不使用 cv_bridge,而是直接操作 sensor_msgs::msg::Image 类型。你需要手动将 OpenCV 的 cv::Mat 转换为 ROS 2 的 sensor_msgs::msg::Image 类型。这可以通过创建一个新的 sensor_msgs::msg::Image 对象并填充其字段来完成

                            @小伊 这里如何编写

                            1 条回复 最后回复 回复 引用 0
                            • 小伊小
                              机器人小伊
                              最后由 编辑

                              在 ROS 2 中,将 OpenCV 的 cv::Mat 转换为 ROS 2 的 sensor_msgs::msg::Image 类型,确实需要手动填充 sensor_msgs::msg::Image 的各个字段。以下是一个具体的步骤和示例代码,展示如何完成这个转换:

                              1. 包含必要的头文件:
                                你需要包含 OpenCV 和 ROS 2 的相关头文件。

                              2. 创建并填充 sensor_msgs::msg::Image 对象:
                                你需要设置图像的编码格式(如 BGR8)、高度、宽度、步长以及实际的数据。

                              3. 使用 ROS 2 的发布机制:
                                你可以使用 ROS 2 的发布器来发布这个图像消息。

                              以下是一个完整的示例代码,展示了如何将 cv::Mat 转换为 sensor_msgs::msg::Image 并发布:

                              #include <opencv2/opencv.hpp>
                              #include <sensor_msgs/msg/image.hpp>
                              #include <rclcpp/rclcpp.hpp>
                              #include <std_msgs/msg/string.hpp>
                              #include <memory>
                              
                              class ImagePublisher : public rclcpp::Node
                              {
                              public:
                                  ImagePublisher()
                                      : Node("image_publisher_node"), image_pub_(this->create_publisher<sensor_msgs::msg::Image>("image_topic", 10))
                                  {
                                      // 读取图像(这里假设你已经有一个图像路径)
                                      cv::Mat frame = cv::imread("path_to_your_image.jpg");
                              
                                      if (frame.empty())
                                      {
                                          RCLCPP_ERROR(this->get_logger(), "Could not open or find the image");
                                          return;
                                      }
                              
                                      // 将 cv::Mat 转换为 sensor_msgs::msg::Image
                                      sensor_msgs::msg::Image img_msg;
                                      img_msg.height = frame.rows;
                                      img_msg.width = frame.cols;
                              
                                      // 图像编码,这里使用 BGR8
                                      img_msg.encoding = sensor_msgs::image_encodings::BGR8;
                              
                                      // 计算步长,这里假设图像是连续的
                                      img_msg.step = frame.cols * frame.elemSize();
                              
                                      // 将 cv::Mat 的数据复制到 sensor_msgs::msg::Image 的 data 字段中
                                      img_msg.data.resize(frame.total() * frame.elemSize());
                                      std::memcpy(img_msg.data.data(), frame.data, img_msg.data.size());
                              
                                      // 发布图像
                                      RCLCPP_INFO(this->get_logger(), "Publishing image...");
                                      image_pub_->publish(img_msg);
                              
                                      // 设置一个定时器来定期发布图像(可选)
                                      this->timer_ = this->create_wall_timer(
                                          std::chrono::seconds(1), std::bind(&ImagePublisher::timer_callback, this));
                                  }
                              
                              private:
                                  void timer_callback()
                                  {
                                      // 这里可以添加代码来周期性地执行某些操作,比如重新读取和发布图像
                                      RCLCPP_INFO(this->get_logger(), "Timer callback, publishing...");
                                  }
                                  rclcpp::TimerBase::SharedPtr timer_;
                                  rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr image_pub_;
                              };
                              
                              int main(int argc, char *argv[])
                              {
                                  rclcpp::init(argc, argv);
                                  rclcpp::spin(std::make_shared<ImagePublisher>());
                                  rclcpp::shutdown();
                                  return 0;
                              }
                              

                              解释:

                              1. 包含头文件:

                                • #include <opencv2/opencv.hpp>:包含 OpenCV 的头文件。
                                • #include <sensor_msgs/msg/image.hpp>:包含 ROS 2 的 sensor_msgs::msg::Image 消息定义。
                                • #include <rclcpp/rclcpp.hpp>:包含 ROS 2 的核心功能。
                              2. 节点和发布器的创建:

                                • ImagePublisher 类继承自 rclcpp::Node。
                                • 在构造函数中,创建一个发布器 image_pub_,用于发布图像消息。
                              3. 图像读取和转换:

                                • 使用 cv::imread 读取图像。
                                • 检查图像是否成功读取。
                                • 设置 sensor_msgs::msg::Image 的各个字段,包括高度、宽度、编码、步长和数据。
                                • 使用 std::memcpy 将 cv::Mat 的数据复制到 sensor_msgs::msg::Image 的 data 字段中。
                              4. 发布图像:

                                • 使用 image_pub_->publish(img_msg) 发布图像消息。
                                • 可选地,设置一个定时器来定期执行某些操作(如重新读取和发布图像)。
                              5. 主函数:

                                • 初始化 ROS 2。
                                • 创建一个 ImagePublisher 对象并启动 ROS 2 的自旋机制。
                                • 关闭 ROS 2。

                              确保你已经在你的 CMakeLists.txt 文件中正确配置了 OpenCV 和 ROS 2 的依赖项。


                              以上为生成回答,仅供参考~

                              我是小伊,已接入ChatGpt,所有回复,仅供参考~

                              1 条回复 最后回复 回复 引用 0
                              • 第一个帖子
                                最后一个帖子
                              皖ICP备16016415号-7
                              Powered by NodeBB | 鱼香ROS