盗梦陀螺攻略3- 上拉式磁悬浮

有了磁悬浮陀螺的念头,我没有直接开始做下推式,而是先做一个上拉式的练练手。这件事的经历说明:对一个新手来说,可以采用由浅入深,先易后难的策略;虽然总时间可能会更长一点,但是对增强信心,掌握经验很有帮助。(好吧,水木的Joker们看到这句话一定会想歪,色情猥琐男们请自觉面壁)

上拉式磁悬浮原理相当简单。先用万能的乐高颗粒搭一个架子,把绕好的线圈固定在上面。然后用钕铁硼强磁做一个浮子。小窍门来了,我们在线圈的上方放置一个大磁铁,一开始浮子会被吸在线圈下方,慢慢的向上抬大磁铁,到一定高度时,浮子吸不住了向下落。记住这个位置,把大磁铁固定在那里。这样的效果是:线圈里只要通一点电流,就可以吸住浮子,电流一断浮子就会下落。

线圈和浮子的安装

线圈和浮子的安装

图中的浮子下面有个白色的东西,其实那不是什么秘诀,只是我用来标示上下的记号。大磁铁下面有好几个乐高齿轮,其实那都是调节高度用的,之所以用齿轮而不是用圆片倒是有原因的,因为我觉得比较酷 :D

电路方面,上拉式磁悬浮只需要一个传感器,但是我还是焊了双路的板子,这样和将来的下推式用同一块就可以。电路图还没时间学习怎么画,先用画笔凑合弄了个原理图,里面省略了一些细节,不过应该能看明白了。

上拉式磁悬浮原理图

上拉式磁悬浮原理图

请注意我的电路中用了两个电位器。其中电位器1是多圈电位器,作用是调节传感器输出范围。3503很灵敏,电流被放大以后,很容易就超出0到5V的测量范围,所以在需要一个精密的电位器,让输出范围尽量在5V以内。电位器2是用来调节浮子位置的,它是我们设置的“目标位置”。Arduino开发板的作用,就是调整线圈电流大小,从而控制浮子上下移动,最终让传感器的读数等于我们设定的目标值。实物的接线图请看:

接线图,貌似不太清楚

接线图,貌似不太清楚

这个可能大点

这个可能大点

代码就非常简单了,所有的代码只有下面这几行:

int readPin = 2;    //用来连接输入
int i1Pin = 36;     //连接电机驱动板的I1接口
int i2Pin = 37;     //连接电机驱动板的I2接口
int powerPin = 8;   //连接电机驱动板的EA接口
int adjustPin = 6;

boolean flag = true;
int power = 0;
int readValue = 0;
int adjustValue = 0;

void GetPowerValue()
{
  power = readValue - adjustValue;
  if(power < 0) power = 0;
  if(power > 50) power = 50;
  power = power * 16 / 10;
}

void setup()
{
  pinMode(i1Pin, OUTPUT);     //I1和I2都是数字信号
  pinMode(i2Pin, OUTPUT);     //通过设置I1和I2来控制电流方向
  pinMode(powerPin, OUTPUT);  //按占空比方式输出的模拟信号
  digitalWrite(i1Pin, !flag);
  digitalWrite(i2Pin, flag);
  //Serial.begin(9600);          //设置波特率
}

void loop()
{
  //读取电位器和传感器的读数
  readValue = analogRead(readPin);
  //传感器的电压范围是220~580,所以调节电位器的范围可以稍作调整
  adjustValue = analogRead(adjustPin) / 3 + 220;
  GetPowerValue();
  //Serial.println(readValue);
  //Serial.println(adjustValue);
  //Serial.println(power);

  analogWrite(powerPin, power);
  //delay(2000);
  //delay(1);
}

代码虽然简单,但是在制作的过程中却走了很多弯路。这段代码的重点在于:
power = power * 16 / 10;

这个相当于是调整线圈电流的放大倍数,参数1.6如果小了则吸不住浮子,大了则无法稳定。程序中的16如果换成15或者17都不行的。因为这么一个小小的问题,我走了一星期的弯路。当时怀疑原理不对,在反复检查无果之后,已经跟圈妈提出放弃这个项目。幸好这时候得到了圈圈妈“严厉”的鼓励:遇到这么点困难就打退堂鼓,以后怎么做大事!从另一个角度说,当你想尽办法几乎绝望的时候,其实已经接近成功了,因为你已经排除了大部分错误。

果然第二天就解决了问题!后来在制作下推式的时候,类似的事情又一次发生,那次主要问题在于线圈绕的不行,而重做线圈是一个非常浩大的工程,同样也是在圈妈的鼓励下,终于下决心重新做一遍。在此向顽强的圈妈表示敬意(圈妈表示鸭梨不大,反正她不出力干活^_^ )

这个实验最终的经验总结如下:
1,参数很重要!如果你的磁悬浮上下跳动的厉害,恭喜你,其实你已经接近成功了。
2,这个试验中的参数有效范围非常窄,跟程序也有关系,后面会介绍一种PID算法,可以扩大范围,更容易调节。
3,坚持,太累的时候放松一下,然后换个思路想想。

视频如下:



对 “盗梦陀螺攻略3- 上拉式磁悬浮” 的 109 条 评论

  1. jlzhou 说:

    做一个磁悬浮轨道小火车吧,环形的,能高速转圈的。

  2. dead_lee 说:

    生命在於折騰啊

  3. darko 说:

    长期围观的不明真相群众表示持续支持中~

  4. hefanghua 说:

    盗梦陀螺做得很好。没想到这么快就由“科幻”转到现实了,呵呵。强烈支持!

  5. 李宙恒 说:

    有一个问题 电位器1 是连载LM358的哪个管脚上了啊?

  6. vvisper 说:

    问一个巨弱智无比的问题 那种插在杜邦头上 都粘在一起的导线叫什么导线呀 我觉得这比单根的要整洁清晰多了 买的时候买什么样的

  7. wlreg 说:

    请教一下:
    ————————————————-
    //读取电位器和传感器的读数
    readValue = analogRead(readPin);
    //传感器的电压范围是220~580,所以调节电位器的范围可以稍作调整
    adjustValue = analogRead(adjustPin) / 3 + 220;
    GetPowerValue();
    ————————————————–
    这里传感器的电压范围是怎样得出来的呢?那个adjustValue的范围的调整的表达式是可以换的吧?如果换成其他的,power的表达式也要跟着换就可以了吧?
    问题可能有点弱智……希望见谅啊。过几天开发板就送到了,想在动手之前把没有看懂的地方都弄懂的说

    • 啊,不好意思,这个没说清楚。
      220~580是我在板子上量的,adjustPin的目的,是让它恰好等于传感器平衡时的读数。
      而传感器在最初已经调解到400左右(因为它的电压满额是3.7V,相当于模拟输入的740,我把它调到差不多400,这样左右变动的裕度比较大)
      因为温飘等原因,实际上可能会上下浮动一些,我量过的最大误差达到180,所以就有了这么个220~580
      而ajustPin的读数可以是0~1023,如果用它直接去匹配这个400左右的数比较浪费精度
      除以3以后相当于提高了精度,本来你轻轻拧一下,读数会变15,现在只会变5

  8. DIY新手 说:

    我是一个高中生,看起来不算难,不知道能不能做出来…动力男孩能帮帮我吗?

    • 调试的时候可能会花不少时间,所以请根据你的学习进度合理安排。有问题可以在这里留言,之前也有其他一些朋友的讨论,可以参考一下 :)

      • DIY新手 说:

        真的是灰常灰常感谢……现在放假,过些日子开工……这些知识大学里的老师能给我讲通吗?我对这方面的知识了解的不多…害怕耽误你工作,所以想找个大学的老师详细讲解…

        • 不知道你们现在有没有编程的课,做磁悬浮需要的知识不算复杂,但是需要一些编程 :)
          大学老师应该没问题

          • DIY新人 说:

            有点编程的基础知识,用VB编过二次函数图像和1+2+3……100的小程序,用的是开源代码……你已经给了源代码,我想编程不成问题…我先仔细看看,有不懂的我就留言…谢谢~

  9. 一颗原子 说:

    那个控制板用这个可以吗?
    http://item.taobao.com/item.htm?id=12767340993

    • 一颗原子 说:

      还有 STC单片机 是干什么的?
      我看好多上拉式用到了这个

    • 应该可以,这个应该是那种简化板,标准版可以直接把线插入针孔里测试用,这种板就必须焊上了。但是它也很有优势,体积小,价格便宜,小心使用的话没有问题

  10. 在天愿做747 说:

    您好,我有一个问题。
    3503检测的磁场变化主要是由于浮子位置移动而产生的还是线圈电流变化产生的?
    是不是浮子位置移动了,3503检测到浮子位置移动产生的磁场变化,然后通过算法去控制线圈的电流大小,使得线圈产生的磁场变化从而使浮子回归原位,完成对浮子位置的控制?

  11. riddler 说:

    请问您能指导我一下吗?我正在做上拉式的,但是一直没成功。qq好就是我的邮箱

  12. 摸金校尉 说:

    我想搞一个可以载物的,要怎么做呢?

  13. 小马 说:

    if(power 50) power = 50;
    我是个初学者,请问这两句是什么意思啊?

  14. 小灰灰 说:

    亲 那个PID 算法

  15. XANA 说:

    最近一直在围观 ,找了个ARDUINO 的PID v1 库试着改写,不知有没有用
    /********************************************************
    * PID Adaptive Tuning Example
    * One of the benefits of the PID library is that you can
    * change the tuning parameters at any time. this can be
    * helpful if we want the controller to be agressive at some
    * times, and conservative at others. in the example below
    * we set the controller to use Conservative Tuning Parameters
    * when we’re near setpoint and more agressive Tuning
    * Parameters when we’re farther away.
    ********************************************************/

    #include
    int i1Pin=12; // 电机
    int i2Pin=13; // 电机
    int h2Pin=A2; //霍尔元件2
    int c1Pin=9; //PWM 输出 连接电机驱动板的EA接口
    int readValue2;
    //Define Variables we’ll be connecting to
    double Setpoint, Input, Output;

    //Define the aggressive and conservative Tuning Parameters
    double aggKp=4, aggKi=0.2, aggKd=1;
    double consKp=0.1, consKi=0.05, consKd=0.25;

    //Specify the links and initial tuning parameters
    PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);

    void setup()
    {
    //initialize the variables we’re linked to
    readValue2 = analogRead(h2Pin);
    Input = analogRead(A2);
    Setpoint = 45;

    //turn the PID on
    myPID.SetMode(AUTOMATIC);
    pinMode(i1Pin,OUTPUT);
    pinMode(i2Pin,OUTPUT);
    Serial.begin(9600);
    }

    void loop()
    {
    int readValue2 = 0;
    for(int i = 0; i >= 2;
    Input = readValue2;
    double gap = abs(Setpoint-Input); //distance away from setpoint
    if(gap<10)
    { //we're close to setpoint, use conservative tuning parameters
    myPID.SetTunings(consKp, consKi, consKd);
    }
    else
    {
    //we're far from setpoint, use aggressive tuning parameters
    myPID.SetTunings(aggKp, aggKi, aggKd);
    }

    myPID.Compute();
    digitalWrite(i1Pin,HIGH);
    digitalWrite(i2Pin,LOW);
    analogWrite(c1Pin,Output);
    Serial.print(Input);
    Serial.print(",");
    Serial.print(Output);
    Serial.print(",");
    Serial.print(consKp);// close to setpoint
    Serial.print(",");
    Serial.print(consKi);
    Serial.print(",");
    Serial.print(consKd);
    Serial.print("\n");
    delay (1000);
    }

    但是参数设置很坑爹

  16. CCT116 说:

    你好 电阻 100K和2K这4个分别接在哪?

  17. owo 说:

    动力哥,上拉式的线圈他的直径和圈数大概是多少

  18. 物理狂人 说:

    顺便再问下那个
    圆环形黑磁铁 145*80*20 1个
    钕铁硼强磁 D15*4mm D30*2mm D31.7*19.1*3.2mm
    分别装在原理图的哪个位置啊?,在实物图上我看到原理图上“大磁铁”的位置装的应该是铝铁硼强磁吧,难道是我眼花?还有那个浮子明明是两个一样的磁铁啊,你清单上却用了三种型号的磁铁。哎总而言之,那个大磁铁和铝铁硼磁是怎么回事。指点下呗,老男孩老师

  19. owo 说:

    你好
    if(power 50) power = 50;
    power = power * 16 / 10;
    想问一下,50 和16 是代表什么物理量? 功率? 当初是为什么知道要设这数值?
    谢谢

    • 不是有特殊含义的物理量,是通过试验试出来的“工程量”
      其中50是用来限制最大值,不然会震动的很厉害,16也是调出来的比例值

  20. 物理狂人 说:

    老男孩,做上拉式要一个线圈就够了吗?你那八百匝我不好买哎,可以说你用了多少克或斤吗?

    • 一个就够了,线圈这个事情不用太纠结,我也没真正数过,线圈也是随意找了一个。
      关键在后期的程序调节,磁力不够就加大电流

  21. hl 说:

    我有个问题想请教你一下,希望能指导一下。
    我的上拉式磁悬浮其中power = power * 16 / 10;当power=15时,线圈吸不住浮子,当power=16时可以吸住浮子。但是只要浮子离开线圈5-6毫米时就吸不住掉了下了。我感觉我的线圈变成了磁铁,通电后浮子贴着线圈就会被吸住,离开一点线圈就会掉下了。不知道是什么原因。只会吸住或掉下来。我没有加线圈上的大磁铁(我们在线圈的上方放置一个大磁铁,一开始浮子会被吸在线圈下方,慢慢的向上抬大磁铁,到一定高度时,浮子吸不住了向下落。)

  22. 高志伟 说:

    请问用stc51单片机可以带动吗,我用51做了一个,硬件都ok了,但是程序好像不能用,我用tip122当驱动芯片的,悬浮物会大浮动摆动,很快就掉了,不是吸上去就是掉下来

  23. 王琦哲 说:

    请问,你的笔记本电源适配器是怎样和7809引脚接在一起的?(实际操作上)

  24. 高志伟 说:

    我电路和程序又改了下,还是不能用,想知道你脉冲频率多大的

  25. 高志伟 说:

    我加了个铁心来增加磁性,另外我想问下你线圈电流大概多大啊

    • 哈哈,不能加铁芯啊,我的博客里特地强调了。
      频率大概50Hz就够了,电流相对会比较大,至少要1A以上吧。
      因为你是绕的双层的线圈,相比之下每个线圈可能电阻都比较小,电流估计会更大

  26. 高志伟 说:

    可以通过这么大电流啊,应该会发热吧,我用0.6的线圈电流通过1a多就会发热了,我还是从新绕线圈吧,去掉铁心,铁心会导致电流输出延迟啊,,,,在试一次,不行估计要放弃了,已近调了一周多了

    • 铜丝有点儿粗了,你可能需要用0.25左右的铜丝,另外你的线圈其实是两个绕组吧?相当于电阻只有一半,所以就更热了。
      电流不会一直保持在1A以上的,它调节到平衡位置之后,电流其实不大。
      磁铁本来悬浮在那里,恰好重力和吸引力是平衡的,线圈的电流是用来平衡微小的扰动 :)

  27. 高志伟 说:

    想问下,悬浮的那个位置 是自然情况下(线圈不通电)的平衡点吗?还是在平衡点下方?

      • 高志伟 说:

        我用的是8位ad转换,精度不是很高,平衡点不太好找啊

        • 8位应该也够了,但是不知道你的霍尔放大倍数是多少,也就是说变化的灵敏度是多少?

          • 高志伟 说:

            直接测霍尔元件的输出电压应该在零点几伏到四点几,经过运放放大后ad的数字在3~180左右,这个范围可以小范围调的,按目前的说,我的平衡点应该在111~112(ad转换的数据)之间,但是我程序没有用到浮点数,只用到整数,今天试了好多组数据都不稳定,不知道跟这个平衡点又没关系。我程序也是用你那种的简单的比例算法

          • 你的霍尔输出电压这么高?有经过放大电路吗?

          • 高志伟 说:

            没有啊 用的是44e型号,我现在问题是在参数上吗,方法应该没有出错吧

          • 不知道啊,我的霍尔输出电压非常小,需要经过放大器才能读出

  28. 高志伟 说:

    参数设置不行,你ad采集的数据有进行滤波吗,采集多次然后取平均值之类

    • 霍尔干扰很小,没有滤波。
      但是有个细节需要注意,我的霍尔传感器是放在浮子的正下方,所以线圈对它的影响很小,基本上可以客观的反映浮子距离

      • 高志伟 说:

        把程序和硬件都改了下,没成功,你那个视频悬浮物可以上下调的,那应该悬浮物是放在自然平衡点下方的,我目前用的程序控制的电流是单方向的,没有改变电流方向,离开那个平衡点往下掉的时候给脉冲,其他时候不给脉冲。这样不是掉了就是吸到上方,无法平衡。我准备改下程序,试试可以改变电流方向的方法

  29. 物理狂人 说:

    老男孩,你可以告诉我一下放大器358N接的几个角分别是哪几个脚吗?万分感谢

  30. 磁悬浮 说:

    analogWrite(powerPin, power); 这句应该是pwm使能298吧?

    那后面这段又是什么意思啊 什么是模拟信号?
    void setup()
    {
    pinMode(i1Pin, OUTPUT); //I1和I2都是数字信号
    pinMode(i2Pin, OUTPUT); //通过设置I1和I2来控制电流方向
    pinMode(powerPin, OUTPUT); //按占空比方式输出的模拟信号
    digitalWrite(i1Pin, !flag);
    digitalWrite(i2Pin, flag);
    //Serial.begin(9600); //设置波特率
    }

    急用啊

    • analogWrite不是输出某个电压值的模拟量,而是用PWM输出的占空比。
      以5V电压为例,模拟输出50%是指输出2.5V的电压,而PWM的输出是一半0,一半5V,高速切换

  31. 磁悬浮 说:

    void setup()
    {
    pinMode(i1Pin, OUTPUT); //I1和I2都是数字信号
    pinMode(i2Pin, OUTPUT); //通过设置I1和I2来控制电流方向
    pinMode(powerPin, OUTPUT); //按占空比方式输出的模拟信号
    digitalWrite(i1Pin, !flag);
    digitalWrite(i2Pin, flag);
    //Serial.begin(9600); //设置波特率
    }

    这段代码是控制电流方向的吗,这段看不懂,您用到双向电流吗?太靠近线圈就推,原理就拉

  32. iamzzy015 说:

    问下EA,E1,E2是什么口,out1? in1? enb?

  33. 陈凯恩 说:

    请问您的上拉式磁悬浮可以悬浮多长时间,我的只能3,4分钟

  34. iamzzy015 说:

    LM358怎么接的?需要接其他的电阻吗?怎么接上去之后,arduino板电源灯就灭了,还发烫

  35. zoooonm 说:

    老男孩你好,我想问下为什么我按着原理图接线之后,查A2的电压一直是1023,也就是5V呢?把传感器拔掉还是一直显示1023。我把原理图上的100K换成10K, 4.7K换成了1K,是不是电阻的问题?LM358的接线我也查过- -感觉不是那里的问题

    • zoooonm 说:

      是不是接线以后要调节多圈电位器,然后使A2的读数为400??我现在接LM358,接两边的放大读数是不一样的,一边1000,一边150多,但调节多圈电位器读数都没有变化。。。。但是我把磁铁靠近霍尔传感器,读数会变化,这是唯一值得欣慰的- -。。。

      • zoooonm 说:

        好吧原来是接线的问题- -现在接线貌似没问题了,但我不是很明白你的代码是怎么实现调节电位器2,浮子会上下动?老男孩老师可以解释一下吗?

        • 哈哈,那个不是上下动,可能是镜头的问题吧,应该是水平的移动
          比如你调到中点是400,那么陀螺就会在读数400的地方平衡,如果你调到600,陀螺就会移动到600的地方平衡

      • 奇怪,调电位器的目的是让读数尽量靠近中点,比如400~600都没问题。
        1000的话很麻烦,因为最大值才1024,也就是说你向上偏移一点儿之后就无法识别了

    • 应该不会,估计还是你电路哪里出了问题。
      或者是中点没调节好,你可以量量传感器的输出是多少

  36. 一休哥 说:

    老男孩你好,我一开始用了红外来测量浮子的高度,数据不稳所以放弃了。想问问你上拉式线圈也是用你那个清单里面的那个骨架么?我绕了个10欧的线圈,跳的根本稳不住…..想问问你上拉的线圈的电阻是多少。

  37. Rocky 说:

    您好,请问一下电源适配器怎么连到L298N上呢,您是用什么接口转换了一下么

  38. Rocky 说:

    您好,请问线圈的电流应该多大,为什么我做的感受不到线圈的磁力?

  39. Rocky 说:

    已经有磁性了

  40. Rocky 说:

    请问3503的感应距离有多远,我们的返回值没太大变化。power在25左右就突然吸不上是怎么回事?

  41. 张红坤 说:

    我在程序中为什么没有看见PID运算过程,用的是位置是式的PID还是增量式的PID啊。

    • DaisyHUnter 说:

      晕,power = power * 16 / 10; 这个就是PID运算啊。先是根据power = readValue – adjustValue;都到的传感器电压值减去我们的可调电压(电位器)值得到一个应输出电压,然后按照调试过后的16/10,即1.6倍对电压按比例放大的到一个准确的运行电压,这个按比例放大的过程就是PID运算的一种,我猜你没看PID资料→-→http://www.arduino.cn/thread-12813-1-1.html

  42. DaisyHUnter 说:

    你好,我想请教一下,电阻在放大电路中的重要性,初学Arduino,不是很理解为何要在放大电路上放置滑动电阻之外的定额电阻

  43. DaisyHUnter 说:

    老男孩,我正在zu做这个,但是遇到了一点麻烦,根据电路图焊的传感器会出现数值不稳定的状态,一开始电位器调整到400左右时,突然就飙到峰值750,或者是0,电位器灵敏度变得非常高,就算调到400左右,波动也会10个单位之间摆动,这个让我感觉无从下手。我没有用你做的用来调节浮子高度的电位器,请问这个很关键吗?恳请回答我的问题,已经苦恼了好几天了,每当我准备确认某悬浮位置的传感器电压值时,电压值总会飙,求教

  44. DaisyHUnter 说:

    还有当我把两个传感器呈平面直角排列焊在板子上,也算是为底座磁悬浮做准备,但是同一高度两个传感器的的数值图像呈不同方向变化,一个正增长,一个呈下降,求解缘由。

  45. DaisyHUnter 说:

    老男孩是弃坑了么。。。

  46. Vincent 说:

    请问这个上拉式磁悬浮用的是几毫米的漆包线?

  47. 666 说:

    是是是

  48. 777LUCK 说:

    线圈匝数重要么?

  49. 西芹五花肉 说:

    不仅分享经验,还鼓励我们这些后辈,真是值得学习尊敬的前辈!!!

  50. 西芹五花肉 说:

    您好,前辈,这种上拉式的现在可以分享一下电路图吗?非常感谢

发表评论

可以使用下列 XHTML 标签:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>