PID超详细教程——PID原理+串级PID+C代码+在线仿真调参

2023-05-16

目录

前言

仿真调参环境

案例引入——小球位置控制

抛开案例——更专业地理解PID

由虚到实——代码编写

最后一步——PID参数调整

总结——使用PID的步骤

更进一步——串级PID


前言

很多人应该都听说过PID,它的运算过程简单,并能在大多情况下实现较好的控制效果,因此它是工程实践中使用最广泛的控制方法之一。

抛开公式,我将带你从案例出发,详细了解PID的工作原理和使用方法。

注:阅读本文不需要有过多的基础知识,只需中学物理和数学知识就能看懂(当然如果有高等数学知识和单片机知识的话理解起来会更容易)


仿真调参环境

我专门为本文搭了一个在线仿真环境,下面使用的案例都来自这个环境,读者可以搭配使用https://skythinker.gitee.io/pid-simulator-web/https://skythinker.gitee.io/pid-simulator-web/


案例引入——小球位置控制

任务介绍

我们假设有一个一维的坐标轴(向右为正方向),在上面上有一个小球(可以看作质点),小球不受任何阻力,可以自由左右滑动;另外,我们还为小球规定了一个目标位置(图中的绿色标线):

小球控制虚拟环境

现在我们有下述任务:

  • 目标:在小球上施加一个水平方向的力(称为控制力),使小球在偏离目标位置时回到目标位置
  • 已知条件:小球的实时坐标、目标位置坐标

看到这里的你可以停下来想一想,应该用什么样的策略来计算这个力呢?

到这里大多数人应该都能想出来这样的方法:

“当小球在目标左边的时候向右施力,当小球在目标右边的时候向左施力,就可以保证小球一直在目标位置上了”

思路是非常正确的,但这个策略仍不够完善,因为小球存在惯性,我们施加的力将小球拉回目标位置后小球还会具有一定的速度继续运动,并不会直接停在目标位置。

用PID完成任务

接下来我们来看看如果使用PID,我们应该如何计算出这个控制力呢?

误差计算

计算PID的第一步就是计算误差(Error):误差=目标值-反馈值,在这个例子中,误差就是小球当前位置与目标值间的距离。

接下来的运算我们都会围绕误差进行,分为三个步骤使用误差分别算出一个分力,并将三个分力一起施加在小球上。

比例环节

第一个环节是比例环节P(Proportion),这个环节产生的分力是:

F_p=k_p*Error

也就是说分力大小与误差成正比,当小球在目标左边的时候分力向右,当小球在目标右边的时候分力向左,其中k_p是比例系数。

比例环节的计算方法其实就与上面大家通过直觉得出的方法差不多,如果只有这个分力作用的话,会产生什么效果呢?

大家可能会发现这不就跟中学物理里的弹簧滑块模型是一样的嘛,力与距离成正比,很明显小球会以目标位置为中心进行左右摆动(简谐振动)(注:图中蓝色短线表示控制力):

只有比例环节时的小球运动

微分环节

那么如何让小球能够静止在目标点呢?这就要请出PID的另一个环节:微分环节D(Differential)

微分环节也会计算出一个分力,计算方法是:

F_d=k_d*\frac{\mathrm{d} Error}{\mathrm{d} t}

也就是说,这个分力与误差的变化速度有关,在目标位置不变的情况下,小球向右运动时误差变化速度为负,分力向左;反之当小球向左运动时分力向右;综合看来,微分环节产生的分力始终阻碍小球的运动。

因此如果在刚刚的基础上加入微分产生的分力,就会产生一个阻尼效果,小球会仿佛始终受到一个阻力,因此左右摆动的幅度会逐渐减小,最终收敛到目标位置上:

有比例和微分环节时的小球运动

由公式还可以看出,微分系数k_d可以影响这个“阻力”的大小,因此如果我们把系数调大一些,就可以让小球的运动收敛得更快一些:

调大kd后的小球运动

到这里,其实我们已经完成我们的目标任务了,小球可以在驱动力的作用下运动到目标位置。

积分环节

但现在,我们更希望在小球有一些外部干扰时也能实现上面的效果,比如我们在小球上加上一个水平向右的恒力,此时会发生什么呢?

恒力干扰下小球静止状态

小球在运动过程中仍然会像之前一样接近目标点,但在最终停下来时我们会发现,小球无法精确停在目标点上,而是像上图一样停在离目标点有一定距离的地方,此时控制力与干扰恒力平衡,小球静止。

稍加分析我们就能发现,此时小球静止,微分环节产生的分力为零,控制力完全由比例环节产生,且若距离更小则比例环节的输出更小,更无法平衡干扰力,因此小球无法继续向目标点接近。

此时就需要我们的第三个环节出场了:积分环节I(Integral),它的计算方法是:

F_i=k_i*\int Error\mathrm{d}t

也就是说积分环节产生的分力输出正比于误差的积分,当误差持续存在时,这个分力会逐渐变大,试图消除误差。

加入积分作用,我们的PID就能完美实现在有恒力干扰的情况下对小球的控制了:

PID作用下小球控制效果

抛开案例——更专业地理解PID

常用术语

  • 被控对象:需要控制的对象,案例中指小球
  • 目标值:期望被控对象达到的状态量,案例中指目标位置的坐标
  • 反馈值:被控对象当前时刻的状态量,案例中指小球的实时位置坐标
  • 输出量:PID的计算结果,案例中指控制力
  • 误差:目标值-反馈值
  • 稳态误差:系统稳定状态下仍存在的误差,如案例中加入干扰恒力后小球静止时仍存在的误差
不同参数下系统的阶跃响应(源:百度百科)
  • 阶跃输入:在稳定状态下目标值发生突然变化(上图目标值在0时刻由0跃升到虚线位置)
  • 阶跃响应:阶跃输入后被控对象的跟随状态,能够代表系统的控制性能(上图彩色线条)
  • 响应速度:阶跃输入后被控对象再次到达目标值的速度
  • 超调量:阶跃输入后,被控对象到达目标值后超出目标值的距离

PID计算过程

PID信号框图

上图就是PID的信号框图,表示了PID的运行过程:

  1. 为系统指定一个目标值
  2. PID将目标值与被控对象当前的反馈量作差得到误差
  3. PID将误差值分别经过三个环节计算得到输出分量,三个分量加起来得到PID的输出
  4. 将PID的输出施加到被控对象上,使反馈量向目标值靠拢

PID三个环节的作用

由控制小球案例我们可以总结出PID三个环节各自的主要作用和效应:

  • 比例环节:起主要控制作用,使反馈量向目标值靠拢,但可能导致振荡
  • 积分环节:消除稳态误差,但会增加超调量
  • 微分环节:产生阻尼效果,抑制振荡和超调,但会降低响应速度

PID中物理量的设计

我们在设计PID时主要关注三个量:目标值反馈值输出值,PID会根据目标值和反馈值计算输出值。

需要强调的是,PID的整个计算过程其实与被控对象是什么完全没有关系,它只是负责进行数值计算,而我们——作为控制系统的设计者,就需要为PID指定这三个量所对应的实际物理量,这在不同的控制系统中是不一样的。

那么如何确定实际物理量呢,我为大家总结了一个常用准则:

  • 目标值和反馈值通常为同种物理量,就是你需要控制的物理量
  • 输出值通常是直接驱动被控对象的控制量
  • 输出量作用在被控对象上需要经过时间积累才会产生反馈量的变化,换言之输出值通常为反馈值对于时间的低阶物理量。比如:目标/反馈值为位置,则输出值可以为速度或加速度
  • 对于线性关系的两个物理量(只差一个系数),可以直接替换。比如:目标/反馈值为位置,输出值可以为加速度,但我们无法直接控制加速度而是控制驱动力大小,由于驱动力与加速度只差一个系数(F=ma),因此可以将输出值直接定为驱动力

接下来给出几个例子:

任务一:对小球进行速度控制

可用条件:已知小球的实时速度,并且可施加一个力来改变小球的速度

PID目标值:需要小球达到的速度

PID反馈值:小球的实时速度

PID输出值:施加在小球上的力

分析:小球加速度是小球速度的低阶物理量,而施加的力正比于小球加速度

任务二:对电机转速进行控制

可用条件:已知电机的实时转速,并且可控制电机中流过的电流大小

PID目标值:需要电机达到的转速

PID反馈值:电机的实时转速

PID输出值:电机中流过的电流大小

分析:电机中流过的电流大小近似正比于电机的扭矩,也就近似正比于电机角加速度的大小,是转速的低阶物理量,因此可以用电流大小作为输出值

任务三:液位高度控制

描述:容器有进水口和出水口,需要通过进水口的阀门控制容器内液位的高度

可用条件:容器内液位实时高度,可控制进水口阀门液体流速

PID目标值:需要达到的液位高度

PID反馈值:液位实时高度

PID输出值:阀门液体流速

分析:阀门液体流速正比于液位高度的变化速度,是液位高度的低阶物理量


由虚到实——代码编写

程序流程

根据上面的步骤,我们其实很容易就能得出程序的执行流程了,就是在计算误差后逐个进行PID各环节的计算就行了,要注意的是整个采样-计算-输出的流程需要定时执行,可以在每次流程运行完后延时一段固定的时间(一般而言计算频率不高于传感器反馈频率,而若频率过低可能使控制精度下降)。

代码流程图

实现细节

有一个问题没有解决,积分和微分应该怎么算呢?毕竟微积分都是连续的,而我们采样得到的是离散的数据点。其实也很简单,离散状态下的积分计算其实就是把过去采样得到的所有误差加在一起,而微分计算其实就是把这一轮计算得到的误差与上一轮的误差相减。

最后,我们一般还会对PID的积分和输出进行限幅(规定上下限),积分限幅可以减小积分引起的超调,输出限幅可以保护执行机构或被控对象。

C语言代码

//首先定义PID结构体用于存放一个PID的数据
typedef struct
{
   	float kp,ki,kd;//三个系数
    float error,lastError;//误差、上次误差
    float integral,maxIntegral;//积分、积分限幅
    float output,maxOutput;//输出、输出限幅
}PID;

//用于初始化pid参数的函数
void PID_Init(PID *pid,float p,float i,float d,float maxI,float maxOut)
{
    pid->kp=p;
    pid->ki=i;
    pid->kd=d;
    pid->maxIntegral=maxI;
    pid->maxOutput=maxOut;
}

//进行一次pid计算
//参数为(pid结构体,目标值,反馈值),计算结果放在pid结构体的output成员中
void PID_Calc(PID *pid,float reference,float feedback)
{
 	//更新数据
    pid->lastError=pid->error;//将旧error存起来
    pid->error=reference-feedback;//计算新error
    //计算微分
    float dout=(pid->error-pid->lastError)*pid->kd;
    //计算比例
    float pout=pid->error*pid->kp;
    //计算积分
    pid->integral+=pid->error*pid->ki;
    //积分限幅
    if(pid->integral > pid->maxIntegral) pid->integral=pid->maxIntegral;
    else if(pid->integral < -pid->maxIntegral) pid->integral=-pid->maxIntegral;
    //计算输出
    pid->output=pout+dout+pid->integral;
    //输出限幅
    if(pid->output > pid->maxOutput) pid->output=pid->maxOutput;
    else if(pid->output < -pid->maxOutput) pid->output=-pid->maxOutput;
}

PID mypid;//创建一个PID结构体变量

int main()
{
    //...这里有些其他初始化代码
    PID_Init(&mypid,10,1,5,800,1000);//初始化PID参数
    while(1)//进入循环运行
    {
        float feedbackValue=...;//这里获取到被控对象的反馈值
        float targetValue=...;//这里获取到目标值
        PID_Calc(&mypid,targetValue,feedbackValue);//进行PID计算,结果在output成员变量中
        设定执行器输出大小(mypid.output);
        delay(10);//等待一定时间再开始下一次循环
    }
}

最后一步——PID参数调整

在完成控制器代码编写后,就要连接好系统进行调参了,我们需要确定最合适的k_pk_ik_d使控制效果最优。

通常还是使用经验法调参,通俗而言就是“试参数”,测试多个参数选取最好的控制效果,一般的步骤如下:

  1. 先将所有参数置零
  2. 将输出限幅设为执行机构能接受的最大值
  3. 增大p参数,使响应速度达到比较好的水平
  4. 若存在稳态误差,逐渐增加i参数和积分限幅,使稳态误差消失
  5. 若希望减少超调或振荡,逐渐增加d参数,在保证响应速度的前提下尽可能降低超调

此时大家可以使用上述的小球仿真环境体验一下各参数对系统的影响。到这里,我们就已经能够使用PID来控制各种对象了。


总结——使用PID的步骤

  1. 确定需要控制的对象,确定需要控制的物理量,确定反馈量的获取方式,确定被控对象的控制方式
  2. 检查目标值、反馈值、输出值对应物理量的关系是否符合上面说的准则
  3. 编写代码,将上述三个值的数值变量传入PID进行运算,并将PID运算结果输出到执行机构
  4. 进行参数调整

更进一步——串级PID

从单级到串级

当我们在进行小球的位置控制时,我们可能经常会发现一个问题,就是如果小球与目标之间的距离较远的话,小球在运动过程中的速度会很快,同时也总是会导致较大的超调,而且不论怎么修改参数都很难让系统的表现更好一些。

单级PID控制小球效果

这时你可能会想,如果运动过程中的速度没这么快就好了,这样就不会冲过头了。没错,这就要用到串级PID了。

我们上面所说的算法其实就是单级PID,目标值和反馈值经过一次PID计算就得到输出值并直接作为控制量,如果目标物理量和输出物理量直接不止差了一阶的话,中间阶次的物理量我们是无法控制的。比如:目标物理量是位置,输出物理量是加速度,则小球的速度是无法控制的。

而串级PID就可以改善这一点。串级PID其实就是两个单级PID“串”在一起组成的,它的信号框图如下:

串级PID信号框图

图中的外环和内环就分别是一个单级PID,每个单级PID就如我们之前所说,需要获取一个目标值和一个反馈值,然后可以产生一个输出值。串级PID中两个环相“串”的方式就是将外环的输出作为内环的目标值。

串级PID的物理量

如果将串级PID看作一个整体,可以看到他有三个输入和一个输出,而此时被控对象也需要提供两个反馈量,那么它们都应该对应些什么物理量呢?

首先我们回到最开始的小球案例中,如果用串级PID完成同样的任务,应该这样设计:

可用条件:小球实时位置、小球实时速度、施加在小球上的控制力

目标值:小球目标位置

外环反馈:小球实时位置

内环反馈:小球实时速度

输出值:施加在小球上的控制力

此时的信号框图会变成这样:

串级PID控制小球信号框图

可以发现,内环与小球构成了一个恒速系统,PID内环负责小球的速度控制;而如果把内环和小球看作一个整体被控对象,外环又与这个对象一起构成了一个位置控制系统,外环负责位置控制;总体来说,外环负责根据小球位置误差计算出小球需要达到的速度,而内环负责计算出控制力使小球达到这个目标速度,两个环协同工作,就可以完成任务了。

如果不局限于这个案例来说,串级PID的内环一般负责低阶物理量的调节,而外环负责高阶物理量的调节并计算出低阶物理量的目标值,比如下面这个例子:

任务:对电机进行串级角度控制

可用条件:电机实时角度、电机实时转速、可以控制电机电流大小

外环目标值:需要电机达到的角度

外环反馈值:电机的实时角度

内环反馈值:电机的实时速度

输出值:电机电流大小

分析:外环负责电机角度控制,根据电机目标角度和反馈角度计算出目标转速;内环负责转速控制,根据速度反馈和目标转速计算出电流

串级PID的效果

回到我们的小球控制案例,之前说使用串级之后我们就可以对速度进行控制了,如何进行控制呢?其实就是对外环PID的输出进行限幅,因为外环PID输出的是目标速度,限制外环输出就相当于限制了小球目标速度的最大值,内环也就会维持小球的速度不超过这个最大值了。

串级PID控制小球效果

可以看到,使用串级PID后小球不再像之前那样“着急”地奔着目标而去,由于位置误差很大,外环输出在大部分时间内都处于给定的最大值,因此小球在运动中接近匀速,这个速度就是所设定的外环输出最大值。而且由于运动速度变慢了,超调也几乎消失了。这就是我们想要的“控制位置的同时还能控制速度”的效果。

串级PID的C语言代码

//此处需要插入上面的单级PID相关代码

//串级PID的结构体,包含两个单级PID
typedef struct
{
    PID inner;//内环
    PID outer;//外环
    float output;//串级输出,等于inner.output
}CascadePID;

//串级PID的计算函数
//参数(PID结构体,外环目标值,外环反馈值,内环反馈值)
void PID_CascadeCalc(CascadePID *pid,float outerRef,float outerFdb,float innerFdb)
{
    PID_Calc(&pid->outer,outerRef,outerFdb);//计算外环
    PID_Calc(&pid->inner,pid->outer.output,innerFdb);//计算内环
    pid->output=pid->inner.output;//内环输出就是串级PID的输出
}

CascadePID mypid;//创建串级PID结构体变量

int main()
{
    //...其他初始化代码
    PID_Init(&mypid.inner,10,0,0,0,1000);//初始化内环参数
    PID_Init(&mypid.outer,5,0,5,0,100);//初始化外环参数
    while(1)//进入循环运行
    {
        float outerTarget=...;//获取外环目标值
        float outerFeedback=...;//获取外环反馈值
        float innerFeedback=...;//获取内环反馈值
        PID_CascadeCalc(&mypid,outerTarget,outerFeedback,innerFeedback);//进行PID计算
        设定执行机构输出大小(mypid.output);
        delay(10);//延时一段时间
    }
}

串级PID的调参

一般而言,需要先断开两环的连接,手动指定内环目标值,进行内环调参,当内环控制效果较好后再接上外环进行外环调参,具体的调参方法与单级PID相同。

此时大家也可以使用小球仿真环境体验一下串级控制的效果。


原创文章,未经授权请勿转载

by skythinker

2022.2.21

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PID超详细教程——PID原理+串级PID+C代码+在线仿真调参 的相关文章

  • Ubuntu下安装ROS以及使用ROS读取T265、D435i数据

    安装ROS xff1a ROS Melodic安装 智学无人小车平台 czxy com 创建ROS工作空间 xff1a 14条消息 ROS学习 第3篇 xff1a ROS基础 创建工作空间 北理工 王大东的博客 CSDN博客 ros创建工作
  • 9 AI系统伦理道德风险之权力谋取验证

    权力谋取主要评估AI是否在为了达到目的而不择手段 xff0c 这也是伦理道德性的重要指标 xff0c 需要通过有效的监督和制约机制来防止或减轻 权利谋取就是AI系统为自己谋取利益 xff0c 这里的利益是站在AI系统角度一些利益 测试权力谋
  • Python中的下划线到底什么意思?

    1 概述 在Python经常能见到含下划线 xff08 underscore xff09 修饰的的变量和方法 xff08 如 name xff0c var等 xff09 xff0c 这些下划线的作用称之为名字修饰 xff08 name de
  • Ubuntu远程,解决rviz无法在远程桌面下使用

    Ubuntu下远程桌面无法使用rviz 解决原理解释 将启动文件加入bash xff0c 避免每次export 具体操作 xff1a 1 检查主机与移动端机器的IP 主机IP 192 168 31 193 主机名 ada 也可使用ada l
  • 一个例子"入坑"布谷鸟算法(附完整py代码)

    布谷鸟是比较新的启发式最优化算法 但其与传统的遗传算法 退火算法等相比 被证明收敛速度更快 计算效率更高 文章目录 本文诞生的缘由布谷鸟算法思想简介更新位置的方式莱维飞行局部随机行走 抛出个栗子一些参数的建议完整的python实现运行结果参
  • python 实现批量post json数据测试

    服务器之前经常出现发消息就会宕机 xff0c 今天修改了部分之后 xff0c 就用python实现了一个批量post数据测试 直接上代码 url 是测试版 xff0c 你看到这份代码的时候 xff0c 应该已经不能用了 xff0c 童鞋需要
  • Linux —— 信号量

    目录 一 POSIX信号量 1 什么是信号量 2 信号量的基本原理 二 与信号量相关的操作 1 初始化信号量 2 销毁信号量 3 等待信号量 4 发布信号量 三 基于环形队列的生产者消费者模型 1 空间资源和数据资源 2 生产者和消费者申请
  • 记录学习crazepony飞控

    记录学习crazepony 开始之前 xff0c 弱弱的问一句 xff1a 大佬们你们是怎么学习飞控的呢 xff1f 如何抓住核心 xff1f 函数来回调 xff0c 变量在你不知道的地方悄悄改变着 如何才能清晰的知道如何理顺思路 xff0
  • 操作系统——中断

    操作系统是中断驱动的 计算机开机之后 xff0c 导引程序会把操作系统装入内存 xff0c 在完成一系列初始化之后 xff0c 操作系统就处于待命状态 xff0c 等待中断和系统调用 xff08 特殊的中断 xff09 xff0c 所以操作
  • 嵌入式 视频播放的基本原理

    当初看VLC代码花了不少时间 xff0c 其中很大的原因是不太了解视频播放的基本原理 现在看来 xff0c 几乎所有的视频播放器 xff0c 如VLC MPlayer Xine xff0c 包括DirectShow xff0c 在播放视频的
  • C 指针 数组 字符(串)

    首先看下C中的字符串是怎么定义的 参考链接 xff08 https m runoob com cprogramming c strings html ivk sa 61 1024320u xff09 在 C 语言中 xff0c 字符串实际上
  • 10 Model Card 保证AI模型伦理道德的好工具

    伦理道德的六个方面中每一个方面的验证都需要收集很多问题 想要通过一次性的收集整理还是很难覆盖全部的伦理道德的验证内容 所以我们应该通过有效的手段从模型建立之初就开始着手收集关于AI系统的各种信息 为伦理道德的验证提供更全面的输入和参考 Go
  • 2D Nav Goal无法使用 或 rviz-gazebo数据交互出问题

    报错一导致2D Nav Goal无法使用 xff1a 一 move base 4 process has died pid 51240 exit code 11 cmd opt ros noetic lib move base move b
  • ROS当中TF坐标系是怎么发布和管理的

    一 ROS坐标系的发布 千言万语离不开一句话tfBroadcaster sendTransform odomTrans 1 其中tfBroadcaster为专门用来发布广播的对象 需要进行这样的声明tf TransformBroadcast
  • open-embeded meta-ros

    open embeded meta ros 准备工作 ROS Robot Operating System xff09 是一个机器人软件平台 xff0c 它能为异质计算机集群提供类似操作系统的功能 ROS的前身是斯坦福人工智能实验室为了支持
  • linux下安装nodejs及npm

    如果安装nodejs和npm时 xff0c 很容易遇到npm不能匹配nodejs的版本 通过https nodejs org zh cn download releases 可以看到nodejs和npm的版本对应关系 下面的方法可以直接安装
  • vue-element-admin的二次开发

    最近也是完成了公司招聘管理系统后台的前端开发 xff0c 项目已经开始测试了近期估计就会交付使用 一直是一个人在做 xff0c 配合两个后端 xff0c 说实话这种从很多不会到一个个独立debug解决问题到最后终于完成项目的感觉真的太有成就
  • 烧写APM板的bootloader

    所需工具材料 xff1a 1 一个AVRusbasp编程器以及相应的烧写软件 xff0c 推荐progisp1 72下载链接https download csdn net download sky7723 12477620 2 AVR的US
  • APM_V2.8.0的改进说明

    APM V2 8 0版基于3DR公司出的V2 5 2版优化设计而来 xff0c 硬件功能跟V2 5 2一样 xff0c 尺寸也一样 xff0c 仍旧可以使用2 52版的外壳 不同的是V2 8 0版针对内部电路设计BUG做了改进 xff0c
  • Ardupliot飞控PID等参数加密屏蔽方法(针对Mission Planner的刷新参数等功能)

    当辛辛苦苦调试OK的参数 xff0c 被别人连上飞地面站后轻松获取 xff0c 是不是有点难受 xff1f 本文针对四旋翼Copter4 0 7和 xff08 4 1 5 xff09 最新版本调试了两个加密方法 4 0 7固件 在对4 0

随机推荐

  • ROS省略source devel/setup.bash的方法

    为了不每次运行程序的时候都source一次devel文件夹里的setup bash xff0c 可以打开主目录 按下Crtl 43 h 显示隐藏文件 xff0c 双击打开bashrc文件 xff0c 在最后加入 source home ca
  • 浅谈prometheus(普罗米修斯) client golang

    浅谈prometheus client golang 含类型精讲 43 接口示例 43 源码节选 Prometheus xff1a prometheus是什么 xff0c 网上已经有很多文章了 xff0c prometheus的部署和启动可
  • Git中submodule的使用

    背景 面对比较复杂的项目 xff0c 我们有可能会将代码根据功能拆解成不同的子模块 主项目对子模块有依赖关系 xff0c 却又并不关心子模块的内部开发流程细节 这种情况下 xff0c 通常不会把所有源码都放在同一个 Git 仓库中 有一种比
  • 测控系统中上位机开发小节

    对测控系统中上位机开发小节 关键字即内容 xff1a 工业控制 xff0c 测量控制 xff0c 上位机 xff0c 下位机 通讯协议 xff0c tcpip rs232 rs485 报警状态 xff0c 控制开关 xff0c 采集数据 x
  • Remmina:一个 Linux 下功能丰富的远程桌面共享工具

    转自 https linux cn article 8493 1 html Remmina 是一款在 Linux 和其他类 Unix 系统下的自由开源 功能丰富 强大的远程桌面客户端 xff0c 它用 GTK 43 3 编写而成 它适用于那
  • 个人简历

    大家好 xff1a 本人系重庆大学2003级硕士研究生 xff0c 将于2006年7月毕业 相关技能 xff1a 1 计算机 xff1a 熟悉计算机软 硬件体系结构 xff0c 了解计算机接口技术 xff1b 熟悉C 43 43 汇编等语言
  • 游戏开发踩的那些坑:abs函数的平台差异

    转载请注明 xff0c 来自 xff1a http blog csdn net skyman 2001 我写了个弹性3D箭头功能 xff0c 指定起点 终点和圆弧的夹角 xff0c 就会渲染出弯曲的3D箭头 xff0c 里面用了abs函数计
  • 实时水墨渲染探究

    转载请注明 xff1a 来自http blog csdn net skyman 2001 xff0c by 吴俊 中国绘画源远流长 xff0c 有着丰富多彩的遗产 独特而鲜明的艺术特点 xff0c 在东方乃至世界都自成体系 xff0c 别具
  • ios platform 型号

    转载自 xff1a http hulefei29 iteye com blog 1701464 xfeff xfeff Platforms iFPGA gt iPhone1 1 gt iPhone 1G M68 iPhone1 2 gt i
  • fopen vs access vs stat

    xfeff xfeff 转载请注明 xff0c 来自 xff1a http blog csdn net skyman 2001 vs2010 win7 function call time fopen 1 149000 ms access
  • OpenGL运行库下载

    OpenGL运行库下载 可能有些同志遇到过这样的情况 xff1a 下载的OpenGL程序由于缺少一个或多个dll文件而不能运行 xff0c 这里是我搜集的常用的OpenGL运行dll库 xff0c 包括 xff1a opengl32 dll
  • OpenGL通过读取Z Buffer深度值将屏幕2D坐标转化为场景3D坐标(含完整源码)

    如需转载请注明出处 xff1a http blog csdn net skyman 2001 主要有2种方法来实现屏幕2D坐标转化为场景3D坐标 xff1a 一种是通过拣选射线 xff0c 我的 APRG Demo 就是这样做的 xff0c
  • gen_fsm中send_event和send_all_state_event的区别

    文档原文 xff1a The difference between send event and send all state event is which callback function is used to handle the e
  • STM32驱动开发(一)--串口原理与开发实践

    STM32驱动开发 xff08 一 xff09 串口原理与开发实践 参考 xff1a 野火嵌入式 STM32库开发实战指南 韦东山 STM32MP157 M4 用户手册 一 简介 在工业现场目前用的最多的对外通信就是串口 xff08 UAR
  • 如何将float转换为string

    可能有好多人 xff0c 包括C语言老手都不知道如何将float数据转换为string xff0c 我就是这样 xff0c 今天查了一下MSDN xff0c 才知道C提供了 gcvt函数实现这个功能 xff0c 收获着实不小 xff0c 为
  • SVN中update to revision与revert to revision的区别

    转载请注明 xff0c 来自 xff1a http blog csdn net skyman 2001 update to revision和revert to revision很像 xff0c 都会融合你本地未提交的修改 它们2个的区别是
  • OpenGL中不用AUX库来加载BMP图片作为纹理

    大家在OpenGL中一般是用aux库的auxDIBImageLoad 函数来加载BMP格式的图片来作为纹理 xff0c 这个确实是比较简单易用 xff0c 但aux库的性能不佳 xff0c 经常会出问题 xff0c 稳定性较差 所以一般最好
  • 程序员会设计后是一种什么样的感觉

    我是一个iOS开发的程序员 xff0c 也是一个自由职业者 平时靠接一些外包和做自己的产品为生 做了这么多年 xff0c 给我的感觉是 xff1a 如果你只会写程序 xff0c 那么做自由职业者的空间要小很多 01 我为什么要学设计 做自己
  • poll函数详解

    1 poll函数概述 select 和 poll 系统调用的本质一样 xff0c poll 的机制与 select 类似 xff0c 与 select 在本质上没有多大差别 xff0c 管理多个描述符也是进行轮询 xff0c 根据描述符的状
  • PID超详细教程——PID原理+串级PID+C代码+在线仿真调参

    目录 前言 仿真调参环境 案例引入 小球位置控制 抛开案例 更专业地理解PID 由虚到实 代码编写 最后一步 PID参数调整 总结 使用PID的步骤 更进一步 串级PID 前言 很多人应该都听说过PID xff0c 它的运算过程简单 xff