在单片机上模拟重力小球

硬件
主控: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);
  
}

增删小球
使用链表中常用的增加与删除方式,代码就不贴出来了。

演示视频:

代码下载:点击 Bouncyball.rar