电机矢量控制程序实例(附代码)
EV技研
公众号EV技研作者19002019/08/13 电动汽车 IP:美国


 运行环境

 RX62T 低电压电机控制评估系统 

下面以瑞萨 RX62T 低电压电机控制评估系统 (RSSK)为例,介绍控制相关内容。RSSK 是以 24V 电机为对象,进行 120°/180° 通电,实施霍尔传感器 / 旋转编码器 / 无传感器控制的实验系统。程序中的变量在实际运行过程中的变 化可以通过 PC 显示,也可以通过低电压电机控制系 统的变量波形显示工具 ICS(In-Circuit Scope)显 示,有助于缩短开发时间(照片 1)。 

1565666598523.jpg


系统运行参数 

(1)电 机 ·电机转速:最低 600r/min,最高 2000r/min ·母线电压:24V ·电流:最大相电流为 1.8A (2)逆变器 ·载波频率:20kHz ·电流 / 电压控制:PI 控制(监测 U 相、V 相、 W 相电流,母线电压) ·编码器脉冲:输出轴每旋转 1 圈产生 300 个脉冲 (3)软 件 微处理器 RX62T 的资源分配参见表 1,软件结 构如图 2 所示。

1565666598583.jpg



 控制方法

 控制周期

 由于是矢量控制,根据 PWM 载波周期(20kHz) 的编码器输出信号,计算转子位置和转速,并调整 PWM 输出。速度控制(PI 运算)以 1ms 为周期, 读取编码器脉冲计数的累计值。运算处理的负荷很大,能否在规定时间内完成 运算处理十分重要。运算处理的时间概念如图 3 所 示。下面,我们来看看具体内容。

1565666599469.jpg


 每个载波周期的运算处理项目

 载波周期内的矢量控制运算,大致可以归纳为 以下几点。·获取 U、W 相电流(V 相电流通过计算得出), 逆变器母线电压 ·坐标变换(U,V,W → α, β → d, q) ·电流 PI 控制 ·非干涉控制 ·调制,坐标变换(d, q → α β → U,V,W) ·设定 PWM 输出占空比(U,V,W) 也就是说,将矢量控制插入载波周期中断。当然,所有的计算都不能超过周期,这是必须遵守的绝对条件。对于没有 FPU(浮点运算单元) 的微处理器,要在进行坐标变换时,设定固定的小 数点。另外, 微处理器的时钟频率要达到 50MHz 左右,才有足够的处理能力。使用 20MHz 左右的微 处理器进行控制时,要下调载波频率;或者放弃在 每个载波周期进行控制,每 3 个周期进行一次矢量 控制。 

 运算的输入参数

 (1)编码器输入 编码器检测速度、位置,输入 MTU3 的 MTCLKA、MTCLKB 进行计数(图 4)。

1565666599472.jpg


 编码器每转 动 1 圈输出 300 个脉冲,其脉冲沿计数不会超过:300×4 倍= 1200当计数达到 1200 时,计数器归零。这就是编码 器的设定方式。但是,根据编码器输入得到的是相对位置 (图5),应在电机启动时进行位置调整。其方法将 在后面的内容中介绍。 

1565666599545.jpg


(2)母线电压 母线电压变化时,电机驱动的正弦波的峰峰值 与有效值也会变化。因此,这需要反映到 PWM 输 出占空比控制。实际上,这就决定了正弦波输出有 效值的大小(图 6)。

1565666599802.jpg


(3)相电流 相电流的检测时间,是载波周期内 PWM 输出 切换后电流达到稳定时。PWM 载波周期为 20kHz(50μs)。这比 A-D 转 换时间 1μs 要大,而且,使用了编码器的控制,是 根据相电流来估算转子位置的。因此,A-D 转换开 始触发,即使在载波周期中断内启动软件也是完全 可以的(图6)。

1565666599921.jpg


 为了提高相电流的检测精度,可以放大信号, 使 A - D 转 换 器 工 作 于 极 致 状 态 ( 图 7 )。

1565666600103.jpg


 当 然 , 分流电阻损耗会增加。以 RSSK 为例,电阻值为 0.05Ω(50mΩ)。测量范围是 -10~+10A,信号经 5 倍放大后, 有效值为 1/2Vcc 时,电压为 -2.5~+2.5V。


程序实例1矢量控制——初始化部分

void R_MTR_InitHardware(void)

{

/*==========================*/

/* 初始化时钟 */

/*==========================*/

XXXXXXXXXXXXXXXT.ICK = 0x00; // ICLK : EXTAL×8 (96MHz) / EXTAL=12MHz

XXXXXXXXXXXXXXXT.PCK = 0x01; // PCLK : EXTAL×4 (48MHz) / EXTAL=12MHz

/*===========================*/

/* 初始化外设功能 */

/*===========================*/

MSTP_CMT0 = 0; // 模块停止状态被取消

MSTP_MTU = 0;

MSTP_S12AD0 = 0;

MSTP_S12AD1 = 0;

/*========================*/

/* 初始化 CMT0 */

/*========================*/

XXXXXXXXXXXXXXXXXR0 = 0; // 停止 CMT0

XXXXXXXXXXXXXXXXS = 0; // 时钟 : PCLK/8 */

XXXXXXXCOR = 5999; // 设定间隔时间

XXXXXXXXXXXXXXXXIE = 1; // 比较匹配中段(CMI0) 使能

ICU.IPR[0x04].BIT.IPR = 13;

XXXXXX[28].XXXXXX = 0;

XXXXXXR[0x03].XXXXXXN4 = 1;

/*===================================*/

/* 初始化 MTU3_3,MTU3_4 */

/*===================================*/

XXXXXXXXXXXXTE = 0x00; // 停止 MTU3

XXXXXXXXXXXXXXXSC = 0; // MTU3_3 时钟 : ICLK

XXXXXXXXXXXXXXXEG = 0;

XXXXXXXXXXXXXXXSC = 0; // MTU3_4 时钟 : ICLK

XXXXXXXXXXXXXXXEG = 0;

XXXXXXXXXXXXXXXXC = 0;

XXXXXXXNT = MTR_DEADTIME_SET; // 设定社区时间

XXXXXXXNT = 0;

XXXXXXXRB = MTR_HALF_CARRIER_SET; // 设定占空比

XXXXXXXRA = MTR_HALF_CARRIER_SET;

XXXXXXXRB = MTR_HALF_CARRIER_SET;

XXXXXXXRD = MTR_HALF_CARRIER_SET; // 设定占空比

XXXXXXXRC = MTR_HALF_CARRIER_SET;

XXXXXXXRD = MTR_HALF_CARRIER_SET;

XXXXXXDRA = MTR_DEADTIME_SET;

XXXXXXDRA = (uint16)(MTR_CARRIER_SET - MTR_DEADTIME_SET);

XXXXXXBRA = (uint16)(MTR_CARRIER_SET - MTR_DEADTIME_SET);

XXXXXXXRA = MTR_CARRIER_SET; // 设定载波周期

XXXXXXXRC = MTR_CARRIER_SET;

XXXXXXXXXXXXXXXXXYE = 0;

XXXXXXXXXXXXXT.OLSP = 1; // 正相:初始输出"L", 有效电平"H"

XXXXXXXXXXXXXT.OLSN = 1; // 反相:初始输出"H", 有效电平"H"

XXXXXXXXXXXXXXXXX = 14; // 互补PWM 模式

XXXXXXXXXXXXXXXXXA = 1; // TGRA 和TGRC 一起用于缓冲器换作

XXXXXXXXXXXXXXXXXB = 1; // TGRB 和TGRD 一起用于缓冲器换作

XXXXXXXXXXXXXTE = 0x00;

XXXXXXXXXXXXTE = 0xC0; // PWM 输出禁止

XXXXXXXXXXXXXXXFV = 0; // 下溢中断(TGIA) 使能

XXXXXXXXXXXXXXXXIEV = 1;

ICU.IPR[0x5A].BIT.IPR = 14;

XXXXXX[138].XXXXXX = 0;

XXXXXXR[0x11].XXXXXXN2 = 1;

XXXXXXXXXXXXXT.TITM = 0; // 设定中断跳过功能

XXXXXXXXXXXXXXT.T4VCOR = 1;

XXXXXXXXXXXXXXT.T4VEN = 1;

XXXXXXXXXXXXTE = 0xC0; // 启动 MTU3_3 和MTU3_4

/*********** for encoder ***********/

XXXXXXXXXXXXT.B2 = 1; // B 相输入模式

XXXXXXXXXXXXT.B2 = 0;

XXXXXXXXXXXXT.B3 = 1; // A 相输入模式

XXXXXXXXXXXXT.B3 = 0;

XXXXXXXXXXXXXXXXX = 4;

XXXXXXXXXXXXXXXLR = 1;

XXXXXXXRA = (uint16)(MTR_LOAD_ENCD_CNT - MTR_ENCD_CPR_MECH) + 1;

XXXXXXXXXXXXT.CST1 = 1;

/*=======================================*/

/* 初始化 POE3 */

/*=======================================*/

XXXXXXXXXXXXXXXXT.POE0E = 1; // POE3 过电流设定

XXXXXXXXXXXXT.POE0M = 0x00;

XXXXXXXXXXXXT.PIE1 = 1;

XXXXXXR[0x15].XXXXXXN2 = 1;

ICU.IPR[0x67].BIT.IPR = 15;

XXXXXXXXXXXXT.OCE1 = 1;

XXXXXXXXXXXXT.OIE1 = 1;

XXXXXXXXXXXXXXXXXU3BDZE = 1;

XXXXXXXXXXXXXXXXXU4ACZE = 1;

XXXXXXXXXXXXXXXXXU4BDZE = 1;

/*=============================*/

/* 初始化 I/O 端品 */

/*=============================*/

/*************** inverter ***************/

XXXXXXXXXXXXT.B1 = 1; // Up 输出模式

XXXXXXXXXXXXT.B2 = 1; // Vp 输出模式

XXXXXXXXXXXXT.B3 = 1; // Wp 输出模式

XXXXXXXXXXXXT.B4 = 1; // Un 输出模式

XXXXXXXXXXXXT.B5 = 1; // Vn 输出模式

XXXXXXXXXXXXT.B6 = 1; // Wn 输出模式

XXXXXXXXXXXT.B1 = 0; // Up = "L"

XXXXXXXXXXXT.B2 = 0; // Vp = "L"

XXXXXXXXXXXT.B3 = 0; // Wp = "L"

XXXXXXXXXXXT.B4 = 0; // Un = "L"

XXXXXXXXXXXT.B5 = 0; // Vn = "L"

XXXXXXXXXXXT.B6 = 0; // Wn = "L"

/*************** A/D 转换器 ***************/

XXXXXXXXXXXXT.B0 = 1; ADC

XXXXXXXXXXXXT.B1 = 1;

XXXXXXXXXXXXT.B2 = 1;

XXXXXXXXXXXXT.B6 = 1;

/*==================================*/

/* 初始化 A/D 转换器 */

/*==================================*/

/*************** Unit0 (Iu,Iw,Vdc) ***************/

XXXXXXXXXXXXXXXXXXXGE = 0; // 使用具有采样保持功能的单周期扫描模式

XXXXXXXXXXXXXXXXXXXS = 3;

XXXXXXXXXXXXXXXXXXXIE = 0;

XXXXXXXXXXXXXXXXXXXCS = 1;

XXXXXXXXXXXXXXXXXXX = 2;

XXXXXXXXXXXXXXXXXXXBYP = 0;

XXXXXXXXXXXXXXXXXXXRFMT = 0;

/*************** Unit1 (VR1) ***************/

XXXXXXXXXXXXXXXXXXXGE = 0; // 使用单一模式

XXXXXXXXXXXXXXXXXXXS = 3;

XXXXXXXXXXXXXXXXXXXIE = 0;

XXXXXXXXXXXXXXXXXXXCS = 0;

XXXXXXXXXXXXXXXXXXX = 2;

XXXXXXXXXXXXXXXXXXXRFMT = 0;

/*========================*/

/* 初始化 WDT */

/*========================*/

WDT.WRITE.WINA = 0x5A00; // 使用看门狗定时器模式

WDT.WRITE.WINB = 0xA500;

WDT.WRITE.WINB = 0x5A5F;

WDT.WRITE.WINA = 0xA5FF;

}


程序2 每个载波周期的矢量控制

static void mtr_mtu4_interrupt(void)

{

fl oat32 f4_temp0;

fl oat32 f4_temp1;

fl oat32 f4_temp2;

/*=============================================*/

/* A/D : 电流和电压检测 */

/*=============================================*/

clrpsw_i();

mtr_get_iuiwvdc(&g_f4_iu_ad, &g_f4_iw_ad, &g_f4_vdc_ad);

setpsw_i();

g_f4_iu_ad = g_f4_iu_ad - MTR_ADC_SCALING;

g_f4_iw_ad = g_f4_iw_ad - MTR_ADC_SCALING;

g_f4_iu_ad = g_f4_iu_ad * MTR_CURRENT_SCALING; // U 相电流

g_f4_iw_ad = g_f4_iw_ad * MTR_CURRENT_SCALING; // W 相电流

/*** 电流偏差调整 ***/

if (g_u2_cnt_adjust == 100)

{

g_f4_iu_ad = -g_f4_iu_ad + g_f4_offset_iu;

g_f4_iw_ad = -g_f4_iw_ad + g_f4_offset_iw;

g_f4_iu_ad = g_f4_pre_iu_ad + MTR_CURRENT_LPF_K * (g_f4_iu_ad - g_f4_pre_iu_ad);

g_f4_pre_iu_ad = g_f4_iu_ad;

g_f4_iw_ad = g_f4_pre_iw_ad + MTR_CURRENT_LPF_K * (g_f4_iw_ad - g_f4_pre_iw_ad);

g_f4_pre_iw_ad = g_f4_iw_ad;

}

else

{

/*** 调整偏差 ***/

g_f4_offset_iu += MTR_CURRENT_LPF_K * (g_f4_iu_ad - g_f4_offset_iu);

g_f4_iu_ad = -g_f4_iu_ad + g_f4_offset_iu;

g_f4_offset_iw += MTR_CURRENT_LPF_K * (g_f4_iw_ad - g_f4_offset_iw);

g_f4_iw_ad = -g_f4_iw_ad + g_f4_offset_iw;

g_u2_cnt_adjust++;

if (g_u2_cnt_adjust >= 100)

{

g_u2_cnt_adjust = 100;

}

}

g_f4_iv_ad = - (g_f4_iu_ad + g_f4_iw_ad); // V 相电流

g_f4_vdc_ad = g_f4_vdc_ad * MTR_VDC_SCALING; // Vdc

/*============================*/

/* 检查误差 */

/*============================*/

mtr_error_check();

/*====================================*/

/* 速度和角度计量 */

/*====================================*/

mtr_angle_speed();

/*=============================================================*/

/* 坐标变换(UVW -> αβ ->dq) */

/*=============================================================*/

f4_temp0 = cosf(g_f4_angle_rad) * g_f4_iu_ad;

f4_temp1 = cosf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_iv_ad;

f4_temp2 = cosf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_iw_ad;

g_f4_id_lpf = MTR_SQRT_2_3 * (f4_temp0 + f4_temp1 + f4_temp2);

f4_temp0 = sinf(g_f4_angle_rad) * g_f4_iu_ad;

f4_temp1 = sinf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_iv_ad;

f4_temp2 = sinf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_iw_ad;

g_f4_iq_lpf = MTR_SQRT_2_3 * (f4_temp0 + f4_temp1 + f4_temp2);

g_f4_iq_lpf = -g_f4_iq_lpf;

/*============================*/

/* 电流 PI 控制 */

/*============================*/

/* d-axis */

vd.f4_diff = g_f4_id_ref - g_f4_id_lpf;

vd.f4_kp = g_f4_kp_id;

vd.f4_ki = g_f4_ki_id;

vd.f4_limit = g_f4_lim_vd;

vd.f4_ilimit = g_f4_ilim_vd;

g_f4_vd_ref = mtr_pi_ctrl( &vd );

/* q-axis */

vq.f4_diff = g_f4_iq_ref - g_f4_iq_lpf;

vq.f4_kp = g_f4_kp_iq;

vq.f4_ki = g_f4_ki_iq;

vq.f4_limit = g_f4_lim_vq;

vq.f4_ilimit = g_f4_ilim_vq;

g_f4_vq_ref = mtr_pi_ctrl( &vq );

/*============================*/

/* 解耦控制 */

/*============================*/

f4_temp0 = MTR_LQ * g_f4_iq_lpf; // Lq*iq

f4_temp0 = g_f4_ref_speed_rad * f4_temp0; // w*Lq*iq

g_f4_vd_ref = g_f4_vd_ref - f4_temp0; // -w*Lq*iq

f4_temp0 = MTR_LD * g_f4_id_lpf; // Ld*id

f4_temp0 = f4_temp0 + MTR_M; // Ld*id+Ke

f4_temp0 = g_f4_ref_speed_rad * f4_temp0; // w*(Ld*id+Ke)

g_f4_vq_ref = g_f4_vq_ref + f4_temp0; // +w*(Ld*id+Ke)

/* 坐标变换(dq -> UVW) */

/*================================================*/

f4_temp0 = cosf(g_f4_angle_rad) * g_f4_vd_ref;

f4_temp1 = sinf(g_f4_angle_rad) * g_f4_vq_ref;

g_f4_refu = MTR_SQRT_2_3 * (f4_temp0 - f4_temp1);

f4_temp0 = cosf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_vd_ref;

f4_temp1 = sinf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_vq_ref;

g_f4_refv = MTR_SQRT_2_3 * (f4_temp0 - f4_temp1);

f4_temp0 = cosf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_vd_ref;

f4_temp1 = sinf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_vq_ref;

g_f4_refw = MTR_SQRT_2_3 * (f4_temp0 - f4_temp1);

if (g_f4_refu < -g_f4_inv_limit)

{

g_f4_refu = -g_f4_inv_limit;

}

else if (g_f4_refu > g_f4_inv_limit)

{

g_f4_refu = g_f4_inv_limit;

}

else

{ }

if (g_f4_refv < -g_f4_inv_limit)

{

g_f4_refv = -g_f4_inv_limit;

}

else if (g_f4_refv > g_f4_inv_limit)

{

g_f4_refv = g_f4_inv_limit;

}

else

{ }

if (g_f4_refw < -g_f4_inv_limit)

{

g_f4_refw = -g_f4_inv_limit;

}

else if (g_f4_refw > g_f4_inv_limit)

{

g_f4_refw = g_f4_inv_limit;

}

else

{ }

/*==============================*/

/* PWM 参考值设定 */

/*==============================*/

mtr_inv_set_uvw(g_f4_refu, g_f4_refv, g_f4_refw, g_f4_vdc_ad);

mtr_clear_mtu4_fl ag();

}

void mtr_get_iuiwvdc(volatile fl oat32 *f4_iu_ad,

volatile fl oat32 *f4_iw_ad, volatile fl oat32 *f4_vdc_ad)

{

XXXXXXXXXXXXXXXXXXXST = 1; // 开始转换

while (XXXXXXXXXXXXXXXXXXXST == 1);

*f4_iu_ad = (fl oat32)XXXXXXXXXDR0A;

*f4_iw_ad = (fl oat32)XXXXXXXXXDR1;

*f4_vdc_ad = (fl oat32)XXXXXXXXXDR2;

}

void mtr_inv_set_uvw(fl oat32 f4_u, fl oat32 f4_v, fl oat32 f4_w, fl oat32 f4_vdc)

{

fl oat32 f4_temp0, f4_temp1;

f4_temp0 = (fl oat32)(MTR_HALF_CARRIER_SET);

f4_temp1 = (f4_vdc / 2);

f4_u = -f4_u;

XXXXXXXRD = (uint16)(((f4_temp0 * f4_u) / f4_temp1) + f4_temp0);

// set U 相占空比设定

f4_v = -f4_v;

XXXXXXXRC = (uint16)(((f4_temp0 * f4_v) / f4_temp1) + f4_temp0);

// set V 相占空比设定

f4_w = -f4_w;

XXXXXXXRD = (uint16)(((f4_temp0 * f4_w) / f4_temp1) + f4_temp0);

// set W 相占空比设定

}

void mtr_angle_speed(void)

{

fl oat32 f4_temp_d_encd_tcnt;

fl oat32 f4_temp_speed_rad;

fl oat32 f4_temp;

g_f4_encd_tcnt = mtr_get_encd_tcnt();

if (g_f4_encd_tcnt == 0)

{

g_f4_encd_tcnt = MTR_LOAD_ENCD_CNT; // 编码器 : 0 -> 0x10000 */

}

if (MTR_ENCD_FOC_MODE == g_u2_run_mode)

{

f4_temp_d_encd_tcnt = g_f4_pre_encd_tcnt - g_f4_encd_tcnt;

if (f4_temp_d_encd_tcnt < 0)

{

f4_temp_d_encd_tcnt += MTR_ENCD_CPR_MECH;

}

g_f4_d_angle_rad = ((MTR_TWOPI * f4_temp_d_encd_tcnt) / MTR_ENCD_CPR_ELE);

/* 速度 */

f4_temp_speed_rad = (g_f4_d_angle_rad / MTR_CHECK_ENCD_PERIOD);

g_f4_speed_rad += MTR_SPEED_LPF_K * (f4_temp_speed_rad - g_f4_speed_rad);

/* LPF */

/* 角度 */

f4_temp = MTR_LOAD_ENCD_CNT - g_f4_encd_tcnt;

g_f4_angle_rad = ((MTR_TWOPI * f4_temp) / MTR_ENCD_CPR_ELE); /* angle: 0 to 7*2pi [rad] */

}

else

{

/* 速度 */

g_f4_speed_rad = 0;

if (0 == g_u1_fl ag_id_open)

{

/* 角度 */

g_f4_angle_rad = 0;

}

else if (1 == g_u1_fl ag_id_open)

{

/* 角度 */

g_f4_angle_rad = MTR_HALFPI;

}

}

g_f4_pre_encd_tcnt = g_f4_encd_tcnt;

}



1

END

1



往期精彩








来自:工业技术 / 电动汽车
1
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
公众号EV技研作者1900
机友
文章
105
回复
12
学术分
0
2019/03/04注册,3年1个月前活动

EV电车技术发骚友,新能源电车技术探索,EV电车方向公众号——EV技研作者

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:北京
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}