概述

这个项目是我大学本科四年做的最复杂的一个,从大一下学期到大三结束一路磕磕绊绊走走停停终于到了可以写总结的时候。

警告:本文设计内容具有危险性,不提供任何制造文件资料,仅供科研交流使用,装置测试后已经拆除,严禁仿造用于其他用途。

说一下我的最终设计路线和目标:

  • 高压方案(>300V)
  • 快速连续工作(<1s)
  • 速度快(>100m/s)
  • 效率有追求但不很重要(>10%)

4 LEVELS

基本参数

  • 加速体:A3材质M8x20圆柱定位销
  • 轨道:内8.5外9.5钢管
  • 电压:350V
  • 拓扑:boost
  • IGBT:IRGPS4067d
  • 线圈:0.45mm漆包铜线

Ansys Maxwell仿真

实体模型 电路模型 电流 拉力 速度

仿真工程文件

功率电路

功率板原理图 驱动板原理图 照片 效果

线圈设计参数:

实测速度基本稳定在45m/s,如果连续使用线圈发热增加的电阻率会降低电流导致速度降低,实测温度到40度时速度会降低到40左右,因此未来的设计将会关注热管理问题。

时序控制

外接自制那个esp32开发板,代码在这里,时序使用循环计算,不再需要手动考虑高低电平切换顺序了,以及做了串口调参,节省一下flash的烧录寿命hhh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//cxx: control[just a str], level, 0:duration/1:start time//2:end time

// start time
int c11_time = 0;
int c21_time = 1650;
int c31_time = 2400;
int c41_time = 2950;
// duration
int c10_time = 1460;
int c20_time = 840;
int c30_time = 670;
int c40_time = 580;

// trigger status
const int c1 = 26;
const int c2 = 27;
const int c3 = 14;
const int c4 = 12;
const int c5 = 13;
const int sw = 0;

unsigned long pulseStartTime = 0;
unsigned long pulseNowTime = 0;

String inData="";

void setup() {
Serial.begin(115200);
pinMode(c1, OUTPUT);
pinMode(c2, OUTPUT);
pinMode(c3, OUTPUT);
pinMode(c4, OUTPUT);
pinMode(c5, OUTPUT);
digitalWrite(c1, LOW);
digitalWrite(c2, LOW);
digitalWrite(c3, LOW);
digitalWrite(c4, LOW);
digitalWrite(c5, LOW);

pinMode(sw, INPUT);
}

void loop() {
// serial
while(Serial.available()>0){
delay(5);
char recieved = Serial.read();
inData += recieved;
if(recieved == '\n'){
if (inData.length()<4){
Serial.println("Too short");
break;
}
String function = inData.substring(0, 4);

if (function=="c11 "){
String value_str = inData.substring(4, inData.length());
c11_time = value_str.toInt();
Serial.printf("Now c11 = ");
Serial.println(c11_time);
}else if (function=="c10 "){
String value_str = inData.substring(4, inData.length());
c10_time = value_str.toInt();
Serial.printf("Now c10 = ");
Serial.println(c10_time);
}else if (function=="c21 "){
String value_str = inData.substring(4, inData.length());
c21_time = value_str.toInt();
Serial.printf("Now c21 = ");
Serial.println(c21_time);
}else if (function=="c20 "){
String value_str = inData.substring(4, inData.length());
c20_time = value_str.toInt();
Serial.printf("Now c20 = ");
Serial.println(c20_time);
}else if (function=="c31 "){
String value_str = inData.substring(4, inData.length());
c31_time = value_str.toInt();
Serial.printf("Now c31 = ");
Serial.println(c31_time);
}else if (function=="c30 "){
String value_str = inData.substring(4, inData.length());
c30_time = value_str.toInt();
Serial.printf("Now c30 = ");
Serial.println(c30_time);
}else if (function=="c41 "){
String value_str = inData.substring(4, inData.length());
c41_time = value_str.toInt();
Serial.printf("Now c41 = ");
Serial.println(c41_time);
}else if (function=="c40 "){
String value_str = inData.substring(4, inData.length());
c40_time = value_str.toInt();
Serial.printf("Now c40 = ");
Serial.println(c40_time);
}
inData="";
}

}

// switch
if (digitalRead(sw)==LOW){
// reset
int c11 = 1;
int c21 = 1;
int c31 = 1;
int c41 = 1;
int c12 = 1;
int c22 = 1;
int c32 = 1;
int c42 = 1;
int c12_time = c11_time + c10_time;
int c22_time = c21_time + c20_time;
int c32_time = c31_time + c30_time;
int c42_time = c41_time + c40_time;
Serial.println("starting");
pulseStartTime = micros();
pulseNowTime = micros();
while(c11||c12||c21||c22||c31||c32||c41||c42){
pulseNowTime = micros();
if(pulseNowTime-pulseStartTime>c11_time && c11){
digitalWrite(c1, HIGH);
c11 = 0;}
if(pulseNowTime-pulseStartTime>c12_time && c12){
digitalWrite(c1, LOW);
c12 = 0;}

if(pulseNowTime-pulseStartTime>c21_time && c21){
digitalWrite(c2, HIGH);
c21 = 0;}
if(pulseNowTime-pulseStartTime>c22_time && c22){
digitalWrite(c2, LOW);
c22 = 0;}

if(pulseNowTime-pulseStartTime>c31_time && c31){
digitalWrite(c3, HIGH);
c31 = 0;}
if(pulseNowTime-pulseStartTime>c32_time && c32){
digitalWrite(c3, LOW);
c32 = 0;}

if(pulseNowTime-pulseStartTime>c41_time && c41){
digitalWrite(c4, HIGH);
c41 = 0;}
if(pulseNowTime-pulseStartTime>c42_time && c42){
digitalWrite(c4, LOW);
c42 = 0;}

if(pulseNowTime-pulseStartTime>1000000){
Serial.print("ERROR, time out");
break;
}
}
Serial.println("releasing");

digitalWrite(c5, HIGH);
delay(2000);
digitalWrite(c5, LOW);
Serial.println("finished");
}
}

ZVS升压电源

电源有多种方案,最简单的ZVS谐振逆变升压,十分简单但是不够可控可靠,无法控制工作状态,而且在负载过流情况下一旦停止谐振就会直接在电源上短路,如果使用电池供电十分危险,不过只要重新接入电源重新进入谐振状态就可以继续正常工作。另一种使用开关电路逆变升压,较为复杂但是可控。当然我们的需求是给电容充电,使用恒流源更合适,具体实现参考论文《一种谐振型推挽式直流变换器》

不知道为什么这个电路被称为ZVS(零电压开关)电路,这只是一个恰好工作在零电压开关状态的谐振电路,不过这个名称和电路十分经典广为流传和使用,甚至淘宝所售套件的电源全都是这个方案,而且也足够简单,非常容易做

洞洞板试验 输入 波形 输出
原理图 3D模型 照片

缺失模型的元件是电感和变压器。电感一定要电流足够大,分享一下我的电感和变压器选型吧

电感 现在用的电容 打算以后换的电容

这个电路的问题我也说过了,就是一旦过载停振就会短路,所以我在前面加了一个PMos控制电源开关,短路可以及时关闭和重启。

n*5 LEVELS

电路设计

这次采用了模块化设计,每个板子是5级功率回路,可以直接串联使用

放电电路 驱动电路 供电主板

线圈设计参数:

时序控制

控制程序

考虑到esp32引脚数量不足,主控芯片更换为stm32。以及这次可以进行电压测量和充电电流监控并主动控制,加入了这部分控制代码

1

电磁运动仿真计算

maxwell计算结果和coilgun RLC基本一致,但是出现了一些新的问题,由于线圈电流的巨大变化率,会在相邻线圈产生感生电流,可能导致IGBT过压击穿,因此本来计划做15级破百,由于11-15级匝数更少电流更大产生的感生电流过大,因此打算只做10级,速度只能达到70-80。解决这个问题需要改成多路boost,需要重新设计PCB,所以等下一版本再说吧

经过计算发现,最佳的开启和关断位置是固定的,这一次仿真已经是完全由位置触发得到的了,效果非常好,甚至可以用于估算代码设置的延迟时间

运动参数 线圈电流 电容电压

但是线圈电流仿真结果显示线圈匝数的设计还有优化空间,关断时的电流过大,降低了效率和IGBT可靠性

Maxwell仿真文件

设计优化

对于线圈,首先应该用较大的匝数进行初始的加速,然后随着速度增加,线圈导通的时间越来越短,因此需要减少电感量来提高响应速度,即减少匝数。因此后级最佳的匝数应逐级减少。

当IGBT关断时,线圈的电流应该已经过了峰值,并且降低的足够低,这样可以降低电容剩余电压,提高加速度。因此可以根据关断时的电流值确定合适的匝数。如果刚过峰值就关断,就减少线圈的匝数。应该比较好的关断时机是电流峰值的2/3到1/2

当速度达到接近100时,由于匝数很小可能导致电感过小电流过大,此时可以降低电容容量,降低峰值电流避免IGBT出现故障

对于磁阻结构,能量的损耗在于电阻发热和磁场加速损耗,线圈使用更大的线径可以降低电阻,进一步提高效率。实际制造中,更粗的线圈会极大提高手工绕制难度,因此我自己的方案仍然使用0.45mm直径

线圈直径越大,在缝隙处的损耗就会占比更小,因此拥有更高的效率,我也因此把定位销尺寸从m6改为m8。为了减少缝隙的磁场损耗,缝隙处从1mm厚度的abs和1mm厚度线轴改为0.5mm的不锈钢缠绕高温胶带绝缘。减少缝隙可以极大提高效率。

根据其他人的实验,AUIRGPS4067D的峰值电流在驱动电压正20负5时,520V560uf100uh大概每隔30s放电一次,800A450us关断,极限测试了50次没有问题。不过保守使用3-500A应该不会有问题

推挽升压电源

这种方案使用芯片产生的指定频率的互补的PWM波形控制MOS推挽升压,至少不会停振短路了。我用的是SG3525产生信号然后UCC27324驱动MOS,经过变压器升压,整流后输出高压直流。为了及时关断,使用单片机采集电压控制开关

全桥恒流谐振

直接上论文:

特别感谢

科创网
JLC
QQX