Over the course of approximately a month, I have crafted a quadruped robot driven by an ESP8266
module. The robot’s movements control and on-screen displays drawing are primarily from other open-source programs. However, these programs frequently rely on the ESP8266
itself to establish web services for control, posing challenges for users with limited technical backgrounds. To address this issue, I have made a WeChat mini-program that introduce MQTT
communication protocols to control the robot, significantly enhancing user accessibility.
#include <ESP8266WiFiMulti.h>
#include <ESP8266httpUpdate.h>
#include <U8g2lib.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Adafruit_PWMServoDriver.h>
// ### The serial data line (SDA) and serial clock line (SCL) for the I2C connection are linked to specific pins on the ESP8266. For the exact numerical values corresponding to the pin connections, please refer to the ESP8266 pinout diagram.
#define SCL 2
#define SDA 0
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
ESP8266WiFiMulti WiFiMulti;
//Initialization of the JSON data transmission.
const size_t capacity = JSON_OBJECT_SIZE(2) + 30;
DynamicJsonDocument mydata(capacity);
char jsondata[capacity];
// ### MQTT Broker
const char *mqtt_broker = ""; //Server address
const char *topic = ""; //Subscription of commands passed from the mini-program to the local device.
const char *t_topic = ""; //Subscription of commands passed from the local device to the mini-program.
const char *mqtt_username = ""; //mqtt user name
const char *mqtt_password = ""; //mqtt password
const int mqtt_port = 1883; //mqtt service port
WiFiClient espClient;
PubSubClient client(espClient);
// ### bemfa OTA
//I use bemfa Cloud for OTA service
String upUrl = "";
//Configure of oled screen
int c_x = -15;
int c_y = 20;
int r_x = 128;
int r_y = 40;
// ### The data arrays of pictures used for emotion
// ### You should convert pictures format from png/jpg... into arrays for use
PROGMEM const uint8_t normale[] { DATA_SET_HERE };
PROGMEM const uint8_t goe[] { DATA_SET_HERE };
PROGMEM const uint8_t sleepe[] { DATA_SET_HERE };
PROGMEM const uint8_t helloe[] { DATA_SET_HERE };
PROGMEM const uint8_t laiyae[] { DATA_SET_HERE };
PROGMEM const uint8_t sajiaoe[] { DATA_SET_HERE };
PROGMEM const uint8_t maimenge[] { DATA_SET_HERE };
PROGMEM const uint8_t sade[] { DATA_SET_HERE };
PROGMEM const uint8_t yaobaie[] { DATA_SET_HERE };
uint8_t command = 0;
//Wireless Configure
void startWiFiConnect(){
digitalWrite(16, LOW);
Serial.println();
Serial.println("Wait for WiFi...");
while(WiFiMulti.run() != WL_CONNECTED){
Serial.print(".");
delay(50);
}
Serial.print("Connected to: ");
Serial.println(WiFi.SSID());
digitalWrite(16, HIGH);
}
//MQTT Connection
void startMqttConnect(){
while (!client.connected()){
String client_id = "Esp8266-client-";
client_id += String(WiFi.macAddress());
Serial.printf("%s is waiting for MQTT broker\n", client_id.c_str());
if(client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("MQTT broker connected");
}
else{
Serial.print("failed with state ");
Serial.println(client.state());
delay(2000);
}
}
//subscribe and publish
client.subscribe(topic);
client.publish(t_topic, jsondata);
}
//Send message while updating
void update_started() {
mydata["update"] = 1;
serializeJson(mydata,jsondata);
client.publish(t_topic, jsondata);
}
//Senf message when updating is failed
void update_error(int err) {
mydata["update"] = -1;
serializeJson(mydata,jsondata);
client.publish(t_topic, jsondata);
mydata["update"] = 0;
serializeJson(mydata,jsondata);
}
/**
* Firmware upgrade.
*/
void updateBin(){
WiFiClient UpdateClient;
ESPhttpUpdate.onStart(update_started);
ESPhttpUpdate.onError(update_error);
t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl);
}
void setup() {
Serial.begin(115200);
u8g2.setBusClock(9000000);
u8g2.begin();
u8g2.enableUTF8Print()
//Initialization the communication message.
mydata["status"] = 1;
mydata["update"] = 0;
serializeJson(mydata, jsondata);
// ### Add Wifi info
WiFiMulti.addAP("", "");
pinMode(16, OUTPUT);
pwm.begin();
pwm.setPWMFreq(60);
delay(1000);
zc();
normal();
startWiFiConnect();
//开始MQTT连接
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
startMqttConnect();
}
//MQTT message callback.
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
JsonObject jsonObj = doc.as<JsonObject>();
JsonObject params =jsonObj["params"];
if (params["hello"] == 1){
client.publish(t_topic, jsondata);
normal();
nh();
hello();
zc();
}
else if (params["normal"] == 1){
client.publish(t_topic, jsondata);
normal();
zc();
}
else if (params["maimeng"] == 1){
client.publish(t_topic, jsondata);
normal();
mm();
middle();
}
else if (params["sajiao"] == 1){
client.publish(t_topic, jsondata);
sleep();
gp();
dog();
dog();
dog();
dog();
zc();
}
else if (params["sad"] == 1){
client.publish(t_topic, jsondata);
sleep();
tx();
surrender();
}
else if (params["laia"] == 1){
client.publish(t_topic, jsondata);
normal();
la();
come();
zc();
}
else if (params["yaobai"] == 1){
client.publish(t_topic, jsondata);
normal();
yb();
swing();
zc();
normal();
}
else if (params["forward"] == 1){
client.publish(t_topic, jsondata);
yd();
normal();
forward();
forward();
forward();
forward();
zc();
}
else if (params["backward"] == 1){
client.publish(t_topic, jsondata);
yd();
normal();
backward();
backward();
backward();
backward();
zc();
}
else if (params["left"] == 1){
client.publish(t_topic, jsondata);
yd();
normal();
left();
left();
left();
zc();
}
else if (params["right"] == 1){
client.publish(t_topic, jsondata);
yd();
normal();
right();
right();
right();
right();
zc();
}
else if (params["shuijiao"] == 1){
client.publish(t_topic, jsondata);
sleep();
sj();
}
else if (params["update"] == 1){
sleep();
updating();
updateBin();
}
}
void loop() {
//接收mqtt
client.loop();
//如果WiFi断开则重连WiFi和MQTT
if(WiFi.status() != WL_CONNECTED){
startWiFiConnect();
startMqttConnect();
}
}
/*----------Movement functions----------*/
// | 7 | | 6 |
// ----- ----- ----- -----
// | 3 | | 2 |
// ----- -----
// | 1 | | 0 |
// ----- ----- ----- -----
// | 5 | | 4 |
void sleep()
{
pwm.setPWM(4, 0, 340); delay(100);
pwm.setPWM(5, 0, 370); delay(100);
pwm.setPWM(6, 0, 360); delay(100);
pwm.setPWM(7, 0, 410); delay(100);
pwm.setPWM(0, 0, 390); delay(100);
pwm.setPWM(1, 0, 190); delay(100);
pwm.setPWM(2, 0, 185); delay(100);
pwm.setPWM(3, 0, 365);
}
void normal()
{
pwm.setPWM(0, 0, 280); delay(100);
pwm.setPWM(1, 0, 280); delay(100);
pwm.setPWM(2, 0, 280); delay(100);
pwm.setPWM(3, 0, 270); delay(100);
pwm.setPWM(4, 0, 580); delay(100);
pwm.setPWM(5, 0, 120); delay(100);
pwm.setPWM(6, 0, 595); delay(100);
pwm.setPWM(7, 0, 135);
}
void left()
{
pwm.setPWM(4, 0, 450); pwm.setPWM(7, 0, 260); delay(100);
pwm.setPWM(0, 0, 390); pwm.setPWM(3, 0, 365); delay(100);
pwm.setPWM(4, 0, 580); pwm.setPWM(7, 0, 135); delay(100);
pwm.setPWM(6, 0, 460); pwm.setPWM(5, 0, 280); delay(100);
pwm.setPWM(2, 0, 450); pwm.setPWM(1, 0, 460); delay(100);
pwm.setPWM(6, 0, 595); pwm.setPWM(5, 0, 120); delay(100);
pwm.setPWM(0, 0, 280); pwm.setPWM(1, 0, 280); pwm.setPWM(2, 0, 280);
pwm.setPWM(3, 0, 270); delay(100);
}
void right()
{
pwm.setPWM(5, 0, 280); pwm.setPWM(6, 0, 490); delay(100);
pwm.setPWM(1, 0, 190); pwm.setPWM(2, 0, 185); delay(100);
pwm.setPWM(5, 0, 120); pwm.setPWM(6, 0, 595); delay(100);
pwm.setPWM(7, 0, 260); pwm.setPWM(4, 0, 450); delay(100);
pwm.setPWM(3, 0, 210); pwm.setPWM(0, 0, 190); delay(100);
pwm.setPWM(7, 0, 135); pwm.setPWM(4, 0, 580); delay(100);
pwm.setPWM(0, 0, 280); pwm.setPWM(1, 0, 280); pwm.setPWM(2, 0, 280);
pwm.setPWM(3, 0, 270); delay(100);
}
void forward()
{
pwm.setPWM(7, 0, 260); pwm.setPWM(4, 0, 450); delay(50);
pwm.setPWM(3, 0, 365); pwm.setPWM(0, 0, 120); delay(100);
pwm.setPWM(7, 0, 135); pwm.setPWM(4, 0, 580); delay(100);
pwm.setPWM(0, 0, 280); pwm.setPWM(3, 0, 270); pwm.setPWM(6, 0, 490);
pwm.setPWM(5, 0, 280); delay(50);
pwm.setPWM(2, 0, 185); pwm.setPWM(1, 0, 460); delay(100);
pwm.setPWM(6, 0, 595); pwm.setPWM(5, 0, 120); delay(100);
pwm.setPWM(1, 0, 280); pwm.setPWM(2, 0, 280);
}
void backward()
{
pwm.setPWM(5, 0, 280); pwm.setPWM(6, 0, 490); delay(50);
pwm.setPWM(1, 0, 190); pwm.setPWM(2, 0, 450); delay(100);
pwm.setPWM(5, 0, 120); pwm.setPWM(6, 0, 595); delay(100);
pwm.setPWM(1, 0, 280); pwm.setPWM(2, 0, 280); pwm.setPWM(4, 0, 450);
pwm.setPWM(7, 0, 260); delay(50);
pwm.setPWM(0, 0, 390); pwm.setPWM(3, 0, 140); delay(100);
pwm.setPWM(4, 0, 580); pwm.setPWM(7, 0, 135); delay(100);
pwm.setPWM(0, 0, 280); pwm.setPWM(3, 0, 270);
}
void hello()
{
pwm.setPWM(7, 0, 300); delay(100);
pwm.setPWM(0, 0, 390); delay(200);
pwm.setPWM(4, 0, 110); delay(300);
pwm.setPWM(4, 0, 340); delay(300);
pwm.setPWM(4, 0, 110); delay(300);
pwm.setPWM(4, 0, 340); delay(300);
pwm.setPWM(4, 0, 110); delay(300);
pwm.setPWM(4, 0, 340); delay(500);
pwm.setPWM(0, 0, 280); pwm.setPWM(4, 0, 580); pwm.setPWM(7, 0, 135);
}
void come()
{
pwm.setPWM(7, 0, 300); delay(100);
pwm.setPWM(0, 0, 120); pwm.setPWM(4, 0, 280); delay(500);
pwm.setPWM(4, 0, 110); delay(200);
pwm.setPWM(4, 0, 340); delay(400);
pwm.setPWM(4, 0, 110); delay(200);
pwm.setPWM(4, 0, 340); delay(400);
pwm.setPWM(0, 0, 280); pwm.setPWM(4, 0, 580); pwm.setPWM(7, 0, 135);
}
void dog()
{
delay(300); pwm.setPWM(0, 0, 120); pwm.setPWM(1, 0, 460); pwm.setPWM(2, 0, 450); pwm.setPWM(3, 0, 140);
delay(300); pwm.setPWM(0, 0, 390); pwm.setPWM(1, 0, 190); pwm.setPWM(2, 0, 185); pwm.setPWM(3, 0, 365);
}
void middle()
{
pwm.setPWM(7, 0, 300); delay(100);
pwm.setPWM(0, 0, 120); delay(100);
pwm.setPWM(4, 0, 110);
}
void surrender()
{
delay(100); pwm.setPWM(4, 0, 90); pwm.setPWM(5, 0, 620); pwm.setPWM(6, 0, 110); pwm.setPWM(7, 0, 640);
}
void swing()
{
delay(50); pwm.setPWM(4, 0, 450); pwm.setPWM(7, 0, 260);
delay(50); pwm.setPWM(0, 0, 390); pwm.setPWM(3, 0, 365);
delay(50); pwm.setPWM(4, 0, 580); pwm.setPWM(7, 0, 135);
delay(50); pwm.setPWM(5, 0, 280); pwm.setPWM(6, 0, 490);
delay(50); pwm.setPWM(1, 0, 190); pwm.setPWM(2, 0, 185);
delay(50); pwm.setPWM(5, 0, 120); pwm.setPWM(6, 0, 595);
delay(500); pwm.setPWM(4, 0, 450); pwm.setPWM(5, 0, 120);
pwm.setPWM(6, 0, 470); pwm.setPWM(7, 0, 135); delay(400);
pwm.setPWM(4, 0, 580); pwm.setPWM(5, 0, 270); pwm.setPWM(6, 0, 595);
pwm.setPWM(7, 0, 310); delay(400);
pwm.setPWM(4, 0, 450); pwm.setPWM(5, 0, 120);
pwm.setPWM(6, 0, 470); pwm.setPWM(7, 0, 135);
delay(400); pwm.setPWM(4, 0, 580); pwm.setPWM(5, 0, 270);
pwm.setPWM(6, 0, 595); pwm.setPWM(7, 0, 310);
delay(400); pwm.setPWM(4, 0, 450); pwm.setPWM(5, 0, 120);
pwm.setPWM(6, 0, 470); pwm.setPWM(7, 0, 135); delay(400);
pwm.setPWM(4, 0, 580); pwm.setPWM(5, 0, 270);
pwm.setPWM(6, 0, 595); pwm.setPWM(7, 0, 310);
delay(400); pwm.setPWM(4, 0, 450); pwm.setPWM(5, 0, 120);
pwm.setPWM(6, 0, 470); pwm.setPWM(7, 0, 135); delay(400);
pwm.setPWM(4, 0, 580); pwm.setPWM(5, 0, 270); pwm.setPWM(6, 0, 595);
pwm.setPWM(7, 0, 310); delay(400); pwm.setPWM(4, 0, 450);
pwm.setPWM(5, 0, 120); pwm.setPWM(6, 0, 470); pwm.setPWM(7, 0, 135);
delay(400); pwm.setPWM(4, 0, 580); pwm.setPWM(5, 0, 270);
pwm.setPWM(6, 0, 595); pwm.setPWM(7, 0, 310); delay(400);
pwm.setPWM(4, 0, 450); pwm.setPWM(5, 0, 120); pwm.setPWM(6, 0, 470);
pwm.setPWM(7, 0, 135); delay(400); pwm.setPWM(4, 0, 580);
pwm.setPWM(5, 0, 270); pwm.setPWM(6, 0, 595); pwm.setPWM(7, 0, 310); delay(400);
}
//u8g2 control the screen
void mm()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, maimenge);
u8g2.sendBuffer();
delay(20);
}
void zc()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, normale);
u8g2.sendBuffer();
delay(20);
}
void sj()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, sleepe);
u8g2.sendBuffer();
delay(20);
}
void nh()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, helloe);
u8g2.sendBuffer();
delay(20);
}
void la()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, laiyae);
u8g2.sendBuffer();
delay(20);
}
void gp()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, sajiaoe);
u8g2.sendBuffer();
delay(20);
}
void tx()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, sade);
u8g2.sendBuffer();
delay(20);
}
void yb()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, yaobaie);
u8g2.sendBuffer();
delay(20);
}
void yd()
{
u8g2.clearBuffer();
u8g2.drawXBMP(0, 0, 128, 64, goe);
u8g2.sendBuffer();
delay(20);
}
void updating()
{
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy12_t_chinese1);
u8g2.drawStr(32, 32, "Updating...");
u8g2.sendBuffer();
delay(20);
}