③ 蜘蛛机械人—模型分析与开发
1 安装驱动
1.1 安装 PL2303 驱动程序
执行驱动程序安装之前,请不要将主板和电脑的 USB 连接,待安装结束后,请将电脑重启
1.2 若正确安装,会在菜单 Tools->Serial ports 中多处一个 COM Port
1.3 将主板和电脑通过 USB 连接后,编译上传程序
若无软硬件错误,下方就会出现烧录信息。烧录时会有小数点”…”表示进度。烧录结束后会告诉你上传成功。
2 导入工程文件
2.1 可以直接下载bin文件
直接下载bin文件可以不用做其他东西,直接使用了。
2.2 机器人热点 Robot-J mini -_*_
密码12345678
2.3 控制界面
192.168.4.1
3 蜘蛛型四足机器人运动分析
一般来说,在考虑四足机器人运动控制时,我们会分析其运动学/动力学模型,基于运动速度、步态和足端轨迹等去计算关节角度或关节力矩。普通模拟舵机只能控制输出角度,对于普通模拟舵机驱动的迷你四足,我们对他的最大速度、负载、精度等指标并不过多关注,让其按照预设状态动起来即可,因此我们简单分析其一个周期内的运动状态。步态可以说是整个设计中最复杂的部分之一了,刚开始构思项目是打算做成单步行走的(一次只动一条腿),然后把效果做出来之后觉得实在不太行,程序顺序执行且舵机一次只能做一组点对点的僵硬动作,而且做不到奔跑的动作(虽然最终也没有实现),所以就放弃了这个方案。最终想到了现在的解决方案:使用操作系统,把每一条腿分离成单独的任务,每个任务只执行自己动作的部分,利用任务并发实现整个移动姿势的动作周期。把四个任务设置成一样的优先级,使用时间片轮转调度,以达到同步的效果。
3.1 “Trot步态”
trot步态是四足中最常见且应用较广的步态,它的特征有对角一致、两组相差半周;即对角线上的两个腿为一组,同组内腿运动步调一致;两组腿运动状态相差半个周期;此处参考trot步态来简单分析蜘蛛型小四足的运动;
首先我们需要知道,不管是人还是动物,在前进时运动主要分抬腿、往前迈两个动作,因此我们一条腿安装两个驱动舵机:一个用来抬腿、一个用来迈腿(可以简单理解为这样)。当然一个符合四足动物特征能完成前进、转弯、翻滚等动作的四足机器人单腿一般有三个自由度,此处简化结构、并且蜘蛛型结构两个驱动舵机即可实现大部分功能;
下面我们来考虑一个前进运动周期内,一条腿的运动状态都有哪些;
很自然的可以想到,一个舵机驱动腿抬起来、再放下去,另一个舵机驱动腿往前迈;这时候我们需要注意到,第一组腿(例如左前+右后)往前迈(摆动)的时候,第二组腿(右前+左后)需要支撑在地面上;同样第二组腿开始往前迈(摆动)的时候,第一组腿需要处于支撑状态;
也就是说,每条腿在一个前进运动周期内,都有两个状态:摆动 + 支撑;
下面我们再来分析,在摆动、支撑两个阶段内,单条腿中的两个驱动舵机都应该如何转动;
首先是用来迈腿的舵机(可称之为髋关节舵机):
从图1可以看出,一个周期内:摆动阶段,髋骨节舵机转动,往前迈腿;支撑阶段,髋关节舵机反向转动,将机器人身体前移;
接着是抬腿的舵机(可称之为膝关节舵机):
从图2可以看出,一个周期内:摆动阶段,膝关节抬起再放下;支撑阶段,膝关节舵机保持;
以上对腿部两个舵机角度的分析只是示意,考虑到不同足端轨迹对运动稳定性的影响,关节驱动角度变化也会相对多样;
接着将一条腿的舵机控制,映射到另外三条腿,然后让两组腿运动状态相差半个周期,即可实现四足的前进、旋转;
注意前进状态中,髋关节转动方向,同侧腿相同、异侧腿相反(例如第一组中,左前方髋关节先顺时针、后逆时针;而右后方髋关节,先逆时针、再顺时针);旋转状态中,髋关节转动方向,四条腿皆相同;膝关节运动状态皆相同(不同组相差半个周期)。
3.2 运动分析
起->“抬起前移”、落->“前移放下”、前->“放下后移”、后->“后移抬起”
通过测试机械人的平衡性和协调性的时候,发现并不能保持平衡,因此必须要同一时刻至少有三条腿接触地面才能不导致重心便宜。解决方法是把腿在地面接触的“放下后移”这个动作姿势给分成两个部分,延长这条腿呆在地面的时间,这样总体的总做时间就变成了5个动作单位,具体看下图:
3.3 扩展
后面可以根据自己需要,添加mpu6050陀螺仪,可以采集到三轴的角度信息,用它实现了一个稳定模式的功能,通过采集俯仰角和横滚角,利用四条腿计算偏移进行调整,使其在一个不稳定的平面上保持水平。
4 把源代码导入Arduino软件
4.1 编程的时候舵机接口
---- ----
| 00 | | 03 |
---- -------- ----
| 01 02 |
| |
| 14 13 |
---- -------- ----
| 15 | | 12 |
---- ----
4.2 代码解析
4.2.1 参数定义与头文件
#include <Servo.h> //舵机头文件
#include <EEPROM.h> //EEPROM存储
#include <ESP8266WiFi.h> //8266 WIFI头文件
#include <ESP8266WebServer.h> //8266 WIFI头文件
#include <Adafruit_PWMServoDriver.h> //PWM
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// Firmware version
String FW_Version = "Robot-J mini - Quadruped Robot v1.5 (Designed by August)";
// Servos matrix
const int ALLMATRIX = 9; // 舵机驱动IO
const int ALLSERVOS = 8; // 舵机驱动IO
// MG90S servo PWM pulse traveling
const int PWMRES_Min = 1; // PWM Resolution 1
const int PWMRES_Max = 180; // PWM Resolution 180
const int SERVOMIN = 150;
const int SERVOMAX = 600;
int servo_id;
// Servo delay base time
const int BASEDELAYTIME = 10; // 10 ms
// AP password
const char WiFiAPPSK[] = "12345678";
// Motion data index
int Servo_PROGRAM;
// Backup servo value
int Running_Servo_POS [ALLMATRIX];
ESP8266WebServer server(80);
const int Servo_Map[ALLSERVOS] = {3, 2, 13, 12, 0, 1, 14, 15};
// Action
// --------------------------------------------------------------------------------
// Servo zero position 零位置
// ----------------------------- , ms
int Servo_Act_0 [ ] PROGMEM = { 135, 45, 135, 45, 45, 135, 45, 135, 500 };
// Start position 起始位置
// ----------------------------- ms
int Servo_Act_1 [ ] PROGMEM = { 135, 45, 135, 45, 45, 135, 45, 135, 500 };
4.2.2 机械人动作函数—通过数组去驱动舵机
// Standby 待機
int Servo_Prg_1_Step = 2;
int Servo_Prg_1 [][ALLMATRIX] PROGMEM = {
// , ms
{ 90, 90, 90, 90, 90, 90, 90, 90, 500 }, // servo center point
{ 70, 90, 90, 110, 110, 90, 90, 70, 500 }, // standby
};
// Forward 前行
int Servo_Prg_2_Step = 11;
int Servo_Prg_2 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // standby
{ 90, 90, 90, 110, 110, 90, 45, 90, 200 }, // leg1,4 up; leg4 fw
{ 70, 90, 90, 110, 110, 90, 45, 70, 200 }, // leg1,4 dn
{ 70, 90, 90, 90, 90, 90, 45, 70, 200 }, // leg2,3 up
{ 70, 45, 135, 90, 90, 90, 90, 70, 200 }, // leg1,4 bk; leg2 fw
{ 70, 45, 135, 110, 110, 90, 90, 70, 200 }, // leg2,3 dn
{ 90, 90, 135, 110, 110, 90, 90, 90, 200 }, // leg1,4 up; leg1 fw
{ 90, 90, 90, 110, 110, 135, 90, 90, 200 }, // leg2,3 bk
{ 70, 90, 90, 110, 110, 135, 90, 70, 200 }, // leg1,4 dn
{ 70, 90, 90, 110, 90, 135, 90, 70, 200 }, // leg3 up
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // leg3 fw dn
};
// Backward 退後
int Servo_Prg_3_Step = 11;
int Servo_Prg_3 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // standby
{ 90, 45, 90, 110, 110, 90, 90, 90, 200 }, // leg4,1 up; leg1 fw
{ 70, 45, 90, 110, 110, 90, 90, 70, 200 }, // leg4,1 dn
{ 70, 45, 90, 90, 90, 90, 90, 70, 200 }, // leg3,2 up
{ 70, 90, 90, 90, 90, 135, 45, 70, 200 }, // leg4,1 bk; leg3 fw
{ 70, 90, 90, 110, 110, 135, 45, 70, 200 }, // leg3,2 dn
{ 90, 90, 90, 110, 110, 135, 90, 90, 200 }, // leg4,1 up; leg4 fw
{ 90, 90, 135, 110, 110, 90, 90, 90, 200 }, // leg3,1 bk
{ 70, 90, 135, 110, 110, 90, 90, 70, 200 }, // leg4,1 dn
{ 70, 90, 135, 90, 110, 90, 90, 70, 200 }, // leg2 up
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // leg2 fw dn
};
// Left shift 左移
int Servo_Prg_4_Step = 11;
int Servo_Prg_4 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // standby
{ 70, 90, 45, 90, 90, 90, 90, 70, 200 }, // leg3,2 up; leg2 fw
{ 70, 90, 45, 110, 110, 90, 90, 70, 200 }, // leg3,2 dn
{ 90, 90, 45, 110, 110, 90, 90, 90, 200 }, // leg1,4 up
{ 90, 135, 90, 110, 110, 45, 90, 90, 200 }, // leg3,2 bk; leg1 fw
{ 70, 135, 90, 110, 110, 45, 90, 70, 200 }, // leg1,4 dn
{ 70, 135, 90, 90, 90, 90, 90, 70, 200 }, // leg3,2 up; leg3 fw
{ 70, 90, 90, 90, 90, 90, 135, 70, 200 }, // leg1,4 bk
{ 70, 90, 90, 110, 110, 90, 135, 70, 200 }, // leg3,2 dn
{ 70, 90, 90, 110, 110, 90, 135, 90, 200 }, // leg4 up
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // leg4 fw dn
};
// Right shift 右移
int Servo_Prg_5_Step = 11;
int Servo_Prg_5 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // standby
{ 70, 90, 90, 90, 90, 45, 90, 70, 200 }, // leg2,3 up; leg3 fw
{ 70, 90, 90, 110, 110, 45, 90, 70, 200 }, // leg2,3 dn
{ 90, 90, 90, 110, 110, 45, 90, 90, 200 }, // leg4,1 up
{ 90, 90, 45, 110, 110, 90, 135, 90, 200 }, // leg2,3 bk; leg4 fw
{ 70, 90, 45, 110, 110, 90, 135, 70, 200 }, // leg4,1 dn
{ 70, 90, 90, 90, 90, 90, 135, 70, 200 }, // leg2,3 up; leg2 fw
{ 70, 135, 90, 90, 90, 90, 90, 70, 200 }, // leg4,1 bk
{ 70, 135, 90, 110, 110, 90, 90, 70, 200 }, // leg2,3 dn
{ 90, 135, 90, 110, 110, 90, 90, 70, 200 }, // leg1 up
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // leg1 fw dn
};
// Turn left 左轉leg
int Servo_Prg_6_Step = 8;
int Servo_Prg_6 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // standby
{ 90, 90, 90, 110, 110, 90, 90, 90, 200 }, // leg1,4 up
{ 90, 135, 90, 110, 110, 90, 135, 90, 200 }, // leg1,4 turn
{ 70, 135, 90, 110, 110, 90, 135, 70, 200 }, // leg1,4 dn
{ 70, 135, 90, 90, 90, 90, 135, 70, 200 }, // leg2,3 up
{ 70, 135, 135, 90, 90, 135, 135, 70, 200 }, // leg2,3 turn
{ 70, 135, 135, 110, 110, 135, 135, 70, 200 }, // leg2,3 dn
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // leg1,2,3,4 turn
};
// Turn right 右轉
int Servo_Prg_7_Step = 8;
int Servo_Prg_7 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // standby
{ 70, 90, 90, 90, 90, 90, 90, 70, 200 }, // leg2,3 up
{ 70, 90, 45, 90, 90, 45, 90, 70, 200 }, // leg2,3 turn
{ 70, 90, 45, 110, 110, 45, 90, 70, 200 }, // leg2,3 dn
{ 90, 90, 45, 110, 110, 45, 90, 90, 200 }, // leg1,4 up
{ 90, 45, 45, 110, 110, 45, 45, 90, 200 }, // leg1,4 turn
{ 70, 45, 45, 110, 110, 45, 45, 70, 200 }, // leg1,4 dn
{ 70, 90, 90, 110, 110, 90, 90, 70, 200 }, // leg1,2,3,4 turn
};
// Lie 趴地
int Servo_Prg_8_Step = 1;
int Servo_Prg_8 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 110, 90, 90, 70, 70, 90, 90, 110, 500 }, // leg1,4 up
};
// Say Hi 打招呼
int Servo_Prg_9_Step = 7;
int Servo_Prg_9 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 90, 90, 90, 90, 90, 400}, // leg2,3,4 dn
{ 170, 90, 90, 90, 90, 90, 90, 90, 400}, // leg1 up
{ 170, 130, 90, 90, 90, 90, 90, 90, 400}, // leg1 left
{ 170, 50, 90, 90, 90, 90, 90, 90, 400}, // leg1 right
{ 170, 130, 90, 90, 90, 90, 90, 90, 400}, // leg1 left
{ 170, 90, 90, 90, 90, 90, 90, 90, 400}, // leg1 right
{ 70, 90, 90, 90, 90, 90, 90, 90, 400}, // leg1 dn
};
// Fighting 戰鬥姿態
int Servo_Prg_10_Step = 11;
int Servo_Prg_10 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 120, 90, 90, 110, 60, 90, 90, 70, 500 }, // leg1, 2 down
{ 120, 70, 70, 110, 60, 70, 70, 70, 500 }, // body turn left
{ 120, 110, 110, 110, 60, 110, 110, 70, 500 }, // body turn right
{ 120, 70, 70, 110, 60, 70, 70, 70, 500 }, // body turn left
{ 120, 110, 110, 110, 60, 110, 110, 70, 500 }, // body turn right
{ 70, 90, 90, 70, 110, 90, 90, 110, 500 }, // leg1, 2 up ; leg3, 4 down
{ 70, 70, 70, 70, 110, 70, 70, 110, 500 }, // body turn left
{ 70, 110, 110, 70, 110, 110, 110, 110, 500 }, // body turn right
{ 70, 70, 70, 70, 110, 70, 70, 110, 500 }, // body turn left
{ 70, 110, 110, 70, 110, 110, 110, 110, 500 }, // body turn right
{ 70, 90, 90, 70, 110, 90, 90, 110, 500 } // leg1, 2 up ; leg3, 4 down
};
// Push up 掌上壓
int Servo_Prg_11_Step = 11;
int Servo_Prg_11 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 90, 90, 110, 110, 90, 90, 70, 500 }, // start
{ 100, 90, 90, 80, 80, 90, 90, 100, 600 }, // down
{ 70, 90, 90, 110, 110, 90, 90, 70, 700 }, // up
{ 100, 90, 90, 80, 80, 90, 90, 100, 800 }, // down
{ 70, 90, 90, 110, 110, 90, 90, 70, 900 }, // up
{ 100, 90, 90, 80, 80, 90, 90, 100, 1500 }, // down
{ 70, 90, 90, 110, 110, 90, 90, 70, 2000 }, // up
{ 135, 90, 90, 45, 45, 90, 90, 135, 200 }, // fast down
{ 70, 90, 90, 45, 60, 90, 90, 135, 800 }, // leg1 up
{ 70, 90, 90, 45, 110, 90, 90, 135, 800 }, // leg2 up
{ 70, 90, 90, 110, 110, 90, 90, 70, 800 } // leg3, leg4 up
};
// Sleep 睡眠姿勢
int Servo_Prg_12_Step = 2;
int Servo_Prg_12 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 30, 90, 90, 150, 150, 90, 90, 30, 500 }, // leg1,4 dn
{ 30, 45, 135, 150, 150, 135, 45, 30, 500 }, // protect myself
};
// 舞步 1
int Servo_Prg_13_Step = 10;
int Servo_Prg_13 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 90, 90, 90, 90, 90, 90, 90, 90, 400 }, // leg1,2,3,4 up
{ 50, 90, 90, 90, 90, 90, 90, 90, 400 }, // leg1 dn
{ 90, 90, 90, 130, 90, 90, 90, 90, 400 }, // leg1 up; leg2 dn
{ 90, 90, 90, 90, 90, 90, 90, 50, 400 }, // leg2 up; leg4 dn
{ 90, 90, 90, 90, 130, 90, 90, 90, 400 }, // leg4 up; leg3 dn
{ 50, 90, 90, 90, 90, 90, 90, 90, 400 }, // leg3 up; leg1 dn
{ 90, 90, 90, 130, 90, 90, 90, 90, 400 }, // leg1 up; leg2 dn
{ 90, 90, 90, 90, 90, 90, 90, 50, 400 }, // leg2 up; leg4 dn
{ 90, 90, 90, 90, 130, 90, 90, 90, 400 }, // leg4 up; leg3 dn
{ 90, 90, 90, 90, 90, 90, 90, 90, 400 }, // leg3 up
};
// 舞步 2
int Servo_Prg_14_Step = 9;
int Servo_Prg_14 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 45, 135, 110, 110, 135, 45, 70, 400 }, // leg1,2,3,4 two sides
{ 115, 45, 135, 65, 110, 135, 45, 70, 400 }, // leg1,2 up
{ 70, 45, 135, 110, 65, 135, 45, 115, 400 }, // leg1,2 dn; leg3,4 up
{ 115, 45, 135, 65, 110, 135, 45, 70, 400 }, // leg3,4 dn; leg1,2 up
{ 70, 45, 135, 110, 65, 135, 45, 115, 400 }, // leg1,2 dn; leg3,4 up
{ 115, 45, 135, 65, 110, 135, 45, 70, 400 }, // leg3,4 dn; leg1,2 up
{ 70, 45, 135, 110, 65, 135, 45, 115, 400 }, // leg1,2 dn; leg3,4 up
{ 115, 45, 135, 65, 110, 135, 45, 70, 400 }, // leg3,4 dn; leg1,2 up
{ 75, 45, 135, 105, 110, 135, 45, 70, 400 }, // leg1,2 dn
};
// 舞步 3
int Servo_Prg_15_Step = 10;
int Servo_Prg_15 [][ALLMATRIX] PROGMEM = {
// 15, 14, 13, 12, 0, 1, 2, 3, ms
{ 70, 45, 45, 110, 110, 135, 135, 70, 400 }, // leg1,2,3,4 bk
{ 110, 45, 45, 60, 70, 135, 135, 70, 400 }, // leg1,2,3 up
{ 70, 45, 45, 110, 110, 135, 135, 70, 400 }, // leg1,2,3 dn
{ 110, 45, 45, 110, 70, 135, 135, 120, 400 }, // leg1,3,4 up
{ 70, 45, 45, 110, 110, 135, 135, 70, 400 }, // leg1,3,4 dn
{ 110, 45, 45, 60, 70, 135, 135, 70, 400 }, // leg1,2,3 up
{ 70, 45, 45, 110, 110, 135, 135, 70, 400 }, // leg1,2,3 dn
{ 110, 45, 45, 110, 70, 135, 135, 120, 400 }, // leg1,3,4 up
{ 70, 45, 45, 110, 110, 135, 135, 70, 400 }, // leg1,3,4 dn
{ 70, 90, 90, 110, 110, 90, 90, 70, 400 }, // standby
};
// --------------------------------------------------------------------------------
4.2.3 舵机驱动函数,输入是舵机的1位置和pwm数据
void Set_PWM_to_Servo(int iServo, int iValue)
{
// 读取 EEPROM 修正误差
int NewPWM = iValue + (int8_t)EEPROM.read(iServo);
NewPWM = map(NewPWM, PWMRES_Min, PWMRES_Max, SERVOMIN, SERVOMAX);
pwm.setPWM(Servo_Map[iServo], 0, NewPWM);
}
void Servo_PROGRAM_Zero()
{
// 清除备份目前舵机的數值
for (int Index = 0; Index < ALLMATRIX; Index++) {
Running_Servo_POS[Index] = Servo_Act_0[Index];
}
// 重新載入舵机預设數值
for (int iServo = 0; iServo < ALLSERVOS; iServo++) {
Set_PWM_to_Servo(iServo, Running_Servo_POS[iServo]);
delay(10);
}
}
void Servo_PROGRAM_Center()
{
// 清除目前舵机数值
for (int Index = 0; Index < ALLMATRIX; Index++) {
Running_Servo_POS[Index] = Servo_Act_1[Index];
}
// 重新載入舵机預設数值
for (int iServo = 0; iServo < ALLSERVOS; iServo++) {
Set_PWM_to_Servo(iServo, Running_Servo_POS[iServo]);
delay(10);
}
}
void Servo_PROGRAM_Run(int iMatrix[][ALLMATRIX], int iSteps)
{
int INT_TEMP_A, INT_TEMP_B, INT_TEMP_C;
for (int MainLoopIndex = 0; MainLoopIndex < iSteps; MainLoopIndex++) { // iSteps
int InterTotalTime = iMatrix[MainLoopIndex][ALLMATRIX - 1]; // InterTotalTime 此步骤总时间
int InterDelayCounter = InterTotalTime / BASEDELAYTIME; // InterDelayCounter 此步驟基本延遲次數
for (int InterStepLoop = 0; InterStepLoop < InterDelayCounter; InterStepLoop++) { // 內差次數迴圈
for (int ServoIndex = 0; ServoIndex < ALLSERVOS; ServoIndex++) {
INT_TEMP_A = Running_Servo_POS[ServoIndex];
INT_TEMP_B = iMatrix[MainLoopIndex][ServoIndex];
if (INT_TEMP_A == INT_TEMP_B) { // 数值不变
INT_TEMP_C = INT_TEMP_B;
} else if (INT_TEMP_A > INT_TEMP_B) { // 数值減少
INT_TEMP_C = map(BASEDELAYTIME * InterStepLoop, 0, InterTotalTime, 0, INT_TEMP_A - INT_TEMP_B); // PWM內差值 = map(执行次数时间累加, 开始时间, 结束时间, 內差起始值, 內差最大值)
if (INT_TEMP_A - INT_TEMP_C >= INT_TEMP_B) {
Set_PWM_to_Servo(ServoIndex, INT_TEMP_A - INT_TEMP_C);
}
} else if (INT_TEMP_A < INT_TEMP_B) { // 数值增加
INT_TEMP_C = map(BASEDELAYTIME * InterStepLoop, 0, InterTotalTime, 0, INT_TEMP_B - INT_TEMP_A); // PWM內差值 = map(执行次数时间累加, 开始时间, 结束时间, 內差起始值, 內差最大值)
if (INT_TEMP_A + INT_TEMP_C <= INT_TEMP_B) {
Set_PWM_to_Servo(ServoIndex, INT_TEMP_A + INT_TEMP_C);
}
}
}
delay(BASEDELAYTIME);
}
// 备份目前舵机数值
for (int Index = 0; Index < ALLMATRIX; Index++) {
Running_Servo_POS[Index] = iMatrix[MainLoopIndex][Index];
}
}
}
4.2.4 EEPROM记录舵机数值
void writeKeyValue(int8_t key, int8_t value)
{
EEPROM.write(key, value);
EEPROM.commit();
}
int8_t readKeyValue(int8_t key)
{
Serial.println("read");
Serial.println(key);
int8_t value = EEPROM.read(key);
}
// --------------------------------------------------------------------------------
4.2.5 手机连接WIFI网页代码
void handleAction(WiFiClient client, String req, HTTPMethod method)
{
server.send(200, "text/plain", "Hello!");
}
void handleSave()
{
String key = server.arg("key");
String value = server.arg("value");
int8_t keyInt = key.toInt();
int8_t valueInt = value.toInt();
delay(50);
if (keyInt == 100) {
writeKeyValue(0, 0);
writeKeyValue(1, 0);
writeKeyValue(2, 0);
writeKeyValue(3, 0);
writeKeyValue(4, 0);
writeKeyValue(5, 0);
writeKeyValue(6, 0);
writeKeyValue(7, 0);
} else {
if (valueInt >= -124 && valueInt <= 124) {
writeKeyValue(keyInt, valueInt);
}
}
delay(10);
server.send(200, "text/html", "(key, value)=(" + key + "," + value + ")");
}
void handleController()
{
String pm = server.arg("pm");
String servo = server.arg("servo");
if (pm != "") {
Servo_PROGRAM = pm.toInt();
}
if (servo != "") {
servo_id = servo.toInt();
String ival = server.arg("value");
Set_PWM_to_Servo(servo_id, ival.toInt());
}
server.send(200, "text/html", "(pm)=(" + pm + ")");
}
void handleOnLine()
{
String m0 = server.arg("m0");
String m1 = server.arg("m1");
String m2 = server.arg("m2");
String m3 = server.arg("m3");
String m4 = server.arg("m4");
String m5 = server.arg("m5");
String m6 = server.arg("m6");
String m7 = server.arg("m7");
String t1 = server.arg("t1");
int Servo_Prg_tmp [][ALLMATRIX] = {
// 15, 14, 13, 12, 0, 1, 2, 3, Run Time
{ m0.toInt(), m1.toInt(), m2.toInt(), m3.toInt(), m4.toInt(), m5.toInt(), m6.toInt(), m7.toInt(), t1.toInt() }
};
Servo_PROGRAM_Run(Servo_Prg_tmp, 1);
server.send(200, "text/html", "(m0, m1)=(" + m0 + "," + m1 + ")");
}
// --------------------------------------------------------------------------------
4.2.6 WebServer
void enableWebServer()
{
HTTPMethod getMethod = HTTP_GET;
server.on("/controller", getMethod, handleController);
server.on("/save", getMethod, handleSave);
server.on("/", getMethod, handleIndex);
server.on("/editor", getMethod, handleEditor);
server.on("/zero", getMethod, handleZero);
server.on("/setting", getMethod, handleSetting);
server.on("/online", getMethod, handleOnLine);
server.begin();
}
// --------------------------------------------------------------------------------
4.2.7 Setup代码
void setup(void)
{
Serial.begin(115200);
Serial.println("Robot-J mini Start!");
// PWMServoDriver
pwm.begin();
pwm.setPWMFreq(60); // servos run at 60Hz updates
// AP SSID Name
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.softAPmacAddress(mac);
String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
macID.toUpperCase();
String AP_NameString = "Robot-J mini - " + macID;
char AP_NameChar[AP_NameString.length() + 1];
memset(AP_NameChar, 0, AP_NameString.length() + 1);
for (int i = 0; i < AP_NameString.length(); i++)
AP_NameChar[i] = AP_NameString.charAt(i);
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_NameChar, WiFiAPPSK);
IPAddress myIP = WiFi.softAPIP();
// EEPROM
EEPROM.begin(512);
delay(10);
// 清除备份目前舵机數值
for (int Index = 0; Index < ALLMATRIX; Index++) {
Running_Servo_POS[Index] = Servo_Act_0[Index];
}
// 增加組裝便利性
Servo_PROGRAM_Zero();
// 网页生成
enableWebServer();
//Servo_PROGRAM = 101;
}
4.2.8 loop 代码
void loop(void)
{
// 網頁建構
server.handleClient();
if (Servo_PROGRAM >= 1 ) {
switch (Servo_PROGRAM) {
case 1: // Standby 待机
Servo_PROGRAM_Run(Servo_Prg_1, Servo_Prg_1_Step);
break;
case 2: // Forward 前行
Servo_PROGRAM_Run(Servo_Prg_2, Servo_Prg_2_Step);
break;
case 3: // Backward 后退
Servo_PROGRAM_Run(Servo_Prg_3, Servo_Prg_3_Step);
break;
case 4: // Left shift 左移
Servo_PROGRAM_Run(Servo_Prg_4, Servo_Prg_4_Step);
break;
case 5: // Right shift 右移
Servo_PROGRAM_Run(Servo_Prg_5, Servo_Prg_5_Step);
break;
case 6: // Turn left 左转
Servo_PROGRAM_Run(Servo_Prg_6, Servo_Prg_6_Step);
break;
case 7: // Turn right 右转
Servo_PROGRAM_Run(Servo_Prg_7, Servo_Prg_7_Step);
break;
case 8: // Lie 趴地
Servo_PROGRAM_Run(Servo_Prg_8, Servo_Prg_8_Step);
break;
case 9: // Say Hi 打招呼
Servo_PROGRAM_Run(Servo_Prg_9, Servo_Prg_9_Step);
Servo_PROGRAM_Run(Servo_Prg_1, Servo_Prg_1_Step);
break;
case 10: // Fighting 戰鬥姿態
Servo_PROGRAM_Run(Servo_Prg_10, Servo_Prg_10_Step);
break;
case 11: // Push up 掌上壓
Servo_PROGRAM_Run(Servo_Prg_11, Servo_Prg_11_Step);
break;
case 12: // Sleep 睡眠姿勢
Servo_PROGRAM_Run(Servo_Prg_1, Servo_Prg_1_Step);
Servo_PROGRAM_Run(Servo_Prg_12, Servo_Prg_12_Step);
break;
case 13: // 舞步 1
Servo_PROGRAM_Run(Servo_Prg_13, Servo_Prg_13_Step);
break;
case 14: // 舞步 2
Servo_PROGRAM_Run(Servo_Prg_14, Servo_Prg_14_Step);
break;
case 15: // 舞步 3
Servo_PROGRAM_Run(Servo_Prg_15, Servo_Prg_15_Step);
break;
case 99: // 待機
Servo_PROGRAM_Center();
delay(300);
break;
case 100:
Servo_PROGRAM_Zero();
delay(300);
case 101:
Servo_PROGRAM_Run(Servo_Prg_1, Servo_Prg_1_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_2, Servo_Prg_2_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_3, Servo_Prg_3_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_4, Servo_Prg_4_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_5, Servo_Prg_5_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_6, Servo_Prg_6_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_7, Servo_Prg_7_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_8, Servo_Prg_8_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_9, Servo_Prg_9_Step);
Servo_PROGRAM_Run(Servo_Prg_1, Servo_Prg_1_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_10, Servo_Prg_10_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_11, Servo_Prg_11_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_12, Servo_Prg_12_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_13, Servo_Prg_13_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_14, Servo_Prg_14_Step);
Servo_PROGRAM_Center();
delay(1000);
Servo_PROGRAM_Run(Servo_Prg_15, Servo_Prg_15_Step);
Servo_PROGRAM_Center();
delay(1000);
break;
}
Servo_PROGRAM = 0;
}
}
4.2.9 手机看到网页代码
void handleZero()
{
String content = "";
content += "<html>";
content += "<head>";
content += "<title>Zero check</title>";
content += "<meta charset=UTF-8>";
content += "<meta name=viewport content=width=device-width>";
content += "<style type=text/css>";
content += "body {";
content += "margin: 0px;";
content += "backgound-color: #FFFFFF;";
content += "font-family: helvetica, arial;";
content += "font-size: 100%;";
content += "color: #555555;";
content += "}";
content += "td {";
content += "text-align: center;";
content += "}";
content += "span {";
content += "font-family: helvetica, arial;";
content += "font-size: 80%;";
content += "color: #777777;";
content += "}";
content += "button {";
content += "width: 40%;";
content += "font-family: helvetica, arial;";
content += "font-size: 90%;";
content += "color: #555555;";
content += "background: #BFDFFF;";
content += "padding: 5px 5px 5px 5px;";
content += "border: none;";
content += "}";
content += "</style>";
content += "</head>";
content += "<body>";
content += "<br>";
content += "<table width=100% height=90%>";
content += "<tr>";
content += "<td width=50%><button type=button style=background:#FFE599 onclick=controlServo(4,45)>D16</button></td>";
content += "<td width=50%><button type=button style=background:#FFE599 onclick=controlServo(0,135)>D14</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td><button type=button onclick=controlServo(5,135)>D05</button></td>";
content += "<td><button type=button onclick=controlServo(1,45)>D12</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td><button type=button onclick=controlServo(6,45)>D04</button></td>";
content += "<td><button type=button onclick=controlServo(2,135)>D13</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td><button type=button style=background:#FFE599 onclick=controlServo(7,135)>D02</button></td>";
content += "<td><button type=button style=background:#FFE599 onclick=controlServo(3,45)>D15</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td colspan=2><button type=button style=background:#FFBFBF onclick=controlPm(100)>ZERO Postition</button></td>";
content += "</tr>";
content += "</table>";
content += "</body>";
content += "<script>";
content += "function controlServo(id, value) {";
content += "var xhttp = new XMLHttpRequest();";
content += "xhttp.onreadystatechange = function() {";
content += "if (xhttp.readyState == 4 && xhttp.status == 200) {";
content += "document.getElementById(\"demo\").innerHTML = xhttp.responseText;";
content += "}";
content += "};";
content += "xhttp.open(\"GET\", \"controller?servo=\"+id+\"&value=\"+value, true);";
content += "xhttp.send();";
content += "}";
content += "function controlPm(value) {";
content += "var xhttp = new XMLHttpRequest();";
content += "xhttp.onreadystatechange = function() {";
content += "if (xhttp.readyState == 4 && xhttp.status == 200) {";
content += "document.getElementById(\"demo\").innerHTML = xhttp.responseText;";
content += "}";
content += "};";
content += "xhttp.open(\"GET\", \"controller?pm=\"+value, true);";
content += "xhttp.send();";
content += "}";
content += "</script>";
content += "</html>";
server.send(200, "text/html", content);
}
// Servo calibration
void handleSetting()
{
int servo7Val = readKeyValue(7);
String servo7ValStr = String(servo7Val);
int servo6Val = readKeyValue(6);
String servo6ValStr = String(servo6Val);
int servo5Val = readKeyValue(5);
String servo5ValStr = String(servo5Val);
int servo4Val = readKeyValue(4);
String servo4ValStr = String(servo4Val);
int servo3Val = readKeyValue(3);
String servo3ValStr = String(servo3Val);
int servo2Val = readKeyValue(2);
String servo2ValStr = String(servo2Val);
int servo1Val = readKeyValue(1);
String servo1ValStr = String(servo1Val);
int servo0Val = readKeyValue(0);
String servo0ValStr = String(servo0Val);
String content = "";
content += "<html>";
content += "<head>";
content += "<title>Servo calibration</title>";
content += "<meta charset=UTF-8>";
content += "<meta name=viewport content=width=device-width>";
content += "<style type=text/css>";
content += "body {";
content += "margin: 0px;";
content += "backgound-color: #FFFFFF;";
content += "font-family: helvetica, arial;";
content += "font-size: 100%;";
content += "color: #555555;";
content += "}";
content += "td {";
content += "text-align: center;";
content += "}";
content += "span {";
content += "font-family: helvetica, arial;";
content += "font-size: 70%;";
content += "color: #777777;";
content += "}";
content += "input[type=text] {";
content += "width: 40%;";
content += "font-family: helvetica, arial;";
content += "font-size: 90%;";
content += "color: #555555;";
content += "text-align: center;";
content += "padding: 3px 3px 3px 3px;";
content += "}";
content += "button {";
content += "width: 40%;";
content += "font-family: helvetica, arial;";
content += "font-size: 90%;";
content += "color: #555555;";
content += "background: #BFDFFF;";
content += "padding: 5px 5px 5px 5px;";
content += "border: none;";
content += "}";
content += "</style>";
content += "</head>";
content += "<body>";
content += "<br>";
content += "<table width=100% height=90%>";
content += "<tr>";
content += "<td width=50%>D16<br/><input type=text id=servo_4 value=\"" + servo4ValStr + "\"><button type=button style=background:#FFE599 onclick=saveServo(4,'servo_4')>SET</button></td>";
content += "<td width=50%>D14<br/><input type=text id=servo_0 value=\"" + servo0ValStr + "\"><button type=button style=background:#FFE599 onclick=saveServo(0,'servo_0')>SET</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td>D05<br/><input type=text id=servo_5 value=\"" + servo5ValStr + "\"><button type=button onclick=saveServo(5,'servo_5')>SET</button></td>";
content += "<td>D12<br/><input type=text id=servo_1 value=\"" + servo1ValStr + "\"><button type=button onclick=saveServo(1,'servo_1')>SET</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td>D04<br/><input type=text id=servo_6 value=\"" + servo6ValStr + "\"><button type=button onclick=saveServo(6,'servo_6')>SET</button></td>";
content += "<td>D13<br/><input type=text id=servo_2 value=\"" + servo2ValStr + "\"><button type=button onclick=saveServo(2,'servo_2')>SET</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td>D02<br/><input type=text id=servo_7 value=\"" + servo7ValStr + "\"><button type=button style=background:#FFE599 onclick=saveServo(7,'servo_7')>SET</button></td>";
content += "<td>D15<br/><input type=text id=servo_3 value=\"" + servo3ValStr + "\"><button type=button style=background:#FFE599 onclick=saveServo(3,'servo_3')>SET</button></td>";
content += "</tr>";
content += "<!--<tr>";
content += "<td colspan=2><button type=button style=background:#FFBFBF onclick=saveServo(100,0)>RESET ALL</button></td>";
content += "</tr>-->";
content += "</table>";
content += "</body>";
content += "<script>";
content += "function saveServo(id, textId) {";
content += "var xhttp = new XMLHttpRequest();";
content += "var value = \"0\";";
content += "if(id==100){";
content += "document.getElementById(\"servo_7\").value = \"0\";";
content += "document.getElementById(\"servo_6\").value = \"0\";";
content += "document.getElementById(\"servo_5\").value = \"0\";";
content += "document.getElementById(\"servo_4\").value = \"0\";";
content += "document.getElementById(\"servo_3\").value = \"0\";";
content += "document.getElementById(\"servo_2\").value = \"0\";";
content += "document.getElementById(\"servo_1\").value = \"0\";";
content += "document.getElementById(\"servo_0\").value = \"0\";";
content += "}else{";
content += "value = document.getElementById(textId).value;";
content += "}";
content += "xhttp.onreadystatechange = function() {";
content += "if (xhttp.readyState == 4 && xhttp.status == 200) {";
content += "document.getElementById(\"demo\").innerHTML = xhttp.responseText;";
content += "}";
content += "};";
content += "xhttp.open(\"GET\",\"save?key=\"+id+\"&value=\"+value, true);";
content += "xhttp.send();";
content += "}";
content += "</script>";
content += "</html>";
server.send(200, "text/html", content);
}
// Motion editor
void handleEditor()
{
String content = "";
content += "<html>";
content += "<head>";
content += "<title>Motion editor</title>";
content += "<meta charset=UTF-8>";
content += "<meta name=viewport content=width=device-width>";
content += "<style type=text/css>";
content += "body {";
content += "margin: 0px;";
content += "backgound-color: #FFFFFF;";
content += "font-family: helvetica, arial;";
content += "font-size: 100%;";
content += "color: #555555;";
content += "}";
content += "td {";
content += "text-align: center;";
content += "}";
content += "span {";
content += "font-family: helvetica, arial;";
content += "font-size: 70%;";
content += "color: #777777;";
content += "}";
content += "input[type=range] {";
content += "-webkit-appearance: none;";
content += "background-color: #CCCCCC;";
content += "width: 70%;";
content += "height: 20px;";
content += "}";
content += "input[type=range]::-webkit-slider-thumb {";
content += "-webkit-appearance: none;";
content += "background-color: #4DA6FF;";
content += "opacity: 0.9;";
content += "width: 12px;";
content += "height: 20px;";
content += "}";
content += "input[type=text] {";
content += "width: 40%;";
content += "font-family: helvetica, arial;";
content += "font-size: 90%;";
content += "color: #555555;";
content += "text-align: center;";
content += "padding: 3px 3px 3px 3px;";
content += "}";
content += "button {";
content += "width: 40%;";
content += "font-family: helvetica, arial;";
content += "font-size: 90%;";
content += "color: #555555;";
content += "padding: 5px 5px 5px 5px;";
content += "border: none;";
content += "}";
content += "</style>";
content += "</head>";
content += "<body onload='actionCode()'>";
content += "<br>";
content += "<table width=100% height=90%>";
content += "<tr>";
content += "<td width=50%>D16 <span>Default 110<br>⬇ 150 <input type=range id=range_4 min=30 max=150 value=110 style=direction:rtl onchange=controlServo(4,'range_4')> 30 ⬆</span>";
content += "<br><input type=text id=servo_4 value=110> <button type=button style=background:#FFE599 onclick=controlServo(4,'servo_4')>Send</button></td>";
content += "<td width=50%>D14 <span>Default 70<br>⬆ 150 <input type=range id=range_0 min=30 max=150 value=70 style=direction:rtl onchange=controlServo(0,'range_0')> 30 ⬇</span>";
content += "<br><input type=text id=servo_0 value=70> <button type=button style=background:#FFE599 onclick=controlServo(0,'servo_0')>Send</button></td>";
content += "</tr>";
content += "<tr><td colspan=4><span><br></span></td></tr>";
content += "<tr>";
content += "<td>D05 <span>Default 90<br>◀ 150 <input type=range id=range_5 min=30 max=150 value=90 style=direction:rtl onchange=controlServo(5,'range_5')> 30 ▶</span>";
content += "<br><input type=text id=servo_5 value=90> <button type=button style=background:#BFDFFF onclick=controlServo(5,'servo_5')>Send</button></td>";
content += "<td>D12 <span>Default 90<br>◀ 150 <input type=range id=range_1 min=30 max=150 value=90 style=direction:rtl onchange=controlServo(1,'range_1')> 30 ▶</span>";
content += "<br><input type=text id=servo_1 value=90> <button type=button style=background:#BFDFFF onclick=controlServo(1,'servo_1')>Send</button></td>";
content += "</tr>";
content += "<tr><td colspan=4><span><br></span></td></tr>";
content += "<tr>";
content += "<td>D04 <span>Default 90<br>◀ 30 <input type=range id=range_6 min=30 max=150 value=90 onchange=controlServo(6,'range_6')> 150 ▶</span>";
content += "<br><input type=text id=servo_6 value=90> <button type=button style=background:#BFDFFF onclick=controlServo(6,'servo_6')>Send</button></td>";
content += "<td>D13 <span>Default 90<br>◀ 30 <input type=range id=range_2 min=30 max=150 value=90 onchange=controlServo(2,'range_2')> 150 ▶</span>";
content += "<br><input type=text id=servo_2 value=90> <button type=button style=background:#BFDFFF onclick=controlServo(2,'servo_2')>Send</button></td>";
content += "</tr>";
content += "<tr><td colspan=4><span><br></span></td></tr>";
content += "<tr>";
content += "<td>D02 <span>Default 70<br>⬇ 30 <input type=range id=range_7 min=30 max=150 value=70 onchange=controlServo(7,'range_7')> 150 ⬆</span>";
content += "<br><input type=text id=servo_7 value=70> <button type=button style=background:#FFE599 onclick=controlServo(7,'servo_7')>Send</button></td>";
content += "<td>D15 <span>Default 110<br>⬆ 30 <input type=range id=range_3 min=30 max=150 value=110 onchange=controlServo(3,'range_3')> 150 ⬇</span>";
content += "<br><input type=text id=servo_3 value=110> <button type=button style=background:#FFE599 onclick=controlServo(3,'servo_3')>Send</button></td>";
content += "</tr>";
content += "<tr>";
content += "<td colspan=4><br><span>Action Code:<br><output id=actionCode></output></span></font></td>";
content += "</tr>";
content += "<tr><td colspan=4><span><br></span></td></tr>";
content += "<tr>";
content += "<td colspan=2><button type=button style=background:#FFCC99 onclick=controlPm(1)>Standby</button></td>";
content += "</tr>";
content += "</body>";
content += "<script>";
content += "function controlServo(id, textId) {";
content += "var xhttp = new XMLHttpRequest();";
content += "var value = document.getElementById(textId).value;";
content += "document.querySelector('#range_' + id).value = value;";
content += "document.querySelector('#servo_' + id).value = value;";
content += "actionCode();";
content += "xhttp.onreadystatechange = function() {";
content += "if (xhttp.readyState == 4 && xhttp.status == 200) {";
content += "document.getElementById(\"demo\").innerHTML = xhttp.responseText;";
content += "}";
content += "};";
content += "xhttp.open(\"GET\",\"controller?servo=\"+id+\"&value=\"+value, true);";
content += "xhttp.send();";
content += "}";
content += "function controlPm(value) {";
content += "var xhttp = new XMLHttpRequest();";
content += "xhttp.onreadystatechange = function() {";
content += "if (xhttp.readyState == 4 && xhttp.status == 200) {";
content += "document.getElementById(\"demo\").innerHTML = xhttp.responseText;";
content += "}";
content += "};";
content += "xhttp.open(\"GET\", \"controller?pm=\"+value, true);";
content += "xhttp.send();";
content += "}";
content += "function actionCode() {";
content += "document.querySelector('#actionCode').value =";
content += "document.getElementById('servo_0').value + ', '";
content += "+ document.getElementById('servo_1').value + ', '";
content += "+ document.getElementById('servo_2').value + ', '";
content += "+ document.getElementById('servo_3').value + ', '";
content += "+ document.getElementById('servo_4').value + ', '";
content += "+ document.getElementById('servo_5').value + ', '";
content += "+ document.getElementById('servo_6').value + ', '";
content += "+ document.getElementById('servo_7').value;";
content += "}";
content += "</script>";
content += "</html>";
server.send(200, "text/html", content);
}
// Main controller
void handleIndex()
{
String content = "";
content += "<html>";
content += "<head>";
content += "<title>Q1 mini Controller</title>";
content += "<meta charset=UTF-8>";
content += "<meta name=viewport content=width=device-width>";
content += "<style type=text/css>";
content += "body {";
content += "margin: 0px;";
content += "backgound-color: #FFFFFF;";
content += "font-family: helvetica, arial;";
content += "font-size: 100%;";
content += "color: #555555;";
content += "}";
content += "td {";
content += "text-align: center;";
content += "}";
content += "span {";
content += "font-family: helvetica, arial;";
content += "font-size: 70%;";
content += "color: #777777;";
content += "}";
content += "button {";
content += "width: 90%;";
content += "height: 90%;";
content += "font-family: helvetica, arial;";
content += "font-size: 100%;";
content += "color: #555555;";
content += "background: #BFDFFF;";
content += "padding: 5px 5px 5px 5px;";
content += "border: none;";
content += "}";
content += "</style>";
content += "</head>";
content += "<body>";
content += "<br>";
content += "<table width=100% height=90%>";
content += "<tr height=19%>";
content += "<td width=33%><button type=button style=background:#BFFFCF onclick=controlPm(6)>左转</button></td>";
content += "<td width=33%><button type=button onclick=controlPm(2)>前进</button></td>";
content += "<td width=33%><button type=button style=background:#BFFFCF onclick=controlPm(7)>右转</button></td>";
content += "</tr>";
content += "<tr height=19%>";
content += "<td><button type=button onclick=controlPm(4)>左移</button></td>";
content += "<td><button type=button onclick=controlPm(3)>后退</button></td>";
content += "<td><button type=button onclick=controlPm(5)>右移</button></td>";
content += "</tr>";
content += "<tr height=5%><td colspan=3><span><br></span></td></tr>";
content += "<tr height=20%>";
content += "<td><button type=button style=background:#FFCC99 onclick=controlPm(1)>站立</button></td>";
content += "<td><button type=button style=background:#FFE599 onclick=controlPm(9)>说Hi</button></td>";
content += "<td><button type=button style=background:#FFE599 onclick=controlPm(11)>俯卧撑</button></td>";
content += "</tr>";
content += "<tr height=19%>";
content += "<td><button type=button style=background:#FFE599 onclick=controlPm(8)>躺下</button></td>";
content += "<td><button type=button style=background:#FFE599 onclick=controlPm(10)>战斗</button></td>";
content += "<td><button type=button style=background:#FFBFBF onclick=controlPm(12)>睡觉</button></td>";
content += "</tr>";
content += "<tr height=19%>";
content += "<td><button type=button style=background:#CFBFFF onclick=controlPm(13)>舞姿 1</button></td>";
content += "<td><button type=button style=background:#CFBFFF onclick=controlPm(14)>舞姿 2</button></td>";
content += "<td><button type=button style=background:#CFBFFF onclick=controlPm(15)>舞姿 3</button></td>";
content += "</tr>";
content += "</table>";
content += "<span><p align=center>" + FW_Version + "</p></span>";
content += "</body>";
content += "<script>";
content += "function controlPm(id) {";
content += "var xhttp = new XMLHttpRequest();";
content += "xhttp.onreadystatechange = function() {";
content += "if (xhttp.readyState == 4 && xhttp.status == 200) {";
content += "}";
content += "};";
content += "xhttp.open(\"GET\", \"controller?pm=\"+id, true);";
content += "xhttp.send();";
content += "}";
content += "function controlPms(id) {";
content += "var xhttp = new XMLHttpRequest();";
content += "xhttp.onreadystatechange = function() {";
content += "if (xhttp.readyState == 4 && xhttp.status == 200) {";
content += "}";
content += "};";
content += "xhttp.open(\"GET\", \"controller?pms=\"+id, true);";
content += "xhttp.send();";
content += "}";
content += "</script>";
content += "</html>";
server.send(200, "text/html", content);
}
评论(1)
您还未登录,请登录后发表或查看评论