二自由度机械臂软件系统(三)ros2_control硬件底层插件
- ros2_control实现了两个功能,一个是控制算法插件即控制的实现,另一个是底层插件即跟硬件通信的功能。
参考资料:https://zhuanlan.zhihu.com/p/682574842
1、创建功能包
ros2 pkg create --build-type ament_cmake robot_control_test
- 在src中创建功能包并编译
2、创建launch文件
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.conditions import IfCondition
from launch.substitutions import Command, FindExecutable, LaunchConfiguration, PathJoinSubstitutionfrom launch_ros.actions import Node
from launch_ros.substitutions import FindPackageSharedef generate_launch_description():# Declare arguments 1、声明参数declared_arguments = []declared_arguments.append(DeclareLaunchArgument("description_file",default_value="robottest.urdf.xacro", #这个名字是跟description中的xacro文件有关的description="URDF/XACRO description file with the robot.带有机器人的URDF/XACRO描述文件。",))declared_arguments.append(DeclareLaunchArgument("gui",default_value="true",description="Start Rviz2 and Joint State Publisher gui automatically \with this launch file.使用此启动文件自动启动Rviz2和Joint State Publisher gui。",))declared_arguments.append(DeclareLaunchArgument("prefix",default_value='""',description="Prefix of the joint names, useful for \multi-robot setup. If changed than also joint names in the controllers' configuration \have to be updated.\关节名称的前缀,用于多机器人设置。如果改变了,那么控制器配置中的联合名称也必须更新",))# Initialize Arguments 2、初始化参数description_file = LaunchConfiguration("description_file")gui = LaunchConfiguration("gui")prefix = LaunchConfiguration("prefix")# Get URDF via xacro 3、通过xacro给出urdfrobot_description_content = Command([PathJoinSubstitution([FindExecutable(name="xacro")])," ",PathJoinSubstitution([FindPackageShare("robot_test_control"), "urdf", description_file]),])robot_description = {"robot_description": robot_description_content}# rviz_config_file = PathJoinSubstitution(# [FindPackageShare("motor_test_control"), "rviz", "motorbot_view.rviz"]# )########################################################################################joint_state_publisher_node = Node(package="joint_state_publisher_gui",executable="joint_state_publisher_gui",condition=IfCondition(gui),)#发布关节数据信息robot_state_publisher_node = Node(package="robot_state_publisher",executable="robot_state_publisher",output="both",parameters=[robot_description],)#发布模型信息rviz_node = Node(package="rviz2",executable="rviz2",name="rviz2",output="log",# arguments=["-d", rviz_config_file],condition=IfCondition(gui),)#rviz节点nodes = [joint_state_publisher_node,robot_state_publisher_node,rviz_node,]return LaunchDescription(declared_arguments + nodes)
- 启动文件分成了两部分,参数的存储和节点生成。前面都是在准备所需的参数,后面设置节点,最终利用LaunchDescription生成了节点。
| 节点名 | 作用 |
|---|---|
| rviz_node | 运行rviz |
| joint_state_publisher_node | 用一个ui获得控制命令,并发布到状态节点 |
| robot_state_publisher_node | 主要用于发布机器人的urdf模型数据 |
3、机器人的xacro文件

(1)robottest.urdf.xacro
<?xml version="1.0"?>
<!-- Basic differential drive mobile base -->
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="robotdrive_robot"><!-- 导入基本的几何形状 --><xacro:include filename="$(find robot_control_test)/urdf/robottest_description.urdf.xacro" /><!-- 导入 ros2_control 描述部分 --><xacro:include filename="$(find robot_control_test)/urdf/robottest.ros2_control.xacro" /></robot>
- 分别导入模型和控制器
(2)robottest.ros2_control.xacro
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro"><ros2_control name="test_control123" type="system"><hardware><plugin>robot_control_test/RobotTestSystemHardware</plugin></hardware><joint name="link1_joint"><command_interface name="position"/><state_interface name="position"/><state_interface name="velocity"/></joint><joint name="link2_joint"><command_interface name="position"/><state_interface name="position"/><state_interface name="velocity"/></joint></ros2_control></robot>
- 这是导入控制器的代码,注意在这里引入了底层控制器的插件。这个插件就是之后要写代码编译生成的动态库
4、底层硬件控制器代码
#include "motor_test_system.hpp"#include <chrono>
#include <cmath>
#include <cstddef>
#include <limits>
#include <memory>
#include <vector>#include "hardware_interface/types/hardware_interface_type_values.hpp"
#include "rclcpp/rclcpp.hpp"
#include "utils_can.h"utils_can motor1(1);
utils_can motor2(2);namespace
{
constexpr auto DEFAULT_COMMAND_TOPIC = "motor_test_cmd";
constexpr auto DEFAULT_STATE_TOPIC = "motor_test_state";} // namespacenamespace motor_test_control
{
hardware_interface::CallbackReturn MotorTestSystemHardware::on_init(const hardware_interface::HardwareInfo & info)
{ std::cout << "初始化" << std::endl;//1、打开can盒int state = 0;state = VCI_OpenDevice(VCI_USBCAN2A,0,0);if(state==1)//打开设备{std::cout << "open deivce success!\n" <<std::endl;//打开设备成功}else if(state==-1){std::cout << "no can device!\n" <<std::endl;}else{printf(">>open deivce fail!\n");//这个就算成功打开,还是为0}//2、初始化两路can口//2.1 can1初始化VCI_INIT_CONFIG config_can;config_can.AccCode=0;config_can.AccMask=0xFFFFFFFF;config_can.Filter=1;//接收所有帧config_can.Mode=0;//正常模式config_can.Timing0=0x00;/*波特率1000 Kbps*/config_can.Timing1=0x14;std::cout <<"1000" <<std::endl;if(VCI_InitCAN(VCI_USBCAN2,0,0,&config_can)!=1){std::cout << ">>Init CAN fail" <<std::endl;VCI_CloseDevice(VCI_USBCAN2,0);}else{std::cout << ">>Init CAN success" <<std::endl;}if(VCI_StartCAN(VCI_USBCAN2,0,0)!=1){VCI_CloseDevice(VCI_USBCAN2,0);}else{std::cout << ">>start CAN success" <<std::endl;}motor1.CanInit();motor2.CanInit();if (hardware_interface::SystemInterface::on_init(info) !=hardware_interface::CallbackReturn::SUCCESS){return hardware_interface::CallbackReturn::ERROR;}if (info_.joints.size() != 2){RCLCPP_FATAL(rclcpp::get_logger("MotorTestSystemHardware"),"The number of crawlers is set not correactly,please check your urdf. 2 is expected,but now it is %zu.", info_.joints.size());return hardware_interface::CallbackReturn::ERROR;}else{RCLCPP_INFO(rclcpp::get_logger("MotorTestSystemHardware"), "Found 2 crawlers sucessfully!");}hw_positions_.resize(info_.joints.size(), std::numeric_limits<double>::quiet_NaN());hw_velocities_.resize(info_.joints.size(), std::numeric_limits<double>::quiet_NaN());hw_commands_.resize(info_.joints.size(), std::numeric_limits<double>::quiet_NaN());for (const hardware_interface::ComponentInfo & joint : info_.joints){// DiffBotSystem has exactly two states and one command interface on each jointif (joint.command_interfaces.size() != 1){RCLCPP_FATAL(rclcpp::get_logger("MotorTestSystemHardware"),"Joint '%s' has %zu command interfaces found. 1 expected.", joint.name.c_str(),joint.command_interfaces.size());return hardware_interface::CallbackReturn::ERROR;}if (joint.command_interfaces[0].name != hardware_interface::HW_IF_POSITION){RCLCPP_FATAL(rclcpp::get_logger("MotorTestSystemHardware"),"Joint '%s' have %s command interfaces found. '%s' expected.", joint.name.c_str(),joint.command_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION);return hardware_interface::CallbackReturn::ERROR;}if (joint.state_interfaces.size() != 2){RCLCPP_FATAL(rclcpp::get_logger("MotorTestSystemHardware"),"Joint '%s' has %zu state interface. 2 expected.", joint.name.c_str(),joint.state_interfaces.size());return hardware_interface::CallbackReturn::ERROR;}if (joint.state_interfaces[0].name != hardware_interface::HW_IF_POSITION){RCLCPP_FATAL(rclcpp::get_logger("MotorTestSystemHardware"),"Joint '%s' have '%s' as first state interface. '%s' expected.", joint.name.c_str(),joint.state_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION);return hardware_interface::CallbackReturn::ERROR;}if (joint.state_interfaces[1].name != hardware_interface::HW_IF_VELOCITY){RCLCPP_FATAL(rclcpp::get_logger("MotorTestSystemHardware"),"Joint '%s' have '%s' as second state interface. '%s' expected.", joint.name.c_str(),joint.state_interfaces[1].name.c_str(), hardware_interface::HW_IF_VELOCITY);return hardware_interface::CallbackReturn::ERROR;}}return hardware_interface::CallbackReturn::SUCCESS;
}std::vector<hardware_interface::StateInterface> MotorTestSystemHardware::export_state_interfaces()
{std::vector<hardware_interface::StateInterface> state_interfaces;for (auto i = 0u; i < info_.joints.size(); i++){state_interfaces.emplace_back(hardware_interface::StateInterface(info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_positions_[i]));state_interfaces.emplace_back(hardware_interface::StateInterface(info_.joints[i].name, hardware_interface::HW_IF_VELOCITY, &hw_velocities_[i]));}return state_interfaces;
}std::vector<hardware_interface::CommandInterface> MotorTestSystemHardware::export_command_interfaces()
{std::vector<hardware_interface::CommandInterface> command_interfaces;for (auto i = 0u; i < info_.joints.size(); i++){command_interfaces.emplace_back(hardware_interface::CommandInterface(info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_commands_[i]));}return command_interfaces;
}hardware_interface::CallbackReturn MotorTestSystemHardware::on_activate(const rclcpp_lifecycle::State & /*previous_state*/)
{std::cout << "激活" << std::endl;// BEGIN: This part here is for exemplary purposes - Please do not copy to your production codeRCLCPP_INFO(rclcpp::get_logger("MotorTestSystemHardware"), "Activating ...please wait...");// END: This part here is for exemplary purposes - Please do not copy to your production code// set some default valuesfor (auto i = 0u; i < hw_positions_.size(); i++){if (std::isnan(hw_positions_[i])){hw_positions_[i] = 0;hw_velocities_[i] = 0;hw_commands_[i] = 0;}}subscriber_is_active_ = true;this->node_ = std::make_shared<rclcpp::Node>("hardware_node");std_msgs::msg::Float64MultiArray empty_int16array;for(std::size_t i = 0; i < hw_positions_.size(); i++){empty_int16array.data.push_back(0.0);}received_fb_msg_ptr_.set(std::make_shared<std_msgs::msg::Float64MultiArray>(empty_int16array));fb_subscriber_ =this->node_->create_subscription<std_msgs::msg::Float64MultiArray>(DEFAULT_STATE_TOPIC, rclcpp::SystemDefaultsQoS(),[this](const std::shared_ptr<std_msgs::msg::Float64MultiArray> msg) -> void{if (!subscriber_is_active_){RCLCPP_WARN(this->node_->get_logger(), "Can't accept new commands. subscriber is inactive");return;}received_fb_msg_ptr_.set(std::move(msg));});//创建实时Publishercmd_publisher = this->node_->create_publisher<std_msgs::msg::Float64MultiArray>(DEFAULT_COMMAND_TOPIC, rclcpp::SystemDefaultsQoS());realtime_cmd_publisher_ = std::make_shared<realtime_tools::RealtimePublisher<std_msgs::msg::Float64MultiArray>>(cmd_publisher);RCLCPP_INFO(rclcpp::get_logger("MotorTestSystemHardware"), "Successfully activated!");return hardware_interface::CallbackReturn::SUCCESS;
}hardware_interface::CallbackReturn MotorTestSystemHardware::on_deactivate(const rclcpp_lifecycle::State & /*previous_state*/)
{std::cout << "反激活" << std::endl;// BEGIN: This part here is for exemplary purposes - Please do not copy to your production codeRCLCPP_INFO(rclcpp::get_logger("MotorTestSystemHardware"), "Deactivating ...please wait...");subscriber_is_active_ = false;fb_subscriber_.reset();received_fb_msg_ptr_.set(nullptr);// END: This part here is for exemplary purposes - Please do not copy to your production codeRCLCPP_INFO(rclcpp::get_logger("MotorTestSystemHardware"), "Successfully deactivated!");return hardware_interface::CallbackReturn::SUCCESS;
}hardware_interface::return_type motor_test_control::MotorTestSystemHardware::read(const rclcpp::Time & /*time*/, const rclcpp::Duration & period)
{std::cout << "读" << std::endl;std::shared_ptr<std_msgs::msg::Float64MultiArray> fb_msg;received_fb_msg_ptr_.get(fb_msg);rclcpp::spin_some(this->node_);for (std::size_t i = 0; i < hw_positions_.size(); i++){// Update the joint status: this is a revolute joint without any limit.double pos_ = 0;int id_ = 0;motor1.receive_callback(pos_,id_);if(id_==1){std::cout << "id==1" << std::endl;
hw_positions_[0] = pos_;}else if(id_==2){std::cout << "id==2" << std::endl;
hw_positions_[1] = pos_;}else{std::cout << "else:" << id_<<std::endl;}if(i < hw_velocities_.size()){hw_velocities_[i] = fb_msg->data[i];// hw_positions_[i] = fb_msg->data[i];//+= period.seconds() * hw_velocities_[i];std::cout << "读:" << hw_positions_[i]<<std::endl;}}return hardware_interface::return_type::OK;
}hardware_interface::return_type motor_test_control::MotorTestSystemHardware::write(const rclcpp::Time & /*time*/, const rclcpp::Duration & /*period*/)
{std::cout << "写" << std::endl;if(realtime_cmd_publisher_->trylock()){auto & cmd_msg = realtime_cmd_publisher_->msg_;cmd_msg.data.resize(hw_commands_.size());for (auto i = 0u; i < hw_commands_.size(); i++){cmd_msg.data[i] = hw_commands_[i];std::cout << "写:" <<cmd_msg.data[i] <<std::endl;}motor1.send_callback(cmd_msg.data[0]/3.14*180.0);motor2.send_callback(cmd_msg.data[1]/3.14*180.0);realtime_cmd_publisher_->unlockAndPublish();}return hardware_interface::return_type::OK;
}} // namespace diff_test_control#include "pluginlib/class_list_macros.hpp"
PLUGINLIB_EXPORT_CLASS(motor_test_control::MotorTestSystemHardware, hardware_interface::SystemInterface)
相关文章:
二自由度机械臂软件系统(三)ros2_control硬件底层插件
ros2_control实现了两个功能,一个是控制算法插件即控制的实现,另一个是底层插件即跟硬件通信的功能。 参考资料:https://zhuanlan.zhihu.com/p/682574842 1、创建功能包 ros2 pkg create --build-type ament_cmake robot_control_test在sr…...
24.8.9.11数据结构|链栈和队列
链栈 1、理解 实际上是一个仅在表头进行操作的单链表,头指针指向栈顶结点或头结点,以下恋栈均指带头结点的链栈. 2、 基本操作 1、定义结构:节点含有数据域和指针域 2、初始化操作:建立一个带头结点的空栈 3、取栈顶元素操作:取出栈的栈顶元…...
StarSpider:一款高效的网络爬虫框架解析与实战
文章目录 引言官网链接StarSpider 原理简介基础使用1. 添加依赖2. 编写PageProcessor3. 启动爬虫 高级使用1. 分布式抓取2. 自定义下载器3. 深度定制 优点结语 引言 在大数据时代,数据成为了推动业务增长和创新的关键。网络爬虫作为数据获取的重要手段之一…...
LVS详细解析及其NAT模式与DR模式部署(理论+实验全方位指导)
目录 1. 集群 2. 分布式系统 3. 集群与分布式的比较 4.通俗的解释 集群 分布式系统 总结 LVS(Linux Virtual Server)简介 LVS专业术语 工作原理 LVS调度算法 静态调度算法 动态调度算法 ipvsadm脑图 NAT模式集群 LVS的配置 在LVS主机内打开…...
负载均衡相关概念介绍(一)
负载均衡(Load Balance)是集群技术的一种重要应用,旨在将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,从而提高系统的并发处理能力、增加吞吐量、加强网络处理能力,并提供故障转移以…...
二叉树详解(1)
文章目录 目录1. 树的概念及结构1.1 树的相关概念1.2 树的表示1.3 树在实际中的运用(表示文件系统的目录树结构) 2. 二叉树的概念及结构2.1 概念2.2 特殊的二叉树2.3 二叉树的存储结构 3. 二叉树的顺序结构及实现3.1 二叉树的顺序结构3.2 堆的概念及结构…...
Spring定时任务注解
Service EnableScheduling public class xxxServiceImpl implement xxxService{Scheduled(cron "0 15 11 * * ?") // 每天的11:15执行public void reportCurrentTime() {aaa();}Scheduled(cron "0 15 17 * * ?") // 每天的17:15执行public void report…...
数据结构-绪论
学习目标: 认识数据结构的基本内容 学习内容: 了解:数据结构的研究内容掌握:数据结构的基本概念和术语了解:数据元素间的结构关系掌握:算法及算法的描述 数据结构的发展: 数据结构的发展简史 …...
Web开发:web服务器-Nginx的基础介绍(含AI文稿)
目录 一、Nginx的功能: 二、正向代理和反向代理的区别 三、Nginx负载均衡的主要功能 四、nginx安装目录下的各个文件(夹)的作用: 五、常用命令 一、Nginx的功能: 1.反向代理:例如我有三台服务器&#x…...
共享经济背景下校园、办公闲置物品交易平台-计算机毕设Java|springboot实战项目
🍊作者:计算机毕设残哥 🍊简介:毕业后就一直专业从事计算机软件程序开发,至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长:按照需求定制化开发项目、 源…...
Linux 服务器上简单配置 minio
Linux 服务器上简单配置 minio 初始化结构目录 mkdir -p /data/minio/bin mkdir -p /data/minio/conf mkdir -p /data/minio/data 下载 minio cd /data/minio/bin curl -O https://dl.min.io/server/minio/release/linux-amd64/minio 添加执行权限 chmod x minio 创建配置文件…...
TypeScript 面试题汇总
引言 TypeScript 是一种由微软开发的开源、跨平台的编程语言,它是 JavaScript 的超集,为 JavaScript 添加了静态类型系统和其他高级功能。随着 TypeScript 在前端开发领域的广泛应用,掌握 TypeScript 已经成为很多开发者必备的技能之一。本文…...
杰卡德系数
杰卡德系数(Jaccard Index 或 Jaccard Similarity Coefficient) 杰卡德系数是一种用于衡量两个集合相似度的重要指标。 从数学定义上来看,如前面所述,杰卡德系数计算公式为: J ( A , B ) ∣ A ∩ B ∣ ∣ A ∪ B ∣…...
微服务实现-sleuth+zipkin分布式链路追踪和nacos配置中心
1. sleuthzipkin分布式链路追踪 在大型系统的微服务化构建中,一个系统被拆分成了许多微服务。这些模块负责不同的功能,组合成系统,最终可以提供丰富的功能。 这种架构中,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软…...
数学中常用的解题方法
文章目录 待定系数法应用示例1. 多项式除法2. 分式化简3. 数列通项公式 总结 递归数列特征方程特征根的求解通项公式的求解示例 错位相减,差分错位相减法差分的应用结合理解 韦达定理二项式定理二项式定理的通项公式二项式系数的性质应用示例 一元二次求解1. 因式分…...
pytorch 1 张量
张量 文章目录 张量torch.Tensor 的 主要属性torch.Tensor 的 其他常用属性和方法叶子张量(Leaf Tensors)定义叶子张量的约定深入理解示例代码总结 中间计算结果与 detach() 方法定义中间计算结果不是叶子节点使用 detach() 方法使中间结果成为叶子张量示…...
音视频开发继续学习
RGA模块 RGA模块定义 RGA模块是RV1126用于2D图像的裁剪、缩放、旋转、镜像、图片叠加等格式转换的模块。比方说:要把一个原分辨率1920 * 1080的视频压缩成1280 * 720的视频,此时就要用到RGA模块了。 RGA模块结构体定义 RGA区域属性结构体 imgType&am…...
【Datawhale X 魔搭 】AI夏令营第四期大模型方向,Task1:智能编程助手(持续更新)
在一个数据驱动的世界里,人工智能的未来应由每一个愿意学习和探索的人共同塑造和掌握。希望这里是你实现AI梦想的起点。 大模型小白入门:https://linklearner.com/activity/14/11/25 大模型开发工程师能力测试:https://linklearner.com/activ…...
如何判断监控设备是否支持语音对讲
目录 一、大华摄像机 二、海康摄像机 三、宇视摄像机 一、大华摄像机 注意:大华摄像机支持跨网语音对讲,即设备和服务器可以不在同一网络内,大华设备的语音通道填写:34020000001370000001 配置接入示例: 音频输入…...
Grafana+Influxdb(Prometheus)+Apache Jmeter搭建可视化性能测试监控平台
此性能测试监控平台,架构可以是: GrafanaInfluxdbJmeterGrafanaPrometheusJmeter Influxdb和Prometheus在这里都是时序性数据库 在测试环境中,压测数据对存储和持久化的要求不高,所以这里的组件可以都通过docker-compose.yml文件…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...
【java面试】微服务篇
【java面试】微服务篇 一、总体框架二、Springcloud(一)Springcloud五大组件(二)服务注册和发现1、Eureka2、Nacos (三)负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...
云原生安全实战:API网关Envoy的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口,负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...
2025-05-08-deepseek本地化部署
title: 2025-05-08-deepseek 本地化部署 tags: 深度学习 程序开发 2025-05-08-deepseek 本地化部署 参考博客 本地部署 DeepSeek:小白也能轻松搞定! 如何给本地部署的 DeepSeek 投喂数据,让他更懂你 [实验目的]:理解系统架构与原…...
