U729328 开摆!(附加题)
题目背景
2026 赛季,队长看完比赛录像后拍板:我们要做轮腿平衡步兵。
理由很充分:普通步兵能过台阶吗?不能。能原地起跳躲弹吗?不能。别人家的轮腿在赛场上蹦跶得像个战神,我们家的步兵还在为一块 15° 的坡道写特殊判断。
于是机械组开始画五连杆,硬件组开始挑关节电机,而电控组面对的第一个问题就是——这玩意儿的控制核心,本质上就是一个倒立摆。
轮子往前滚,身子往后倒;轮子往后退,身子往前栽。陀螺仪的数据在串口屏上疯狂跳动,像极了你第一次调平衡车时的表情。LQR 的 Q 阵和 R 阵调了一版又一版,MATLAB 里的仿真曲线优美如画,一上实物车当场表演”滑铲入墙”。
队长深思熟虑后做出决定:新人在把倒立摆立起来之前,谁都不许碰真车。
“连一根杆都立不住,还想立一台二十公斤的车?”
现在,轮到你了。评测机里跑着一台简化的一阶倒立摆仿真——没有地滑,没有电机齿隙,没有 CAN 总线掉线,没有学长在旁边喊”让我看看”。这是最理想的环境,也是你成为电控组正式成员的第一道门槛。
立住它。然后去立那台真正的车。
你需要编写程序控制一个小车上的倒立摆,使其尽可能长时间保持不倒。
小车在一维轨道上运动,车上通过光滑铰链连接一根均质摆杆。每个控制周期你可以对小车施加一个水平方向的力 F,你需要根据当前状态决定 F 的大小。
g 重力加速度 9.8 m/s²
M 小车质量 1.0 kg
m 摆杆质量 0.1 kg
l 摆杆质心到转轴距离(半长) 0.5 m
Δt 控制周期 0.02 s
F_max 最大控制力 10.0 N
x_lim 小车位移上限 2.4 m
θ_lim 摆角上限 12°
T_max 最大步数 5000
题目描述
初始状态 x = 0,ẋ = 0,θ̇ = 0,θ 在 [−6°, 6°] 内由测试点种子随机生成。
失败条件 任一条件满足立即结束:
|θ| > θ_lim
|x| > x_lim
输出的 F 不是有限实数,或 |F| > F_max
交互协议
评测端与选手程序通过标准输入输出交互,每次输出后都必须刷新缓冲区。
重复以下过程:
评测端输出一行:x vx theta vtheta(4 个保留 6 位小数的实数)
选手读入该行,输出一行一个实数 F(施加的控制力)
评测端读入 F,积分一步
结束时,评测端输出一行:E steps(steps 为成功维持的步数),然后关闭。
每个测试点满分 10 分,维持 5000 步得满分,按步数线性给分。
输入格式
一行4个数,通过空格隔开
x vx theta vtheta
分别表示当前倒立摆的位置、速度、角度、角速度
输出格式
输出一行一个实数 F,表示施加的控制力
输入输出样例 #1
输入 #1
(无)
输出 #1
(无)
说明/提示
输入输出示例:
#include <iomanip>
#include <iostream>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
double x, vx, theta, vtheta;
// 从评测端输入一轮状态。
while (std::cin >> x >> vx >> theta >> vtheta) {
// 这里只演示输出,不根据输入计算结果。
// 每轮固定输出 0,并立即刷新,保证交互继续进行。
std::cout << std::fixed << std::setprecision(10)
<< 0.0 << std::endl;
}
return 0;
}