单片机上的重力小球(esp32)
在单片机上模拟重力小球
硬件
主控: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
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
棒棒哒!