打印
[DemoCode下载]

用Arduino制作简易磁悬浮装置

[复制链接]
6265|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
史迪威将军|  楼主 | 2015-8-7 09:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
刚做好的一个下推式磁悬浮装置~需要的外围东西很少,用arduino uno控制,l298n驱动四个线圈电磁铁,配合霍尔传感器就能悬浮了。


首先介绍一下原理,其实很简单,磁力对悬浮物的控制,其基本原理是:霍尔传感器在浮子的正下方,当检测到浮子向左运动时,两边的线圈一个吸一个拉,把它推向右;反之如果浮子想右运动,那么两个线圈的电流都反向,总共两组共四个这样的线圈,就可以把浮子限制在二维平面之内了。但是线圈产生的力是比较小的,因此只能够推动浮子在水平面移动,要克服浮子的重力让它悬浮起来,就要在四个线圈下面再加一个大的环形磁铁提供斥力。
大家应该玩过这中磁悬浮玩具

原理差不多,它下面其实就是一个大的磁铁提供斥力,但是浮子放上去是不稳定的,所以这种玩具需要借助陀螺高速旋转产生的陀螺仪效应维持平衡。而我们这个装置不需要浮子旋转,放上去就能悬浮,对浮子的限制是靠线圈调节的。
我们这个装置主要用到的东西有
1.arduino主控板
2.线圈
3.大磁铁
4.霍尔传感器
顺便解释一下霍尔传感器。。。这是一种测量磁场强度的元件,可以把通过它垂直面的磁力线强度转化为不同的电压值,这样我们用单片机ADC读取之后就可以得到浮子的位置信息了。霍尔传感器的安装位置很有讲究,前面说了它是测量通过其垂直面的磁力线,也就是浮子发出的磁力线,而我们电磁线圈在调节的同时磁力线也在变,如果这个变化被霍尔感应到了结果就很不可靠了,所以霍尔的安装位置应该是位于四个线圈的中间高度,这里的磁力线刚好是与霍尔平行,不产生影响。


用前后左右共四个线圈,两个霍尔传感器配合,就可以把浮子稳定的悬浮住。
为了让悬浮更加稳定,我们采用了PID控制的平衡算法,对PID算法的了解有助于我们对整个实验原理的理解,借用网上对PID的一段介绍:在工程实际中,PID控制是应用最为广泛的调节器控制机制。PID控制中得P代表比例,即proportion;I代表积分,即integral;D代表微分,即differential;因此,PID控制,即比例-积分-微分控制。当被控对象的结构和参数不能完全掌握,或者得不到精确的数学模型时,其他的控制方法难以采用,那么控制器的结构和参数必须结合经验和现场调试来决定,在这种情况下采用PID调节最为方便。首先,比例控制是一种最简单的控制方式,就像胡克公式中的比例系数一样,当控制器的输出与输入信号成比例关系,那么就可以得到一个比例系数。其次,积分控制是指控制器的输出与输入的误差信号的积分有关。就如同电路中的电感元件,某个时刻的电压与电流的积分有关。类似的,有时候信号的输出必须综合之前信号的输入,而这种综合往往是求和关系,因此使用积分控制简单易行。最后,微分控制是指控制器的输出与输入信号的微分有关。最简单的微分关系就是速度是位矢的微分。我们在控制悬浮物的平衡时,光知道悬浮物偏离平衡位置的位移从而采用比例控制是不够的,对于同样的偏离位移,悬浮物可能有不同的速度,那么要求我们对悬浮物有不同的处理方法,而恰恰速度是位矢的微分,于是我们可以通过对位移输入数据进行微分操作,来实现对悬浮物的精确实时控制。可见,PID控制器是一种那个动态的控制机制。 以上就是实现下推式磁悬浮的基本原理,借助以上的基本原理,结合一定的软件算法实现,我们就可以对悬浮物进行动态控制。
看不懂的可以不管那些废话...总之就是我们把霍尔元件度数也就是浮子的位置作为输入变量输入PID函数,设定一个目标值也就是浮子在中间位置时的读数值,然后把输出赋值给PWM驱动线圈,剩下的就是调整PID参数让它自己控制浮子去啦。
接下来是电路

这个其实电路并不复杂,回复中有人给了电路图了,这里再发一个简化一点的

这是L298N和线圈连接的方式,arduino和l298n的连接大家应该比较熟悉了,网上也有很多例程,大家把我代码里的相关引脚改成你连接的脚就行了,霍尔用analogRead()读取,PID有arduino的相关库。
霍尔元件一般需要放大电路放大,但是考虑到对一些初学者比较复杂,大家可以考虑直接到网上买那种线性霍尔元件模块,内置放大的直接接到arduino上就能用,注意一定要线性的!还有一种是开关式的只能输出0和1两个值,我们需要的是输出模拟电压的模块。
接下来是线圈,这个东西买不到,得自己绕制,去网上买一大卷漆包线就可以了,用支架自己绕上2,3百圈基本就够用。。。

这是我绕的样子


这里有三个霍尔,额外的一个用于检测是否放置了浮子的。
这是加上大磁铁之后的样子
三层板。。。

供电电源大家自己想办法,只用arduino的5v电压是肯定不够的,线圈要产生足够的磁力需要更大一点的电压电流,我使用的是电脑显示器的电源适配器,最大有12v4A,大家可以自己去网上找找相关的电源适配器,应该不难买的。
暂时就想到这么多,大家还有什么不懂的再问吧。


沙发
史迪威将军|  楼主 | 2015-8-7 09:11 | 只看该作者
程序源代码
#include <PID_v1.h>

#include <LCD5110_CN.h>

#define IN1 4

#define IN2 3

#define IN3 8

#define IN4 7

#define ENA 6

#define ENB 5

#define BL 2

LCD5110 myGLCD(9,10,11,13,12);

extern uint8_t SmallFont[];

extern uint8_t MediumNumbers[];

extern uint8_t BigNumbers[];

double Setpoint_X, Input_X, Output_X,X_plus;

double p_X = 1,i_X = 0,d_X = 0.01;

double Setpoint_Y, Input_Y, Output_Y,Y_plus;

double p_Y = 1,i_Y = 0,d_Y = 0.01;

int i,on_put;

unsigned long time;

PID PID_X(&Input_X, &Output_X, &Setpoint_X,p_X,i_X,d_X, DIRECT);

PID PID_Y(&Input_Y, &Output_Y, &Setpoint_Y,p_Y,i_Y,d_Y, DIRECT);

char inByte='9',nullByte,run_flag,run_dirict;

float go_step;

void turn_X(int a)

{

if(a>=0)

{

digitalWrite(IN1,1);

digitalWrite(IN2,0);

analogWrite(ENA,a);

}

else

{

a=-a;

digitalWrite(IN1,0);

digitalWrite(IN2,1);

analogWrite(ENA,a);

}

}

void turn_Y(int a)

{

if(a>=0)

{

digitalWrite(IN3,0);

digitalWrite(IN4,1);

analogWrite(ENB,a);

}

else

{

a=-a;

digitalWrite(IN3,1);

digitalWrite(IN4,0);

analogWrite(ENB,a);

}

}

void setup()

{

myGLCD.InitLCD();

myGLCD.setFont(BigNumbers);

pinMode(IN1,OUTPUT);

pinMode(IN2,OUTPUT);

pinMode(IN3,OUTPUT);

pinMode(IN4,OUTPUT);

pinMode(ENA,OUTPUT);

pinMode(ENB,OUTPUT);

pinMode(BL,OUTPUT);

digitalWrite(IN1,0);

digitalWrite(IN2,0);

digitalWrite(IN3,0);

digitalWrite(IN4,0);

analogWrite(ENA,0);

analogWrite(ENB,0);

Serial.begin(115200);

Setpoint_X = 560;//560;

Setpoint_Y = 560;//560;

PID_X.SetTunings(p_X,i_X,d_X);

PID_Y.SetTunings(p_Y,i_Y,d_Y);

PID_X.SetOutputLimits(-255,255);

PID_Y.SetOutputLimits(-255,255);

PID_X.SetSampleTime(5);

PID_Y.SetSampleTime(5);

PID_X.SetMode(AUTOMATIC);

PID_Y.SetMode(AUTOMATIC);

}

void loop()

{

while (Serial.available() > 0)

{

nullByte= char(Serial.read());

if(nullByte == 'w')

{

Setpoint_X+=10;

//inByte =Serial.read();

}

else if(nullByte == 'q')

{

Setpoint_X-=10;

}

else if(nullByte == 's')

{

Setpoint_Y+=10;

}

else if(nullByte == 'a')

{

Setpoint_Y-=10;

}

else if(nullByte == 'o')

{

run_flag=!run_flag;

run_dirict = 1;

Setpoint_X=560;

Setpoint_Y=560;

}

else if(nullByte =='p')

{

run_flag=!run_flag;

run_dirict = 0;

Setpoint_X=560;

Setpoint_Y=560;

}

else if(nullByte =='x')

{

nullByte=char(Serial.read());

if(nullByte>20)

{inByte=nullByte;

Setpoint_X = 10*(inByte-'0')+480;

}

nullByte=char(Serial.read());

if(nullByte>20)

{inByte=nullByte;

Setpoint_Y = 10*(inByte-'0')+480;

}

}

if(Setpoint_X>575)

Setpoint_X=575;

if(Setpoint_Y>575)

Setpoint_Y=575;

if(Setpoint_X<480)

Setpoint_X=480;

if(Setpoint_Y<480)

Setpoint_Y=480;

nullByte ='?';

}

Input_X = analogRead(A1);

Input_Y = analogRead(A0);

if(analogRead(A2)<450)

{

digitalWrite(BL,1);

on_put=1;

}

else

{

digitalWrite(BL,0);

on_put=0;

}

i++;

/*if(i==500)

{

Serial.print(inByte);

Serial.print(",");

Serial.println(Setpoint_Y);

}*/

if(i==1000)

{

myGLCD.printNumI(Setpoint_X, RIGHT, 0);

myGLCD.printNumI(Setpoint_Y, RIGHT, 24);

i=0;

}

if(on_put)

{

PID_X.Compute();

PID_Y.Compute();

turn_X(Output_X+X_plus);

turn_Y(Output_Y+Y_plus);

if(run_flag)

{

if(millis()-time>2)

{

time = millis();

if(run_dirict)

{

X_plus = 25*cos(go_step);

Y_plus = 25*sin(go_step);

}

else

{

X_plus = 25*sin(go_step);

Y_plus = 25*cos(go_step);

}

go_step+=0.07;

if(go_step>6.3)

go_step=0;

}

}

}

else

{

turn_X(0);

turn_Y(0);

}

// myGLCD.printNumI(Input_X, RIGHT, 0);

// myGLCD.printNumI(Input_Y, RIGHT, 24);

// myPID.SetTunings(kp,ki,kd);

}

使用特权

评论回复
板凳
玛尼玛尼哄| | 2015-8-7 10:39 | 只看该作者
这个要学,学会了,做神奇的玩具,忽悠人用。

使用特权

评论回复
地板
大苏牙| | 2015-8-7 11:03 | 只看该作者
玛尼玛尼哄 发表于 2015-8-7 10:39
这个要学,学会了,做神奇的玩具,忽悠人用。

我觉得这个真的不是忽悠人,国外为什么arduino那么火,科技为什么那么发达,完全是由于大家爱折腾导致的

使用特权

评论回复
5
玛尼玛尼哄| | 2015-8-7 11:12 | 只看该作者
大苏牙 发表于 2015-8-7 11:03
我觉得这个真的不是忽悠人,国外为什么arduino那么火,科技为什么那么发达,完全是由于大家爱折腾导致的 ...

我的意思是学了这个本事,用这个本事忽悠那些不懂技术的。就说是魔术。

使用特权

评论回复
6
mintspring| | 2015-8-7 17:18 | 只看该作者
控制的原理和方法如果能讲清楚更好了。

使用特权

评论回复
7
598330983| | 2015-8-8 21:49 | 只看该作者
楼主这个方法还是很牛X的,玩这个,想法很重要

使用特权

评论回复
8
mintspring| | 2015-8-9 19:06 | 只看该作者
,磁力对悬浮物的控制,其基本原理是:霍尔传感器在浮子的正下方,当检测到浮子向左运动时,两边的线圈一个吸一个拉,把它推向右;反之如果浮子想右运动,那么两个线圈的电流都反向,总共两组共四个这样的线圈,就可以把浮子限制在二维平面之内了。
讲的真好

使用特权

评论回复
9
734774645| | 2015-8-9 19:29 | 只看该作者
这个是什么单片机做的啊

使用特权

评论回复
10
IversonCar| | 2015-8-9 20:17 | 只看该作者
734774645 发表于 2015-8-9 19:29
这个是什么单片机做的啊

这个有很多mcu的,开始推出的是avr单片机,后来各个厂家都推出和arduino兼容的版本了

使用特权

评论回复
11
734774645| | 2015-8-9 20:45 | 只看该作者
这个是需要芯片去主动兼容这个软件的吧?

使用特权

评论回复
12
643757107| | 2015-8-9 22:02 | 只看该作者
霍尔传感器。。。这是一种测量磁场强度的元件,可以把通过它垂直面的磁力线强度转化为不同的电压

使用特权

评论回复
13
玛尼玛尼哄| | 2015-8-9 22:30 | 只看该作者
不知道可以用新唐的单片机不

使用特权

评论回复
14
244259402| | 2015-12-21 23:12 | 只看该作者
好帖啊,好帖,怒顶啊.多少年没有见到过这样的良心帖子了

使用特权

评论回复
15
捉虫天师| | 2015-12-21 23:38 | 只看该作者
PID PID_X(&Input_X, &Output_X, &Setpoint_X,p_X,i_X,d_X, DIRECT);

PID PID_Y(&Input_Y, &Output_Y, &Setpoint_Y,p_Y,i_Y,d_Y, DIRECT);
这是PID算法吗?

使用特权

评论回复
16
梁毅| | 2016-6-6 21:17 | 只看该作者
楼主能否解释下BL干吗用的?

使用特权

评论回复
17
gejigeji521| | 2016-6-7 16:52 | 只看该作者
能再详细点就更好了,貌似懂了,又不太懂。

使用特权

评论回复
18
yiyigirl2014| | 2016-6-7 17:39 | 只看该作者
厉害,多多分享点类似的教程,让我们菜鸟好好跟着学学。

使用特权

评论回复
19
zhuomuniao110| | 2019-3-2 17:19 | 只看该作者
帅呆了,给您顶上去。

使用特权

评论回复
20
zhuomuniao110| | 2019-3-2 17:24 | 只看该作者
楼主好几年没看到了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

291

帖子

0

粉丝