在esp32上实现一个重力小球

此篇文章在2022年1月28日被记录


硬件

主控:esp32
屏幕:ILI9341
重力传感器:MPU6050

软件

屏幕驱动:#include <TFT_eSPI.h>
MPU6050驱动:#include <MPU6050_tockn.h>

要求

可以实现屏幕上的小球跟随实际重力运行,并且具有释放回收区域,可以通过按键实现小球的增加与减少;

程序设计

  • 使用链表新建小球:
     typedef struct Balls
    {
      int location_ball[2];//小球的位置
      int last_location_ball[2];//小球上次的位置
      float speed_ball[2];//小球的速度
      float stress_ball;//小球的弹性系数
      int color_ball;//小球的颜色
      int radius_ball;//小球的半径
      struct Balls *next;//下一个小球的数据
    }ball;
  • 创建小球并初始化(赋予初始位置速度等):
    ball *creat_ball(int n)//创建小球,输入参数为个数,返回值为第一个小球的内存地址
    {
      ball *head, *node, *end;
      head = (ball*)malloc(sizeof(ball));
      end = head;
      for (int i = 0; i < n; i++)
      {
        node = (ball*)malloc(sizeof(ball));
        //----------------------//
        //ball_set_val(node); //设置初始值
        node->location_ball[0] = random(50, 100);
        node->location_ball[1] = random(50, 100);
        node->last_location_ball[0] = 0;
        node->last_location_ball[1] = 0;
        node->speed_ball[0] = random(0, 30);
        node->speed_ball[1] = random(0, 30);
        node->stress_ball = (float)((float)random(40, 60) / 100);
        node->color_ball = random(0, 65535);
        node->radius_ball = random(8, 16);
        //---------------------//
        end->next = node;
        end = node;
      }
      end->next = NULL;
      return head;
    }
  • 获取重力:
        void Grav_prc(void)//直接获得加速度,获得的加速度直接乘以10才等于实际重力
        {
          mpu6050.update();
          gx = mpu6050.getAccX() * 10;
          gy = mpu6050.getAccY() * 10;
        }

  • 小球运动过程处理:
    在这个过程中主要做了这些事情:根据高中物理可得:加速度积分获得速度,速度积分得到位置,然后对边缘碰撞进行检测,如果碰撞到了垃圾桶,重新对这个小球赋值,完成这些后指针移动到下一个小球。还需要一些延时,不然移动的太快。
    void Ball_prc(ball *list)
    {
        ball  *ball=list;
        while (ball->next != NULL)
        {
          ball->speed_ball[0]+=gx;//对加速度积分得到速度
          ball->speed_ball[1]+=gy;
    
          ball->location_ball[0]+=ball->speed_ball[0];//对速度积分得到位置
          ball->location_ball[1]+=ball->speed_ball[1];
    
          if(ball->location_ball[0]<0+ball->radius_ball)//碰到最左边
          {
            ball->location_ball[0]=0+ball->radius_ball;
            ball->speed_ball[0]=-(ball->speed_ball[0]*ball->stress_ball);//速度=负的速度乘以弹性系数,模拟弹力衰减
          }
          if(ball->location_ball[0]>MAX_X-ball->radius_ball)//碰到最右边
          {
            ball->location_ball[0]=MAX_X-ball->radius_ball;
            ball->speed_ball[0]=-(ball->speed_ball[0]*ball->stress_ball);//速度=负的速度乘以弹性系数,模拟弹力衰减
          }
          if(ball->location_ball[1]<0+ball->radius_ball)//碰到最上边
          {
            ball->location_ball[1]=0+ball->radius_ball;
            ball->speed_ball[1]=-(ball->speed_ball[1]*ball->stress_ball);//速度=负的速度乘以弹性系数,模拟弹力衰减
          }
          if(ball->location_ball[1]>MAX_Y-ball->radius_ball)//碰到最下边
          {
            ball->location_ball[1]=MAX_Y-ball->radius_ball;
            ball->speed_ball[1]=-(ball->speed_ball[1]*ball->stress_ball);//速度=负的速度乘以弹性系数,模拟弹力衰减
          }
    
          if((ball->location_ball[0]>MAX_X-logoWidth)&&(ball->location_ball[1]>MAX_Y-logoHeight))//碰到垃圾桶回收
          {
                  tft.fillCircle(ball->location_ball[0],ball->location_ball[1],ball->radius_ball,COLOR_BK);
                  tft.fillCircle(ball->last_location_ball[0],ball->last_location_ball[1],ball->radius_ball,COLOR_BK);
                  ball->location_ball[0] = random(50, 100);
                  ball->location_ball[1] = random(50, 100);
                  ball->last_location_ball[0] = 0;
                  ball->last_location_ball[1] = 0;
                  ball->speed_ball[0] = random(0, 30);
                  ball->speed_ball[1] = random(0, 30);
                  ball->stress_ball = (float)((float)random(40, 60) / 100);
                  ball->color_ball = random(0, 65535);
                  ball->radius_ball = random(8, 16);
                  
            
            
            }
          tft.fillCircle(ball->last_location_ball[0],ball->last_location_ball[1],ball->radius_ball,COLOR_BK);
          tft.fillCircle(ball->location_ball[0],ball->location_ball[1],ball->radius_ball,ball->color_ball);
    
          ball->last_location_ball[0]=ball->location_ball[0];
          ball->last_location_ball[1]=ball->location_ball[1];
          
          ball = ball->next;//切换到下一个小球
            //Serial.println(ball->radius_ball);
        }
          tft.drawXBitmap(0, 0, shoot, logoWidth, logoHeight, TFT_WHITE);
          tft.drawXBitmap(MAX_X-logoWidth, MAX_Y-logoHeight, laji, logoWidth, logoHeight, TFT_WHITE);
      
    }
  • 增删小球
    使用链表中常用的增加与删除方式,代码就不贴出来了。

演示视频:

posted @ 2024-12-06 16:31  shumei52  阅读(71)  评论(0)    收藏  举报