what is Virtual channel

本文介绍了通过增加缓冲区数量实现单个连接的时间域复用,形成多个虚拟通道的方法,以此减少阻塞的可能性。并详细解释了异步传输模式(ATM)路由器的工作原理及其架构特点。
 

Virtual channel

A single connection can be time domain multiplexed by increasing the number of buffers. This provides some number of virtual channels for each connection and reduces the likelihood of blocking.

Figure 23: An example of 3 virtual channels per connection.
/includegraphics[width=2.5in]{communic-virtual.eps}
The virtual channel example depicted in Figure 23 is illustrating a relatively complicated architecture. The architecture of an Asynchronous Transfer Mode (ATM) router is built using similar techniques. However ATM routers use cells instead of flits or packets. Each cell is large enough to contain a virtual path and virtual connection identifier. These identifiers allow the cells to be transmitted over a single connection in any order (asynchronously). The router ``switches the labels" as the cells arrive, hence the name label switching routers.

Wavelength routing networks work on the same principle. In this case a single optical fiber contains a number of wavelengths (which are the ``virtual channels"). Incoming packets are switched to an appropriate out going wavelength.

 

 

 

http://tm.eefocus.com/myspace/blog/show_153291.html

xyg@xyg-T6AD:~$ cd ~/ros2_ws colcon build --packages-select pca9685_hardware source install/setup.bash Starting >>> pca9685_hardware --- stderr: pca9685_hardware /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:9:1: error: ‘CallbackReturn’ does not name a type 9 | CallbackReturn Pca9685SystemHardware::on_init(const hardware_interface::HardwareInfo& info) | ^~~~~~~~~~~~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp: In member function ‘virtual std::vector<hardware_interface::StateInterface> pca9685_hardware::Pca9685SystemHardware::export_state_interfaces()’: /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:44:37: error: ‘HW_IF_POSITION’ is not a member of ‘hardware_interface’ 44 | hardware_interface::HW_IF_POSITION, | ^~~~~~~~~~~~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp: In member function ‘virtual std::vector<hardware_interface::CommandInterface> pca9685_hardware::Pca9685SystemHardware::export_command_interfaces()’: /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:59:37: error: ‘HW_IF_POSITION’ is not a member of ‘hardware_interface’ 59 | hardware_interface::HW_IF_POSITION, | ^~~~~~~~~~~~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp: At global scope: /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:67:1: error: ‘CallbackReturn’ does not name a type 67 | CallbackReturn Pca9685SystemHardware::on_activate(const rclcpp_lifecycle::State& previous_state) | ^~~~~~~~~~~~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:126:1: error: ‘CallbackReturn’ does not name a type 126 | CallbackReturn Pca9685SystemHardware::on_deactivate(const rclcpp_lifecycle::State& previous_state) | ^~~~~~~~~~~~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp: In member function ‘virtual hardware_interface::return_type pca9685_hardware::Pca9685SystemHardware::read(const rclcpp::Time&, const rclcpp::Duration&)’: /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:152:81: warning: unused parameter ‘time’ [-Wunused-parameter] 152 | return_type Pca9685SystemHardware::read(const rclcpp::Time& time, const rclcpp::Duration& period) | ~~~~~~~~~~~~~~~~~~~~^~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:152:111: warning: unused parameter ‘period’ [-Wunused-parameter] 152 | ardware::read(const rclcpp::Time& time, const rclcpp::Duration& period) | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp: In member function ‘virtual hardware_interface::return_type pca9685_hardware::Pca9685SystemHardware::write(const rclcpp::Time&, const rclcpp::Duration&)’: /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:159:82: warning: unused parameter ‘time’ [-Wunused-parameter] 159 | eturn_type Pca9685SystemHardware::write(const rclcpp::Time& time, const rclcpp::Duration& period) | ~~~~~~~~~~~~~~~~~~~~^~~~ /home/xyg/ros2_ws/src/pca9685_hardware/src/pca9685_system_hardware.cpp:159:112: warning: unused parameter ‘period’ [-Wunused-parameter] 159 | rdware::write(const rclcpp::Time& time, const rclcpp::Duration& period) | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~ gmake[2]: *** [CMakeFiles/pca9685_hardware.dir/build.make:76:CMakeFiles/pca9685_hardware.dir/src/pca9685_system_hardware.cpp.o] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:137:CMakeFiles/pca9685_hardware.dir/all] 错误 2 gmake: *** [Makefile:146:all] 错误 2 --- Failed <<< pca9685_hardware [2.25s, exited with code 2] Summary: 0 packages finished [2.39s] 1 package failed: pca9685_hardware 1 package had stderr output: pca9685_hardware not found: "/home/xyg/ros2_ws/install/pca9685_hardware/share/pca9685_hardware/local_setup.bash" xyg@xyg-T6AD:~/ros2_ws$ ros2 control list_hardware_components | grep PCA9685 # 应输出: pca9685_hardware/Pca9685SystemHardware [INFO] [1750735736.192545351] [_ros2cli_16699]: waiting for service /controller_manager/list_hardware_components to become available... [WARN] [1750735746.210548769] [_ros2cli_16699]: Could not contact service /controller_manager/list_hardware_components [INFO] [1750735746.210767288] [_ros2cli_16699]: waiting for service /controller_manager/list_hardware_components to become available... ^C 以下分别是pca9685_params.yaml:pca9685_hardware: ros__parameters: hardware: plugin: "pca9685_hardware/Pca9685SystemHardware" i2c_bus: "i2c-1" # 移除/dev/前缀,代码中会自动添加 i2c_address: "0x33" # I2C地址保持不变 channel_mapping: "5,7,9,11,13,15" # 使用逗号分隔的字符串格式 joints: - joint1 # 关节名称与机器人结构对应 - joint2 - joint3 - joint4 - joint5 - joint6然后是pca9685_system_hardware.hpp:#ifndef PCA9685_HARDWARE__PCA9685_SYSTEM_HARDWARE_HPP_ #define PCA9685_HARDWARE__PCA9685_SYSTEM_HARDWARE_HPP_ #include <hardware_interface/types/hardware_interface_return_values.hpp> #include <hardware_interface/system_interface.hpp> #include <rclcpp_lifecycle/state.hpp> #include <rclcpp/logger.hpp> #include <memory> #include <vector> #include <string> #include <fcntl.h> #include <linux/i2c-dev.h> #include <unistd.h> namespace pca9685_hardware { class Pca9685SystemHardware : public hardware_interface::SystemInterface { public: using CallbackReturn = hardware_interface::CallbackReturn; using ReturnType = hardware_interface::return_type; CallbackReturn on_init(const hardware_interface::HardwareInfo& info) override; std::vector<hardware_interface::StateInterface> export_state_interfaces() override; std::vector<hardware_interface::CommandInterface> export_command_interfaces() override; CallbackReturn on_activate(const rclcpp_lifecycle::State& previous_state) override; CallbackReturn on_deactivate(const rclcpp_lifecycle::State& previous_state) override; ReturnType read(const rclcpp::Time& time, const rclcpp::Duration& period) override; ReturnType write(const rclcpp::Time& time, const rclcpp::Duration& period) override; private: int i2c_fd_; std::string i2c_bus_; int i2c_address_; std::vector<int> channel_mapping_; std::vector<double> hw_commands_; std::vector<double> hw_states_; bool write_byte_data(int reg, uint8_t value); bool write_word_data(int reg, uint16_t value); uint8_t read_byte_data(int reg); }; } // namespace pca9685_hardware #endif // PCA9685_HARDWARE__PCA9685_SYSTEM_HARDWARE_HPP_ 然后是:pca9685_hardware_plugin.xml:<library path="libpca9685_hardware"> <class name="pca9685_hardware/Pca9685SystemHardware" type="pca9685_hardware::Pca9685SystemHardware" base_class_type="hardware_interface::SystemInterface"> <description>PCA9685 PWM控制器硬件接口</description> </class> </library> 还有:pca9685_system_hardware.cpp:#include "pca9685_hardware/pca9685_system_hardware.hpp" #include <hardware_interface/types/hardware_interface_return_values.hpp> #include <rclcpp/rclcpp.hpp> #include <cmath> namespace pca9685_hardware { CallbackReturn Pca9685SystemHardware::on_init(const hardware_interface::HardwareInfo& info) { if (SystemInterface::on_init(info) != CallbackReturn::SUCCESS) { return CallbackReturn::ERROR; } try { i2c_bus_ = info.hardware_parameters.at("i2c_bus"); i2c_address_ = std::stoi(info.hardware_parameters.at("i2c_address"), nullptr, 16); std::string channel_str = info.hardware_parameters.at("channel_mapping"); std::istringstream iss(channel_str); std::string token; while (std::getline(iss, token, ',')) { channel_mapping_.push_back(std::stoi(token)); } hw_commands_.resize(info.joints.size(), 0.0); hw_states_.resize(info.joints.size(), 0.0); return CallbackReturn::SUCCESS; } catch (const std::exception& e) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "初始化失败: %s", e.what()); return CallbackReturn::ERROR; } } std::vector<hardware_interface::StateInterface> Pca9685SystemHardware::export_state_interfaces() { std::vector<hardware_interface::StateInterface> state_interfaces; for (size_t i = 0; i < hw_states_.size(); i++) { state_interfaces.emplace_back( hardware_interface::StateInterface( info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_states_[i] ) ); } return state_interfaces; } std::vector<hardware_interface::CommandInterface> Pca9685SystemHardware::export_command_interfaces() { std::vector<hardware_interface::CommandInterface> command_interfaces; for (size_t i = 0; i < hw_commands_.size(); i++) { command_interfaces.emplace_back( hardware_interface::CommandInterface( info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_commands_[i] ) ); } return command_interfaces; } CallbackReturn Pca9685SystemHardware::on_activate(const rclcpp_lifecycle::State& previous_state) { RCLCPP_INFO(rclcpp::get_logger("pca9685_hardware"), "激活硬件接口"); try { std::string device_path = "/dev/" + i2c_bus_; i2c_fd_ = open(device_path.c_str(), O_RDWR); if (i2c_fd_ < 0) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "无法打开I2C设备: %s", device_path.c_str()); return CallbackReturn::ERROR; } if (ioctl(i2c_fd_, I2C_SLAVE, i2c_address_) < 0) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "无法设置I2C地址: 0x%02X", i2c_address_); close(i2c_fd_); return CallbackReturn::ERROR; } // 初始化PCA9685 if (!write_byte_data(0x00, 0x01)) { // 复位 return CallbackReturn::ERROR; } usleep(50000); // 设置为普通模式 if (!write_byte_data(0x00, 0x00)) { return CallbackReturn::ERROR; } // 设置PWM频率为50Hz (20ms周期) uint8_t prescale = static_cast<uint8_t>(25000000.0 / (4096.0 * 50.0) - 1); uint8_t old_mode = read_byte_data(0x00); uint8_t new_mode = (old_mode & 0x7F) | 0x10; // 进入睡眠模式 if (!write_byte_data(0x00, new_mode)) { return CallbackReturn::ERROR; } if (!write_byte_data(0xFE, prescale)) { return CallbackReturn::ERROR; } if (!write_byte_data(0x00, old_mode)) { return CallbackReturn::ERROR; } usleep(50000); if (!write_byte_data(0x00, old_mode | 0x80)) { // 启用自动递增 return CallbackReturn::ERROR; } RCLCPP_INFO(rclcpp::get_logger("pca9685_hardware"), "硬件接口激活成功"); return CallbackReturn::SUCCESS; } catch (const std::exception& e) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "激活失败: %s", e.what()); if (i2c_fd_ >= 0) { close(i2c_fd_); } return CallbackReturn::ERROR; } } CallbackReturn Pca9685SystemHardware::on_deactivate(const rclcpp_lifecycle::State& previous_state) { RCLCPP_INFO(rclcpp::get_logger("pca9685_hardware"), "停用硬件接口"); try { // 关闭所有PWM通道 for (size_t i = 0; i < 16; i++) { if (!write_word_data(0x06 + 4 * i, 0)) { RCLCPP_WARN(rclcpp::get_logger("pca9685_hardware"), "关闭通道 %zu 失败", i); } } if (i2c_fd_ >= 0) { close(i2c_fd_); i2c_fd_ = -1; } RCLCPP_INFO(rclcpp::get_logger("pca9685_hardware"), "硬件接口停用成功"); return CallbackReturn::SUCCESS; } catch (const std::exception& e) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "停用失败: %s", e.what()); return CallbackReturn::ERROR; } } hardware_interface::return_type Pca9685SystemHardware::read(const rclcpp::Time& time, const rclcpp::Duration& period) { // 舵机通常没有位置反馈,所以我们将命令值作为状态返回 hw_states_ = hw_commands_; return ReturnType::OK; } hardware_interface::return_type Pca9685SystemHardware::write(const rclcpp::Time& time, const rclcpp::Duration& period) { try { for (size_t i = 0; i < hw_commands_.size(); i++) { if (i >= channel_mapping_.size()) { RCLCPP_WARN(rclcpp::get_logger("pca9685_hardware"), "通道映射越界: %zu", i); continue; } // 将弧度转换为角度 (0-180度) double angle_rad = hw_commands_[i]; double angle_deg = std::fmod(std::fmod(angle_rad, 2 * M_PI) + 2 * M_PI, 2 * M_PI); angle_deg = std::clamp(angle_deg * 180.0 / M_PI, 0.0, 180.0); // 计算PWM脉冲宽度 (500-2500us对应0-180度) uint16_t pulse_width = static_cast<uint16_t>(500 + (angle_deg / 180.0) * (2500 - 500)); uint16_t pwm_value = static_cast<uint16_t>(pulse_width * 4096.0 / 20000.0); // 设置PWM输出 int channel = channel_mapping_[i]; if (channel < 0 || channel > 15) { RCLCPP_WARN(rclcpp::get_logger("pca9685_hardware"), "无效通道: %d", channel); continue; } // 设置PWM值 (0为关闭时间,pwm_value为开启时间) if (!write_word_data(0x06 + 4 * channel, 0)) { RCLCPP_WARN(rclcpp::get_logger("pca9685_hardware"), "设置通道 %d 关闭时间失败", channel); } if (!write_word_data(0x08 + 4 * channel, pwm_value)) { RCLCPP_WARN(rclcpp::get_logger("pca9685_hardware"), "设置通道 %d 开启时间失败", channel); } } return ReturnType::OK; } catch (const std::exception& e) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "写入失败: %s", e.what()); return ReturnType::ERROR; } } bool Pca9685SystemHardware::write_byte_data(int reg, uint8_t value) { uint8_t buf[2] = {static_cast<uint8_t>(reg), value}; if (::write(i2c_fd_, buf, 2) != 2) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "I2C写入失败: reg=0x%02X, value=0x%02X", reg, value); return false; } return true; } bool Pca9685SystemHardware::write_word_data(int reg, uint16_t value) { uint8_t buf[3] = { static_cast<uint8_t>(reg), static_cast<uint8_t>(value & 0xFF), static_cast<uint8_t>((value >> 8) & 0xFF) }; if (::write(i2c_fd_, buf, 3) != 3) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "I2C写入失败: reg=0x%02X, value=0x%04X", reg, value); return false; } return true; } uint8_t Pca9685SystemHardware::read_byte_data(int reg) { uint8_t buf = static_cast<uint8_t>(reg); if (::write(i2c_fd_, &buf, 1) != 1) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "I2C写入寄存器失败: reg=0x%02X", reg); return 0; } if (::read(i2c_fd_, &buf, 1) != 1) { RCLCPP_ERROR(rclcpp::get_logger("pca9685_hardware"), "I2C读取失败: reg=0x%02X", reg); return 0; } return buf; } } // namespace pca9685_hardware #include "pluginlib/class_list_macros.hpp" PLUGINLIB_EXPORT_CLASS(pca9685_hardware::Pca9685SystemHardware, hardware_interface::SystemInterface) CMakeLists.txt:cmake_minimum_required(VERSION 3.8) project(pca9685_hardware) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif() find_package(ament_cmake REQUIRED) find_package(hardware_interface REQUIRED) find_package(rclcpp REQUIRED) find_package(rclcpp_lifecycle REQUIRED) find_package(pluginlib REQUIRED) add_library( ${PROJECT_NAME} SHARED src/pca9685_system_hardware.cpp ) target_include_directories( ${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> ) ament_target_dependencies( ${PROJECT_NAME} "hardware_interface" "rclcpp" "rclcpp_lifecycle" "pluginlib" ) # 导出插件描述文件(确保resource目录存在) pluginlib_export_plugin_description_file(hardware_interface resource/pca9685_hardware_plugin.xml) install( TARGETS ${PROJECT_NAME} DESTINATION lib ) install( DIRECTORY include/ DESTINATION include ) # 安装插件描述文件(明确指定resource目录) install( FILES resource/pca9685_hardware_plugin.xml DESTINATION share/${PROJECT_NAME} ) ament_package() package.xml:<?xml version="1.0"?> <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema-instance"?> <package format="3"> <name>pca9685_hardware</name> <version>0.0.1</version> <description>PCA9685 PWM Servo Driver Hardware Interface for ROS 2</description> <maintainer email="xyg@example.com">xyg</maintainer> <license>Apache License 2.0</license> <!-- 核心依赖 --> <depend>hardware_interface</depend> <depend>rclcpp</depend> <depend>pluginlib</depend> <depend>controller_manager</depend> <depend>rclcpp_lifecycle</depend> <!-- 测试依赖 --> <test_depend>ament_cmake</test_depend> <test_depend>ament_cmake_copyright</test_depend> <test_depend>ament_cmake_clang_format</test_depend> <test_depend>ament_cmake_cppcheck</test_depend> <!-- 移除所有Python相关依赖 --> <!-- 原test_depend已删除: ament_flake8, ament_pep257, python3-pytest --> <export> <!-- 改为ament_cmake编译类型 --> <build_type>ament_cmake</build_type> <!-- 硬件接口插件描述文件 --> <hardware_interface plugin="${prefix}/resource/plugin_description.xml" /> </export> </package> 以上是各个文件内容以及启动日志报错内容
06-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值