[探索] 为 Arduino 风扇添加 SG90 舵机

请注意,本文编写于 163 天前,最后修改于 1 天前,其中某些信息可能已经过时。

起因是想为风扇添加一个摇头的功能,虽然有大佬跟我说了“没必要”“有别的方法”,但我还是不想浪费了配件里的 SG90 舵机而且他的确可以转起来不是吗?为什么不让我试试呢?搜来的代码感觉都没什么用,于是自己翻了翻别的资料。
昨天晚上开电脑试了试初代版本的草图代码,很好,上传了一波后舵机成功抽风似的回到角度为0处然后不动了!连原本的风扇都转不起来了,现在把代码注释了一段一段的找错误。

看了下网上流传的和书上的基本模板类似这样:

#include <Servo.h>    // 引用舵机库
Servo myservo;        // 定义舵机对象
int djangle;          // 定义舵机角度
 
void setup() {
  myservo.attach(3);  // 定义舵机引脚为第 3 号引脚
  myservo.write(0);   // 舵机角度归零
  delay(1000);        // 设定一定延时等待舵机转动停止
}
 
void loop() {
  // 用 for 循环控制舵机来回转动
  for (djangle = 0; djangle <= 180; djangle += 1) {
    myservo.write(djangle);
    delay(15);
  }  
  for (djangle = 180; djangle >= 0; djangle -= 1) {
    myservo.write(djangle);
    delay(15);
  }
}

然后关于控制舵机转动与停止的话,我的想法是定义一个变量 djstate 表示舵机状态,赋值为 1 时开始转动,赋值为 0 时停止转动。大概…像这样吧:

int djstate=0;
while(djstate==1) {
  for (djangle = 0; djangle <= 180; djangle += 1) {
    myservo.write(djangle);
    delay(15);
  }  
  for (djangle = 180; djangle >= 0; djangle -= 1) {
    myservo.write(djangle);
    delay(15);
  }
}

这个代码……当舵机在任意角度停下来后就没办法处理了好像。待我再看看循环语句再来 hhhhh

此代码运行本来是在 Arduino 运行的 loop() 函数中不断循环,实现舵机角度不断增加,赋值为 0 后先增加至 180 度,之后执行第二个 for() 循环减至 0 度。仅仅通过加一个变量控制似乎并不可行。

然后在之前处理红外信号的函数 irSignalProcess() 里添加情况:

swith(value) {
  case 0xFFE21D:
    // 只有风扇转动时才可以开始摇头
    if(fanspeed != 0){
      djstate = 1;
    }
    break;
  case 0xFFA25D:
    djstate = 0;
    break;
}

虽然按照这个思路我添加到原来的代码中看起来好像很好的样子,但是这破风扇就就出错了…我估计又是定时器冲突什么的问题,因为之前搜索红外信号处理的问题是就看到有的帖子说 Servo.h 库和别的库有冲突来着。当时没留意,现在两行泪…


上课学循环控制,老师讲的练习 emmm... 不如来写舵机控制的代码,刚好老师都讲完循环了。开工:

int djstate=0;         // 舵机状态,1 时开启转动,0 时关闭转动
int djdirection=1;     // 舵机摆动方向,1 时顺时针,2 时逆时针
int djangle;           // 舵机角度
int anglelast;         // 舵机角度,当舵机关闭时获取最新角度存储
int directjudge;       // 舵机转动方向判断用变量,当舵机角度达到临界值时改变 djdirection 来改变舵机转动方向
 
// 当舵机状态为 1 时执行循环
while(djstate==1)
{
        // 顺时针转动
        if(djdirection==1)
        {
            for(djangle=anglelast;djangle<=135;djangle++)
            {
                yaotou.write(djangle);
                delay(20);
            }
        }
        // 逆时针转动
        if(djdirection==2)
        {
            for(djangle=anglelast;djangle>=45;djangle--)
            {
                yaotou.write(djangle);
                delay(20);
            }
        }
}

在红外信号控制的 switch 语句里添加两种情况:

switch (value)
{
    case 0xFFA25D:
        // 按下 CH- 键时停止摇头并读取舵机角度储存在  anglelast 变量里
        djstate = 0;
        anglelast = yaotou.read();
        break;
    case 0xFFE21D:
        // 按下 CH+ 键时开始摇头
        if (fanspeed != 0)
        {
            djstate = 1;
        }
        break;
}

此外要添加一个判断舵机摇头方向的代码,想法如下,让这个代码一直执行,但是不知道这样添加到 loop() 函数里会不会受到其中 delay(); 函数影响无法及时获取舵机角度。讲道理应该不会影响的,因为 loop() 整整一次循环并不会受 delay(); 影响啊!

directjudge=yaotou.read();
while(directjudge==135)
{
    djdirection=2;
}
while(directjudge==45)
{
    djdirection=1;
}

想用 for(;;) 语句来着,后来想想觉得不妥,怕程序在循环里转晕了。事实证明的确如此,代码并不能起到判断转动方向的作用,而且两个 for() 初值和判断条件似乎都不合理,但我也不知道到底还有什么其他写法了。


以上代码不仅鸡肋,而且经过实际测试还并没卵用哈哈哈哈哈,等时间再试别的…改了一晚上我也不知道有什么不对,总感觉:这不是我的错,这锅我不背啊哼哼(ノ=Д=)ノ┻━┻
大佬还在旁边笑,我反正是笑不出来哦,我的眼泪在眼眶里转…
 
咳咳,想了想这个是不是需要来一手多进程的设计?
看到了 Arduino 的 Scoop 库可以用。这样一来的话就可以整俩进程,一个为原先那种控制红外和按键开关的,另一个为控制舵机运行的。这样会不会就不相干扰了。但是我看不懂库里的函数,(ΘへΘ)…想要一个符合条件时启动进程的效果,但是 Scoop 库好像就是开局多进程,不清楚到底怎么写,库的示例里也没有能实现类似功能的代码。试了一下 Scoop.h ,感觉并没有什么用,而且在定义多进程时变量的全局非全局和库的引用太麻烦了搞不懂,最后编译就直接卡住了。放弃。
回到最初的想法又试了试一些方法。可是发现机械结构上可能也有问题,目前我是这样安装的:

舵机摇头风扇
舵机摇头风扇

由于没有 3D 打印加持,也没找到舵机上支架的替代品我就直接把马达暴力安装在舵机旋臂(我这样叫那个直接固定在舵机上的白色的东西大家没意见吧)上了。在百度文库我也看到了类似这样的安装方法:

百度文库某方案安装图
百度文库某方案安装图

原先我没注意,清明放假我再次测试时发现了一个现象:带动风扇扇叶转动的电机运行时持续微小震动,舵机不得不被迫抖动,然后产生了持续不断的不明红外信号,在计算机串口监视器中读取到持续的红外信号,这直接导致原先设定好的红外遥控按键无法解码。我又试了试删除舵机摇头相关的代码,在只有扇叶电机运行时用手拨动舵机(舵机通电后位置固定,不会像没通电时那样可以随意转动),结果不出意料,舵机一抖动计算机串口监视就接收到不明红外信号。我觉得可能是舵机内部的电机就随着抖动产生了对红外传感严重干扰的红外信号,这样红外遥控就失效了。因为 IRremote.h 对红外信号的解码只能一个一个排队来,原来设定好好的控制风扇的红外信号排不上号不能及时处理,解码的流程全部被舵机引起的干扰信号占用了。
目前来看我对这个问题是没什么别的解决思路了,因为关于不引用Servo.h 库手动 PWM 脉冲调节舵机的代码看来也救不了因为马达震动带来的干扰红外信号产生的问题啊?
最后一种想法来自电子发烧友的博文,用一个马达+设计机械结构解决摇头问题,不过看起来结构好麻烦,不理解 ,暂时鸽了

电子发烧友摇头风扇结构
电子发烧友摇头风扇结构

 
 
 
仔细的考虑了一下,电机+舵机+红外控制这本应该是一个很简单的任务,为什么到我手上就变得麻烦了呢?究其根本必然是对程序和算法的理解不够深入。
周五晚我又测试了一番,舵机和电机一同运行是完全没有问题的(未引用红外库,未测试红外接收情况),并不是电源降压等问题引起的。改过几次代码后发生错误,所以问题还是程序结构有问题,但是我现在还真是不知道这到底该用什么结构来写了。

 

会继续更新…不会鸽的,一定不会的…
最近真是烦到原地托马斯螺旋升天高空爆炸啊,专业专业不让我选我预选的哔我重选,英语英语 5 分的破口语给个二点几就是不让我及格,选修选修本来就很水的课哔我动手画装配图,公开课公开课我就特喵的报了一门课还被抽签狗屎运把我踢出去了(^・ェ・^),这破学校就是跟我做对哔我退学是吧?


目前思路

  • <Scoop.h> 多进程库 测试不成功
  • attachInterrupt(interrupt, function, mode); 中断函数

整理了一篇新的文章,有了一点点新想法,如果你愿意再花时间去看的话请点这里:《[假装新篇] 再探 红外+舵机+电机

添加新评论

已有 9 条评论

MonsterX MonsterX 回复 @免费节点

2333 菜哭了

虽然不知道说的是什么,但看起来好厉害的样子!

MonsterX MonsterX 回复 @你的灵兽看起来很好吃

:aru121: 嘿嘿嘿,你的相机看起来也挺好吃哦!

MonsterX MonsterX 回复 @Doratree

:aru16: 我又卡壳了…有一点晕

Doratree Doratree 回复 @MonsterX

慢慢来咯

MonsterX MonsterX 回复 @Doratree

明明感觉很简单的事情到我手上就变得好麻烦了。哎,学的不精可真要命啊。

i i 回复 @MonsterX

加油 没人一开始就什么都会