【花雕学编程】Arduino FOC 之使用雅可比矩阵进行复杂路径规划

在这里插入图片描述

Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。

Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。

在这里插入图片描述
Arduino FOC(Field Oriented Control,场向量控制)是一种先进的电机控制技术,它允许精确控制电机的转矩和速度。这种控制技术特别适用于无刷直流电机(BLDC)和步进电机。在Arduino平台上实现FOC可以提供平滑的运行和高度的扭矩、速度和位置控制,它通过精确控制电机的电流和电压来实现高效率、高精度和低噪声的操作。

主要特点:
1、高性能电机控制:FOC是一种高级的电机控制算法,可以精准控制PMSM(永磁同步电机)和BLDC(无刷直流)电机,实现平滑的转速和扭矩输出。
2、闭环控制架构:FOC采用闭环反馈控制,通过检测电机的位置和速度数据,实时调整输出电压和电流,确保电机动作符合预期。
3、模块化设计:Arduino FOC库采用模块化设计,包含电机建模、速度/位置/电流控制环、PWM生成等子模块,用户可根据需求灵活组合使用。
4、可移植性强:Arduino FOC可移植到多种硬件平台,如Arduino、ESP32、STM32与树莓派等,适用于功率从几十瓦到几千瓦的电机系统。
5、参数自动识别:FOC库具有自动识别电机参数的功能,可以大幅简化电机控制系统的调试过程。

应用场景:
1、工业自动化:在工厂的机器人、传送带、CNC加工设备等领域,Arduino FOC可提供高性能的电机控制解决方案。
2、电动车辆:电动自行车、电动汽车、电动叉车等车载电机驱动系统,可以采用Arduino FOC进行精准控制。
3、家用电器:在电风扇、洗衣机、空调等家用电器中,Arduino FOC可实现细腻的电机速度和扭矩控制。
4、航模和无人机:航模飞机、无人机等对电机控制性能要求很高的领域,Arduino FOC能够提供高精度的电机驱动。
5、机器人:工业机器人、服务机器人、仿生机器人等对电机控制性能有严格要求的领域,Arduino FOC是一个不错的选择。

需要注意的事项:
1、硬件要求:Arduino FOC对控制器的性能(如CPU频率、RAM/ROM容量等)有一定要求,需要选择合适的硬件平台。
2、调试复杂性:FOC算法涉及电机建模、坐标变换、PI调节器等诸多环节,调试和调优过程相对复杂,需要一定的专业知识。
3、噪声抑制:电机驱动电路容易产生噪声干扰,需要采取合理的屏蔽和滤波措施,确保信号质量。
4、安全防护:电机驱动系统可能会产生过电流、过压等故障,需要配备可靠的保护电路,确保人身和设备安全。
5、系统集成:将Arduino FOC集成到完整的电机驱动系统中时,需要考虑机械、电力、控制等各个方面的协调配合。

总的来说,Arduino FOC是一种功能强大、性能优秀的电机控制解决方案,适用于工业自动化、电动车辆、家用电器等众多领域。但在硬件选型、算法调试、噪声抑制和安全防护等方面都需要谨慎考虑,以确保系统稳定可靠地运行。

附录:系列目录
1、Arduino FOC的特点、场景和使用事项
http://t.csdnimg.cn/WZhYL
2、Arduino FOC 之简单FOC库 - 跨平台的无刷直流和步进电机FOC实现
http://t.csdnimg.cn/p9ADE
3、Arduino FOC 之无刷直流电机速度控制
http://t.csdnimg.cn/gZ7CY
4、Arduino FOC 之步进电机位置控制
http://t.csdnimg.cn/VYbIb
5、Arduino FOC 之无刷直流电机电流控制
http://t.csdnimg.cn/wWGVu
6、Arduino FOC 之 SimpleFOC 库的主要函数
http://t.csdnimg.cn/S26MC
7、Arduino FOC 之 ArduinoFOC库的核心函数
http://t.csdnimg.cn/3VLzF
8、Arduino FOC 之传感器校准
http://t.csdnimg.cn/NS3TR
9、Arduino FOC 之SimpleFOCShield v2.0.4无刷电机驱动板
http://t.csdnimg.cn/g9mP7
10、Arduino FOC 之 AS5600角度读取
http://t.csdnimg.cn/dmI6F
11、Arduino FOC 之 FOC算法
http://t.csdnimg.cn/ENxc0
12、Arduino FOC 之 SimpleFOC库的适配电机方案
http://t.csdnimg.cn/QdH6k

在这里插入图片描述
Arduino FOC 之使用雅可比矩阵进行复杂路径规划

主要特点
高效的逆运动学求解:
雅可比矩阵在运动学中用于描述关节速度与末端执行器速度之间的关系。通过使用雅可比矩阵,可以高效地求解复杂路径中的逆运动学问题,快速计算出所需的关节角度和速度。
动态路径调整能力:
结合实时反馈,使用雅可比矩阵进行路径规划能够动态调整运动轨迹和速度。这使得机器人能够根据环境变化或任务要求,实时修正运动路径,确保运动的灵活性与安全性。
多关节协调控制:
雅可比矩阵能够处理多个关节之间的相互关系,通过合理的控制算法实现多关节的协调运动,确保在复杂的路径规划中各个关节能够顺畅配合。
适应性强:
该方法能够适应不同类型的机械臂和移动平台,用户可以根据具体的机械结构调整雅可比矩阵的计算方法,以满足特定应用的需求。
支持复杂运动模式:
使用雅可比矩阵可以实现复杂的运动模式,如轨迹跟踪、目标到达等,增强了机器人在执行任务时的能力。

应用场景
工业机器人:
在自动化生产线中,雅可比矩阵用于实现机械臂的精确路径规划,可以应用于焊接、装配和搬运等任务,提升生产效率和产品质量。
医疗机器人:
在手术机器人中,通过雅可比矩阵进行路径规划可以确保器械的精确移动,提高手术的安全性和成功率,尤其是在复杂的手术环境中。
服务机器人:
在家庭和商业环境中,雅可比矩阵能够帮助服务机器人进行复杂的导航和任务执行,如搬运物品和与人互动,提高用户体验。
机器人教育与研究:
作为教育和科研的技术平台,使用雅可比矩阵进行路径规划能够帮助学生和研究人员理解运动学和控制理论,促进机器人技术的发展。
无人驾驶技术:
在无人驾驶汽车中,雅可比矩阵可以用于实时路径规划和动态调整,确保车辆在复杂交通环境中的安全行驶。

需要注意的事项
雅可比矩阵的计算:
计算雅可比矩阵时,需要确保其准确性和有效性,错误的雅可比矩阵可能导致运动控制不精确,影响路径规划的质量。
实时性能要求:
由于路径规划通常需要实时响应,控制系统必须具备足够的计算能力,以确保在高频率更新时能够快速处理数据。
关节限制:
在路径规划过程中,需要考虑机械臂的关节运动限制,确保计算出的运动轨迹不会超出机械臂的可行范围,避免造成机械损坏。
传感器精度与延迟:
传感器的选择和安装对雅可比矩阵的实时应用至关重要,必须确保传感器能够提供高精度、低延迟的数据,以支持动态调整。
安全机制设计:
在复杂路径规划中,必须设计合理的安全机制,如运动范围限制、故障检测和急停功能,以确保在异常情况下能够及时响应,防止设备损坏或安全事故。
通过合理应用Arduino FOC的雅可比矩阵进行复杂路径规划,开发者能够实现高效、灵活的运动控制,提升机械系统在多种应用场景中的性能与用户体验。

在这里插入图片描述
1、基础雅可比矩阵计算

#include <Arduino.h>

struct Joint {
    float angle; // 关节角度
};

struct EndEffector {
    float x;
    float y;
};

// 机械臂关节
Joint joints[3] = {{0,}, {0,}, {0,}}; // 三个关节

void setup() {
    Serial.begin(9600);
}

void loop() {
    // 更新关节角度
    joints[0].angle = radians(30); // 关节1
    joints[1].angle = radians(45); // 关节2
    joints[2].angle = radians(60); // 关节3

    EndEffector ee = calculateEndEffectorPosition();
    Serial.printf("End Effector Position: (%.2f, %.2f)\n", ee.x, ee.y);
    
    float jacobian[2][3];
    calculateJacobian(jacobian);
    Serial.println("Jacobian Matrix:");
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            Serial.printf("%.2f ", jacobian[i][j]);
        }
        Serial.println();
    }

    delay(2000); // 每2秒更新一次
}

// 计算末端执行器位置
EndEffector calculateEndEffectorPosition() {
    // 假设机械臂的长度为 L1, L2, L3
    float L1 = 50, L2 = 40, L3 = 30;
    EndEffector ee;
    ee.x = L1 * cos(joints[0].angle) + L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    ee.y = L1 * sin(joints[0].angle) + L2 * sin(joints[0].angle + joints[1].angle) + L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    return ee;
}

// 计算雅可比矩阵
void calculateJacobian(float jacobian[2][3]) {
    float L1 = 50, L2 = 40, L3 = 30;
    jacobian[0][0] = -L1 * sin(joints[0].angle) - L2 * sin(joints[0].angle + joints[1].angle) - L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[0][1] = -L2 * sin(joints[0].angle + joints[1].angle) - L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[0][2] = -L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    
    jacobian[1][0] = L1 * cos(joints[0].angle) + L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[1][1] = L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[1][2] = L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
}

要点解读:
基础雅可比矩阵计算:通过计算关节角度和末端执行器位置,实现雅可比矩阵的基本计算。
关节模型:定义了三关节机械臂模型,便于理解不同关节角度对末端位置的影响。
实时输出监测:通过串口输出末端执行器位置和雅可比矩阵,便于观察和调试。
延迟控制:使用 delay() 函数定时更新,增强了程序的可视化效果。
基础与扩展性:保持代码结构简单,为将来添加更多关节或复杂路径规划提供了基础。

2、基于雅可比矩阵的路径跟踪

#include <Arduino.h>

struct Joint {
    float angle; // 关节角度
};

Joint joints[3] = {{0,}, {0,}, {0,}};
float targetX = 100; // 目标位置X
float targetY = 50;  // 目标位置Y

void setup() {
    Serial.begin(9600);
}

void loop() {
    updateJointsToTarget(targetX, targetY);
    
    EndEffector ee = calculateEndEffectorPosition();
    Serial.printf("End Effector Position: (%.2f, %.2f)\n", ee.x, ee.y);
    
    delay(1000); // 每秒更新一次
}

void updateJointsToTarget(float targetX, float targetY) {
    float currentX, currentY;
    EndEffector ee = calculateEndEffectorPosition();
    currentX = ee.x;
    currentY = ee.y;

    // 计算误差
    float errorX = targetX - currentX;
    float errorY = targetY - currentY;

    // 迭代调整关节角度
    float jacobian[2][3];
    calculateJacobian(jacobian);

    // 更新关节角度(这里假设直接使用雅可比矩阵的伪逆来更新)
    for (int i = 0; i < 3; i++) {
        joints[i].angle += 0.01 * (jacobian[i][0] * errorX + jacobian[i][1] * errorY); // 简化更新
    }
}

// 计算末端执行器位置
EndEffector calculateEndEffectorPosition() {
    float L1 = 50, L2 = 40, L3 = 30;
    EndEffector ee;
    ee.x = L1 * cos(joints[0].angle) + L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    ee.y = L1 * sin(joints[0].angle) + L2 * sin(joints[0].angle + joints[1].angle) + L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    return ee;
}

// 计算雅可比矩阵
void calculateJacobian(float jacobian[2][3]) {
    float L1 = 50, L2 = 40, L3 = 30;
    jacobian[0][0] = -L1 * sin(joints[0].angle) - L2 * sin(joints[0].angle + joints[1].angle) - L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[0][1] = -L2 * sin(joints[0].angle + joints[1].angle) - L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[0][2] = -L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    
    jacobian[1][0] = L1 * cos(joints[0].angle) + L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[1][1] = L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[1][2] = L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
}

要点解读:
路径跟踪算法:通过计算目标位置与当前末端位置的误差,迭代调整关节角度,适合实际应用中的路径跟踪。
实时反馈:输出当前末端位置,便于监测和调试路径跟踪效果。
雅可比矩阵应用:利用雅可比矩阵计算关节变化对末端位置的影响,增强了控制的精确性。
延迟控制:使用 delay() 函数定时更新,增强了程序的可视化效果。
基础与扩展性:代码结构清晰,为将来添加更多关节或复杂路径规划提供了基础。

3、复杂路径规划与雅可比矩阵

#include <Arduino.h>

struct Joint {
    float angle;
};

Joint joints[3] = {{0,}, {0,}, {0,}};
float path[5][2] = {{100, 50}, {80, 80}, {60, 30}, {40, 60}, {20, 10}}; // 目标路径

void setup() {
    Serial.begin(9600);
}

void loop() {
    for (int i = 0; i < 5; i++) {
        updateJointsToTarget(path[i][0], path[i][1]);
        EndEffector ee = calculateEndEffectorPosition();
        Serial.printf("Move to: (%.2f, %.2f) | Current Position: (%.2f, %.2f)\n", path[i][0], path[i][1], ee.x, ee.y);
        delay(2000); // 每个目标点延迟2秒
    }
    while (true); // 停止后续循环
}

void updateJointsToTarget(float targetX, float targetY) {
    float currentX, currentY;
    EndEffector ee = calculateEndEffectorPosition();
    currentX = ee.x;
    currentY = ee.y;

    float errorX = targetX - currentX;
    float errorY = targetY - currentY;

    float jacobian[2][3];
    calculateJacobian(jacobian);

    // 更新关节角度(简化版)
    for (int i = 0; i < 3; i++) {
        joints[i].angle += 0.01 * (jacobian[0][i] * errorX + jacobian[1][i] * errorY); // 简化更新
    }
}

// 计算末端执行器位置
EndEffector calculateEndEffectorPosition() {
    float L1 = 50, L2 = 40, L3 = 30;
    EndEffector ee;
    ee.x = L1 * cos(joints[0].angle) + L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    ee.y = L1 * sin(joints[0].angle) + L2 * sin(joints[0].angle + joints[1].angle) + L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    return ee;
}

// 计算雅可比矩阵
void calculateJacobian(float jacobian[2][3]) {
    float L1 = 50, L2 = 40, L3 = 30;
    jacobian[0][0] = -L1 * sin(joints[0].angle) - L2 * sin(joints[0].angle + joints[1].angle) - L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[0][1] = -L2 * sin(joints[0].angle + joints[1].angle) - L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[0][2] = -L3 * sin(joints[0].angle + joints[1].angle + joints[2].angle);
    
    jacobian[1][0] = L1 * cos(joints[0].angle) + L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[1][1] = L2 * cos(joints[0].angle + joints[1].angle) + L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
    jacobian[1][2] = L3 * cos(joints[0].angle + joints[1].angle + joints[2].angle);
}

要点解读:
复杂路径规划:通过一系列目标点,机械臂逐步移动到每个目标位置,适合实际应用场景。
实时反馈与调试:输出当前末端执行器位置与目标位置,便于监测和调试路径跟踪效果。
雅可比矩阵在路径跟踪中的应用:利用雅可比矩阵计算关节变化对末端位置的影响,提高了控制精度。
延迟控制与间隔:使用 delay() 函数控制每个目标点的停留时间,增强程序的可视化效果。
基础与扩展性:保持代码基础,便于后续添加更多路径点或复杂运动模式。

在这里插入图片描述
4、基本雅可比矩阵路径规划

#include <math.h>

// 假设机械臂有两个关节,末端执行器需要到达的目标点
float targetX = 100;
float targetY = 100;

// 机械臂的关节角度,初始值
float joint1 = 0;
float joint2 = 0;

// 雅可比矩阵,这里只是一个2x2矩阵的示例
float J[2][2] = {{1, 0}, {0.5, 2}};

void setup() {
  // 初始化代码...
}

void loop() {
  // 计算关节速度
  float jointSpeed1 = J[0][0] * targetX + J[0][1] * targetY;
  float jointSpeed2 = J[1][0] * targetX + J[1][1] * targetY;

  // 更新关节角度
  joint1 += jointSpeed1;
  joint2 += jointSpeed2;

  // 检查是否到达目标点
  if (abs(joint1) < 0.01 && abs(joint2) < 0.01) {
    // 到达目标点的处理...
  }

  delay(10);
}

5、雅可比矩阵与PID控制结合

#include <math.h>

float targetX = 100;
float targetY = 100;

float joint1 = 0;
float joint2 = 0;

float J[2][2] = {{1, 0}, {0.5, 2}};

float Kp = 0.1; // PID比例系数

void setup() {
  // 初始化代码...
}

void loop() {
  // 计算关节速度
  float errorX = targetX - joint1;
  float errorY = targetY - joint2;
  float jointSpeed1 = Kp * (J[0][0] * errorX + J[0][1] * errorY);
  float jointSpeed2 = Kp * (J[1][0] * errorX + J[1][1] * errorY);

  // 更新关节角度
  joint1 += jointSpeed1;
  joint2 += jointSpeed2;

  delay(10);
}

6、多轴机械臂路径规划

#include <math.h>

// 目标点坐标
float targetPoints[3][3] = {{0, 0, 0}, {100, 100, 0}, {200, 200, 0}};

// 机械臂的关节角度,初始值
float joints[3] = {0, 0, 0};

// 雅可比矩阵,这里只是一个3x3矩阵的示例
float J[3][3] = {{1, 0, 0}, {0.5, 1, 0}, {0, 0.5, 1}};

void setup() {
  // 初始化代码...
}

void loop() {
  // 计算关节速度
  float jointSpeeds[3] = {0, 0, 0};
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      jointSpeeds[i] += J[i][j] * (targetPoints[2][j] - joints[j]);
    }
  }

  // 更新关节角度
  for (int i = 0; i < 3; i++) {
    joints[i] += jointSpeeds[i];
  }

  // 检查是否到达目标点
  if (abs(joints[0]) < 0.01 && abs(joints[1]) < 0.01 && abs(joints[2]) < 0.01) {
    // 到达目标点的处理...
  }

  delay(10);
}

要点解读
雅可比矩阵定义:
雅可比矩阵是一个描述机械臂关节速度与末端执行器速度关系的矩阵,它用于将路径规划问题从操作空间转换到关节空间。
路径规划:
根据目标点和雅可比矩阵计算关节速度,从而规划机械臂的路径。
PID控制:
结合PID控制可以提高路径跟踪的精度和稳定性,通过调整比例、积分、微分项来优化控制效果。
多轴控制:
对于多轴机械臂,需要构建更高维度的雅可比矩阵,并计算每个关节的速度,以实现精确的多维运动控制。
实时控制与反馈:
实时更新关节角度,并根据实际位置与目标位置之间的误差调整控制策略,实现精确的位置控制。

注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。

在这里插入图片描述

### 关于在Arduino使用LVGL库的示例教程 #### 示例代码解析 为了帮助理解如何在Arduino平台上利用LVGL库构建图形用户界面,下面提供了一个简单的`HelloWorld`实例。此例子展示了基本的初始化过程以及创建一个按钮的方法。 ```cpp #include "lvgl/lvgl.h" #include "lv_arduino.h" void setup() { Serial.begin(9600); // 初始化TFT屏幕和触摸屏 tft.init(); ts.begin(); // 初始化LVGL库 lv_init(); lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); /*Basic display driver initialization*/ disp_drv.flush_cb = my_disp_flush; // 设置刷新回调函数 lv_disp_drv_register(&disp_drv); // 创建一个按钮并设置其属性 lv_obj_t * btn1 = lv_btn_create(lv_scr_act()); lv_obj_set_pos(btn1, 10, 10); /*Set its position*/ lv_obj_set_size(btn1, 120, 50); /*Set its size*/ // 给按钮添加标签 lv_obj_t * label = lv_label_create(btn1); lv_label_set_text(label, "Button"); } void loop() { lv_task_handler(); /*Let the GUI do its work*/ delay(5); /*Sleep a bit not to waste resources*/ } ``` 这段代码首先包含了必要的头文件,并定义了`setup()`函数来完成硬件初始化工作[^2]。接着,在屏幕上创建了一个按钮对象,并通过调用`lv_btn_create()`方法将其放置到当前活动窗口中;之后调整位置大小并通过`lv_label_create()`给该按钮附加文字说明。最后,在主循环里不断更新GUI状态以响应事件处理程序。 #### 主要组件解释 - **lvgl/** 文件夹下存放着核心图形引擎及相关模块; - **examples/** 中有多个子目录分别对应不同类型的案例研究,比如最基础的`HelloWorld`入门级应用; - **libraries/** 收录了第三方依赖项和其他支持包; - **tools/** 提供了一些实用工具,例如图像转换器等辅助开发的小应用程序[^5]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值