[ROS 系列学习教程] 建模与仿真 - 使用 ros_control 控制差速轮式机器人

在这里插入图片描述

ROS 系列学习教程(总目录)

本文目录

  • 一、差速轮式机器人
  • 二、差速驱动机器人运动学模型
  • 三、对外接口
    • 3.1 输入接口
    • 3.2 输出接口
  • 四、控制器参数
  • 五、配置控制器参数
  • 六、编写硬件抽象接口
  • 七、控制机器人移动
  • 八、源码

ros_control 提供了多种控制器,其中 diff_drive_controller 用于控制差速驱动轮式机器人。

一、差速轮式机器人

差速轮式机器人是一种移动机器人,其运动基于机器人身体两侧的两个独立驱动轮。因此,它可以通过改变轮子的相对旋转速度来改变方向,不需要额外的转向运动。具有这种驱动器的机器人通常有一个或多个脚轮,以防止车辆倾斜。

如果两个轮子以相同的方向和速度驱动,机器人将沿直线行驶。如果两个轮子以相同的速度朝相反的方向转动,如所示图所示,机器人将绕轴的中心点旋转。否则,根据旋转速度和方向,旋转中心可能落在由两个轮胎接触点定义的线上的任何位置。当机器人沿直线行驶时,旋转中心距离机器人无限远。由于机器人的方向取决于两个驱动轮的旋转速度和方向,因此应精确感测和控制这些量。

image-20240623192426694

差速转向机器人与汽车中使用的差速 齿轮类似,两个车轮可以有不同的转速,但与差速齿轮系统不同,差速转向系统将为两个车轮提供动力。差速轮式机器人在机器人技术中得到广泛应用,因为它们的运动易于编程并且可以很好地控制。当今市场上几乎所有的消费机器人都使用差速转向,主要是因为它成本低且简单。

二、差速驱动机器人运动学模型

如下图为轮式机器人的差速驱动运动学模型示意图:

image-20240623192426694

其中,
V − 机器人线速度 ω − 机器人角速度 X O Y − 世界坐标系 X B Y B − 机器人坐标系 φ − 机器人在世界坐标系的角度 r − 车轮半径 b − 轮距 I C R − 瞬时旋转中心 R − 瞬心到机器人中心的距离 v L , v R − 左右轮接地点切向线速度 ω L , ω R − 左右轮角速度 V - 机器人线速度\\ \omega - 机器人角速度\\ XOY - 世界坐标系\\ X_BY_B - 机器人坐标系\\ \varphi - 机器人在世界坐标系的角度\\ r - 车轮半径\\ b - 轮距\\ ICR - 瞬时旋转中心\\ R - 瞬心到机器人中心的距离\\ v_L,v_R - 左右轮接地点切向线速度\\ \omega_L,\omega_R - 左右轮角速度 V机器人线速度ω机器人角速度XOY世界坐标系XBYB机器人坐标系φ机器人在世界坐标系的角度r车轮半径b轮距ICR瞬时旋转中心R瞬心到机器人中心的距离vL,vR左右轮接地点切向线速度ωL,ωR左右轮角速度

有如下关系:
ω ⋅ ( R + b / 2 ) = v R ω ⋅ ( R − b / 2 ) = v L \omega \cdot (R + b/2) = v_R\\ \omega \cdot (R - b/2) = v_L ω(R+b/2)=vRω(Rb/2)=vL
解这两个方程可得 ω \omega ω R R R
ω = ( v R − v L ) / b R = b / 2 ⋅ ( v R + v L ) / ( v R − v L ) \omega = (v_R-v_L)/b\\ R = b/2 \cdot(v_R+v_L)/(v_R-v_L) ω=(vRvL)/bR=b/2(vR+vL)/(vRvL)
利用角速度方程可得机器人瞬时速度 V V V
V = ω ⋅ R = ( v R + v L ) / 2 V = \omega \cdot R = (v_R+v_L)/2 V=ωR=(vR+vL)/2
车轮切向速度也可以写成:
v R = r ⋅ ω R v L = r ⋅ ω L v_R = r \cdot \omega_R\\ v_L = r \cdot \omega_L vR=rωRvL=rωL
则机器人在本体坐标系中的运动学模型为:
[ x ˙ B y ˙ B φ ˙ ] = [ v ⋅ x B v ⋅ y B ω ] = ⏞ v = r ω [ r 2 r 2 0 0 − r b r b ] [ ω L ω R ] \begin{bmatrix} \dot{x}_B \\ \dot{y}_B \\ \dot{\varphi} \end{bmatrix} = \begin{bmatrix} v \cdot x_B \\ v \cdot y_B \\ \omega \end{bmatrix} \overbrace{=}^{v=r\omega} \begin{bmatrix} \frac r2 & \frac r2 \\ 0 & 0 \\ -\frac rb & \frac rb \end{bmatrix} \begin{bmatrix} \omega_L \\ \omega_R \end{bmatrix} x˙By˙Bφ˙ = vxBvyBω = v=rω 2r0br2r0br [ωLωR]
再通过坐标变换,最终可以得到机器人在世界坐标中的运动学模型:
[ x ˙ y ˙ φ ˙ ] = [ cos ⁡ φ 0 sin ⁡ φ 0 0 1 ] [ V ω ] \begin{bmatrix} \dot{x} \\ \dot{y} \\ \dot{\varphi} \end{bmatrix} = \begin{bmatrix} \cos\varphi & 0 \\ \sin\varphi & 0 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} V \\ \omega \end{bmatrix} x˙y˙φ˙ = cosφsinφ0001 [Vω]
其中, V V V ω \omega ω 为控制变量。

通常我们需要通过机器人的速度和结构参数逆解出左右轮的转速,用于控制电机。在这种情况下,可以很容易地重新表述前面提到的方程。使用如下方程:
R = V / ω ω R = v R / r ω L = v L / r R = V/\omega\\ \omega_R = v_R/r\\ \omega_L = v_L/r R=V/ωωR=vR/rωL=vL/r
可得左右轮角速度方程:
ω R = V + ω ⋅ b / 2 r ω L = V − ω ⋅ b / 2 r \omega_R = \frac{V+\omega \cdot b/2}{r} \\ \omega_L = \frac{V-\omega \cdot b/2}{r} ωR=rV+ωb/2ωL=rVωb/2

三、对外接口

diff_drive_controller 主要通过订阅速度命令作为模块的输入,然后解析运动学模型控制电机,达到控制机器人的目的。

3.1 输入接口

  • cmd_vel(geometry_msgs/Twist)

    位于控制器的命名空间下,给机器人发布速度

3.2 输出接口

  • odom(nav_msgs/Odometry)

    位于控制器的命名空间下,根据硬件反馈计算的里程计信息

  • /tf(tf/tfMessage)

    从 odom 转换为 base_link

  • cmd_vel_out(geometry_msgs/TwistStamped)

    publish_cmd 参数设置为 True 时可用。在控制器的输入上应用限制器后的 Twist。

四、控制器参数

diff_drive_controller 提供了一些参数,用于配置机器人控制。

参数数据类型说明
left_wheelstring /string[…]左轮关节名称或关节名称列表
right_wheelstring /string[…]右轮关节名称或关节名称列表
pose_covariance_diagonaldouble[6]用于里程计位姿发布的协方差矩阵的对角线
twist_covariance_diagonaldouble[6]用于里程计 twist 发布的协方差矩阵的对角线
publish_ratedouble发布里程计的频率,用于 tf 和 odom(单位:Hz,默认值: 50.0)
wheel_separationdouble轮距,左轮和右轮之间的距离。如果未指定此参数,diff_drive_controller 将尝试从 URDF 读取值
wheel_separation_multiplierdouble轮距参数的系数。用于解释机器人模型和真实机器人之间的差异。(默认值:1.0)
wheel_radiusdouble车轮半径。默认两侧车轮都具有相同的尺寸。如果未指定此参数,diff_drive_controller 将尝试从 URDF 读取值。
wheel_radius_multiplierdouble车轮半径参数的系数。用于解释机器人模型和真实机器人之间的差异。(默认值:1.0)
cmd_vel_timeoutdouble两个连续速度命令之间允许的时间间隔。此延迟后,将向车轮发送零速命令。(单位:s,默认值:0.5)
base_frame_idstring用于填充Odometry消息和TF的child_frame_id(默认值:“base_link”)
linearobject线性速度配置参数
+ xobjectx轴,两轮差速机器人线速度只有x轴
++ has_velocity_limitsbool控制器是否限制线速度。(默认值: false)
++ max_velocitydouble最大线速度(单位:m/s)
++ min_velocitydouble最小线速度(单位:m/s)。未指定时,使用max_velocity
++ has_acceleration_limitsbool控制器是否限制线加速度。(默认值: false)
++ max_accelerationdouble最大线加速度(单位:m/s^2)
++ min_accelerationdouble最小线加速度(单位:m/s^2)。未指定时,使用max_acceleration
++ has_jerk_limitsbool控制器是否限制线加速度的变化快慢(默认值: false)
++ max_jerkdouble最大 jerk(单位:m/s^3)
angularobject角速度配置参数
+ zobjectz轴,两轮差速机器人角速度只有z轴
++ has_velocity_limitsbool控制器是否应该限制角速度(默认值: false)
++ max_velocitydouble最大角速度(单位:rad/s)
++ min_velocitydouble最小角速度(单位:rad/s)。将其设置为 0.0 将禁用逆时针旋转。未指定时,将使用max_velocity
++ has_acceleration_limitsbool控制器是否应该限制角加速度(默认值: false)
++ max_accelerationdouble最大角加速度(单位:rad/s^2)
++ min_accelerationdouble最小角加速度(单位为 rad/s^2)。未指定时,使用max_acceleration。
++ has_jerk_limitsbool控制器是否限制角加速度的变化快慢(默认值: false)
++ max_jerkdouble最大 jerk(单位:rad/s^3)
enable_odom_tfbool是否直接发布到 TF(默认值: true )
odom_frame_idstring里程计的frame_id(默认值:“/odom”)
publish_cmdbool发布要执行的速度命令。用于监控限制器对控制器输入的影响。(默认值: False)
allow_multiple_cmd_vel_publishersbool将其设置为 true 将允许输入接口 ~/cmd_vel 有多个发布者。如果将其设置为 false,则如果 ~/cmd_vel 有多个发布者,则会导致控制器停止运行。(默认值: False)
velocity_rolling_window_sizeint用于计算里程计 twist.linear.x 和 twist.angular.z 速度的平均速度样本数量(默认值: 10)

五、配置控制器参数

最小配置示例(即必要配置项):

diff_drive_controller:type: "diff_drive_controller/DiffDriveController"left_wheel: "left_wheel_joint"right_wheel: "right_wheel_joint"pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.03]twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.03]

该差速轮式机器人完整配置:

# 用于控制器硬件接口配置
hardware_interface:joints:- left_wheel_joint- right_wheel_joint- front_caster_joint- back_caster_joint# joint_state_controller 控制器,用于发布各关节状态
joint_state_controller:type: "joint_state_controller/JointStateController"publish_rate: 50# diff_drive_controller 控制器
diff_drive_controller:type: "diff_drive_controller/DiffDriveController"left_wheel: "left_wheel_joint"right_wheel: "right_wheel_joint"publish_rate: 50pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.03]twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.03]cmd_vel_timeout: 100velocity_rolling_window_size: 1publish_cmd: truebase_frame_id: base_linkenable_odom_tf: trueodom_frame_id: odom# 轮间距和轮半径wheel_separation: 0.38wheel_radius: 0.06wheel_separation_multiplier: 1.0wheel_radius_multiplier: 1.0# 速度和加速度限制linear:x:has_velocity_limits: truemax_velocity: 1.0 # m/shas_acceleration_limits: truemax_acceleration: 3.0 # m/s^2angular:z:has_velocity_limits: truemax_velocity: 2.0 # rad/shas_acceleration_limits: truemax_acceleration: 6.0 # rad/s^2

六、编写硬件抽象接口

下面写一个两轮差速硬件接口,使用速度控制接口 VelocityJointInterface 控制 joint 的速度,使用 JointStateInterface 获取 joint 的位置、速度、力等信息。

硬件抽象接口头文件:diff_drive_hardware_interface.h

#ifndef DIFF_DRIVE_HARDWARE_INTERFACE_H
#define DIFF_DRIVE_HARDWARE_INTERFACE_H#include <ros/ros.h>
#include <hardware_interface/joint_command_interface.h>
#include <hardware_interface/joint_state_interface.h>
#include <hardware_interface/robot_hw.h>
#include <controller_manager/controller_manager.h>class DiffDriveHWInterface : public hardware_interface::RobotHW
{
public:struct JointInfo{std::string name;double cmd;double pos;double vel;double eff;JointInfo() : name(""), cmd(0.0), pos(0.0), vel(0.0), eff(0.0){}JointInfo(std::string name_) : name(name_), cmd(0.0), pos(0.0), vel(0.0), eff(0.0){}JointInfo(std::string name_, double cmd_, double pos_, double vel_, double dff_) : name(name_), cmd(cmd_), pos(pos_), vel(vel_), eff(dff_){}};public:DiffDriveHWInterface(ros::NodeHandle &nh);void init();void read(const ros::Duration &period);void write(const ros::Duration &period);private:ros::NodeHandle m_nh;hardware_interface::JointStateInterface m_jnt_state_interface;hardware_interface::VelocityJointInterface m_jnt_vel_interface;std::vector<JointInfo> m_joints;
};#endif // DIFF_DRIVE_HARDWARE_INTERFACE_H

源文件:diff_drive_hardware_interface.cpp

#include "diff_drive_control/diff_drive_hardware_interface.h"DiffDriveHWInterface::DiffDriveHWInterface(ros::NodeHandle &nh) : m_nh(nh)
{
}/*** @brief 初始化关节信息*        注册抽象硬件接口* */
void DiffDriveHWInterface::init()
{std::vector<std::string> joint_names;m_nh.getParam("/hardware_interface/joints", joint_names);for (std::string name : joint_names){m_joints.push_back(JointInfo(name));}for (auto &joint : m_joints){ROS_INFO("get joint: %s", joint.name.c_str());// Initialize hardware interfacehardware_interface::JointStateHandle state_handle(joint.name, &joint.pos, &joint.vel, &joint.eff);m_jnt_state_interface.registerHandle(state_handle);hardware_interface::JointHandle vel_handle(m_jnt_state_interface.getHandle(joint.name), &joint.cmd);m_jnt_vel_interface.registerHandle(vel_handle);}registerInterface(&m_jnt_state_interface);registerInterface(&m_jnt_vel_interface);
}void DiffDriveHWInterface::read(const ros::Duration &period)
{// Read the state of the hardware (e.g., from sensors)
}void DiffDriveHWInterface::write(const ros::Duration &period)
{// Send the command to the hardware (e.g., to actuators)for (auto &joint : m_joints){joint.pos += joint.vel * period.toSec();// if (joint.vel != joint.cmd)// {//     ROS_INFO("write, joint: %s, cmd: %lf", joint.name.c_str(), joint.cmd);// }joint.vel = joint.cmd;}
}

控制节点:diff_drive_control_node.cpp

#include <ros/ros.h>
#include <controller_manager/controller_manager.h>
#include "diff_drive_control/diff_drive_hardware_interface.h"int main(int argc, char **argv)
{ros::init(argc, argv, "diff_drive_control_node");ros::NodeHandle nh;DiffDriveHWInterface diff_drive(nh);diff_drive.init();controller_manager::ControllerManager cm(&diff_drive, nh);ros::Rate rate(50.0);ros::AsyncSpinner spinner(1);spinner.start();while (ros::ok()){ros::Duration period = rate.expectedCycleTime();diff_drive.write(period);cm.update(ros::Time::now(), period);rate.sleep();}return 0;
}

七、控制机器人移动

机器人模型与硬件接口都准备好了,接下来开始编写业务代码控制机器人。

我们仅给机器人发送速度指令,模拟机器人移动任务,如下:

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>geometry_msgs::Twist moveRobot(const double& linear, const double& angular)
{geometry_msgs::Twist msg;msg.linear.x = linear; // 线速度msg.linear.y = 0.0;msg.linear.z = 0.0;msg.angular.x = 0.0;msg.angular.y = 0.0;msg.angular.z = angular; // 角速度ROS_INFO("moveRobot, linear: %.3lf, angular: %.1lf", linear, angular*180/M_PI);return msg;
}int main(int argc, char** argv)
{ros::init(argc, argv, "diff_drive_business");ros::NodeHandle nh;ros::Publisher velPub = nh.advertise<geometry_msgs::Twist>("/diff_drive_controller/cmd_vel", 10);ros::Rate rate(10);while (ros::ok()){velPub.publish(moveRobot(0.5, 0));ros::Duration(3.0).sleep();velPub.publish(moveRobot(0, 1.57));ros::Duration(1.0).sleep();rate.sleep();}return 0;
}

编译执行该节点,在rviz中的可视化结果如下:

在这里插入图片描述

八、源码

项目源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/39556.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

方法的用法

一.简介 目前为止我给出的所有的案例都是将代码放在main方法中&#xff0c;就会产生一些问题&#xff1a; 代码冗长&#xff0c;不利于维护变量过多&#xff0c;想不出那么多的变量名没有重用性 那么该如何解决呢&#xff1f; 我们可以编写功能性的代码块&#xff0c;来被ma…

FormMaking表单设计器V3.8发布,数据表格上线,支持多选、多级表头、列模板自定义、操作列、分页等设置

介绍 FormMaking 是基于Vue的可视化表单设计器&#xff0c;赋能企业实现可视化低代码开发模式&#xff1b;帮助开发者从传统枯燥的表单代码中解放出来&#xff0c;更多关注业务&#xff0c;快速提高效率&#xff0c;节省研发成本。 目前已经在OA系统、考试系统、报表系统、流程…

MyBatis-plus这么好用,不允许还有人不会

你好呀&#xff0c;我是 javapub. 做 Java 的同学都会用到的三件套&#xff0c;Spring、SpringMV、MyBatis。但是由于使用起来配置较多&#xff0c;依赖冲突频发。所有&#xff0c;各路大佬又在这上边做了包装&#xff0c;像我们常用的 SpringBoot、MyBatisPlus。 基于当前要…

C语言的数据结构:图的操作

&#x1f6fa;图的遍历&#xff1a; 注意&#xff1a;在遍历的过程中&#xff0c;可能会出现 回路 ( 已经访问过的节点还要重新访问一次 ) \color{orange}回路(已经访问过的节点还要重新访问一次) 回路(已经访问过的节点还要重新访问一次). 当从A开始访问时&#xff0c;先访问…

heic格式转化jpg,手把手教你将heic转换成jpg【办公必备】

一、什么是heic heic格式是一种高效的图片格式&#xff0c;它可以在较小的文件大小下提供高质量的图片。 二、如何打开heic 然而&#xff0c;这种图片因其格式的特殊性&#xff0c;在实际应用中仍存在一些问题&#xff1a;压缩效果可能不够理想&#xff0c;一些老旧的软件和设…

stm32学习笔记---USART串口外设(理论部分)

目录 USART简介 USART的框图 串口的引脚 USART的基本结构 数据帧 起始位侦测 数据采样 波特率发生器 USD转串口模块的原理图 声明&#xff1a;本专栏是本人跟着B站江科大的视频的学习过程中记录下来的笔记&#xff0c;我之所以记录下来是为了方便自己日后复习。如果你…

TypeScript 中 const enum 和 enum 的核心区别在哪?日常开发应该使用哪个?

编译结果 enum 会生成一个对象&#xff0c;引用的地方保持对其引用 const enum 会擦除 enum 定义的代码&#xff0c;引用的地方会生成 inline code 使用enum&#xff1a; 使用const enum&#xff1a; PS&#xff1a;编译选项 preserveConstEnums 可以使 const enum 不去擦除 …

WPDRRC信息安全体系架构模型

构建信息安全保障体系框架应包括技术体系、组织机构体系和管理体系等三部分&#xff0c;也就是说&#xff1a;人、管理和技术手段是信息安全架构设计的三大要素&#xff0c;而构成动态的信息与网络安全保障体系框架是实现系统的安全保障。 1.WPDRRC信息安全模型的定义 WPDRRC…

Vue3快速上手--3小时掌握

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core截止2023年10月&#xff0c;最新的…

llama-factory训练RLHF-PPO模型

理论上RLHF&#xff08;强化学习&#xff09;效果比sft好&#xff0c;也更难训练。ppo有采用阶段,步骤比较多,训练速度很慢. 记录下工作中使用llama-factory调试rlhf-ppo算法流程及参数配置,希望对大家有所帮助. llama-factory版本: 0.8.2 一 rlhf流程 ppo训练流程图如下, 会…

【Kubernetes】加入节点Node及问题

命令 分别再node节点机器上&#xff0c;执行如下命令&#xff1a; kubeadm join [master机器ip:端口] --token [master机器初始化生成的token] --discovery-token-ca-cent-hash [master机器初始化生成的hash]问题 由于清屏没有记住token和hash的时候&#xff1a; 1&#xff…

Log4j日志框架讲解(全面,详细)

Log4j概述 Log4j是Apache下的一款开源的日志框架&#xff0c;通过在项目中使用 Log4J&#xff0c;我们可以控制日志信息输出到控制台、文件、甚至是数据库中。我们可以控制每一条日志的输出格式&#xff0c;通过定义日志的输出级别&#xff0c;可以 更灵活的控制日志的输出过程…

如何指定Microsoft Print To PDF的输出路径

在上一篇文章中&#xff0c;介绍了三种将文件转换为PDF的方式。默认情况下&#xff0c;在Microsoft Print To PDF的首选项里&#xff0c;是看不到输出路径的设置的。 需要一点小小的手段。 运行输入 control 打开控制面板&#xff0c;选择硬件和声音下的查看设备和打印机 找到…

【ubuntu18.04】 局域网唤醒 wakeonlan

ai服务器经常因为断电,无法重启,当然可以设置bios 来电启动。 这里使用局域网唤醒配置。 自动开关机设置 工具:ethtool 端口 : enp4s0 Wake-on: d 表示禁用Wake-on: g 激活 ,例如:ethtool -s eth0 wol g 配置/etc/rc.local ,这个文件不存在,自己创建工具下载 tengxun W…

【前端vue3】TypeScrip-类型推论和类型别名

类型推论 TypeScript里&#xff0c;在有些没有明确指出类型的地方&#xff0c;类型推论会帮助提供类型。 例如&#xff1a; 变量xiaoc被推断类型为string 如重新给xiaoc赋值数字会报错 let xiaoc "xiaoc"xiaoc 1111111111111如没有给变量指定类型和赋值&#xf…

专题七:Spring源码之BeanDefinition

上一篇我们通过refresh方法中的第二个核心方法obtainBeanFactory&#xff0c;通过createBeanFacotry创建容Spring的初级容器&#xff0c;并定义了容器的两个核心参数是否允许循环引用和覆盖。现在容器有了&#xff0c;我们来看看容器里的第一个重要成员BeanDefinition。 进入lo…

从需求是如何最终抽象成最基本的传参入参

第一层&#xff1a;出参和入参 用通俗的话讲&#xff0c;就是给客户提供服务的一种方式&#xff0c;需要包含入参和出参 。入口参数就是程序执行时会调用的参数&#xff0c;出口参数就是程序执行完会返回的参数。入参的值是被调函数需要&#xff0c; 出参的值是主调函数需要的…

【Linux系统】CUDA的安装与graspnet环境配置遇到的问题

今天在安装环境时遇到报错&#xff1a; The detected CUDA version (10.1) mismatches the version that was used to compile PyTorch (11.8). Please make sure to use the same CUDA versions. 报错原因&#xff1a;安装的cuda版本不对应&#xff0c;我需要安装cuda的版本…

windows远程连接无法复制文件

windows远程桌面无法复制文件 解决方案 打开任务管理器管理器,在详细信息界面,找到rdpclip.exe进程&#xff0c;选中并点击结束任务&#xff0c;杀死该进程。 快捷键 win r 打开运行界面&#xff0c;输入 rdpclip.exe &#xff0c;点击确定运行。即可解决无法复制文件问题。…

产品设计的8大步骤

产品设计&#xff0c;通俗来说就是将创新想法或概念转化为落地实体的过程。一般来说&#xff0c;一个成功的产品应当具有创新性、美观性、实用性、可持续性以及经济效益&#xff0c;从而满足用户的使用需求以及市场的发展需求。产品设计也并不是一件简单的事情&#xff0c;产品…