我正在尝试使用WebSockets从Android设备与ESP8266 WiFi芯片进行通信,以远程控制连接到Arduino的某些电机。首先,我使用PC和Python进行原型设计,并在ESP8266上设置WebSocket服务器...
ESP8266_server.ino
#include <ESP8266WiFi.h>
#include <WebSocketsServer.h>
const char* ssid = "SKYNET";
const char* password = "yourdogsauntsmaidenname";
WebSocketsServer webSocket = WebSocketsServer(81);
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
//Serial.printf("[%u] get Message: %s\r\n", num, payload);
switch(type) {
case WStype_DISCONNECTED:
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
// Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
}
break;
case WStype_TEXT:
{
//Serial.printf("[%u] get Text: %s\r\n", num, payload);
String _payload = String((char *) &payload[0]);
Serial.print(_payload);
}
break;
case WStype_BIN:
{
hexdump(payload, lenght);
}
// echo data back to browser
webSocket.sendBIN(num, payload, lenght);
break;
}
}
void setup() {
// Set up serial comms
Serial.begin(115200);
// Set up WiFi
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
// Serial.print(".");
delay(200);
}
// Serial.println("");
// Serial.println("WiFi connected");
// Serial.println("IP address: ");
// Serial.println(WiFi.localIP());
delay(500);
// Set up web socket
// Serial.println("Start Websocket Server");
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
void loop() {
webSocket.loop();
}
WiFi芯片通过与Arduino Mega的串行连接进行连接,后者依次解析数据以控制2个直流电机的某些H桥。 Arduino还将数据中继到Arduino IDE串行监视器。
motor_control.ino
// Serial comms from Wemos EPS8622 to Arduino Mega
#include "SoftPWM.h"
// Outputs to PWM & H bridge direction
// PWMs:
// DC_pwm, left_pwm, right_pwm = 3, 4, 5
int pwm_out[] = {3, 4, 5};
const int num_pwm = sizeof(pwm_out) / sizeof(pwm_out[0]);
// H bridge direction control:
// right_2, right_1, left_2, left_1, dc_2, dc_1 = 6, 7, 8, 9, 10 ,11
int dir_pins[] = {6, 7, 8, 9, 10 , 11};
const int num_dir_pins = sizeof(dir_pins) / sizeof(dir_pins[0]);
// Input buffer from ESP8266
int in_buff[] = {0, 0};
const int num_in_buff = sizeof(in_buff) / sizeof(in_buff[0]);
void setup() {
// Set up serial comms
Serial.begin(115200); // Debug to Serial Monitor
Serial3.begin(115200); // From ESP8266
// Set up PWM pins
SoftPWMBegin();
for (int i = 0; i < num_pwm; i++)
{
SoftPWMSet(pwm_out[i], 0);
}
// Set up H bridge direction pins
for (int i = 0; i < num_dir_pins; i++)
{
pinMode(dir_pins[i], OUTPUT);
digitalWrite(dir_pins[i], LOW);
}
}
void loop() {
// Check input from EPS8266 & send it to the H bridges
while (Serial3.available() < num_in_buff){}
if (Serial3.available()) {
// read the incoming bytes
// in_buff[0] - direction flags
// in_buff[1] - PWM
Serial.println(".......");
Serial.println("In from ESP8266");
for (int i = 0; i < num_in_buff; i++){
in_buff[i] = Serial3.read();
Serial.println(in_buff[i]);
}
Serial.println(".......");
}
// Set direcions on H bridges
Serial.println("Direction pins");
for (int i = 0; i < num_dir_pins; i++)
{
digitalWrite(dir_pins[i], bitRead(in_buff[0], i));
Serial.print("pin ");
Serial.print(dir_pins[i]);
Serial.print(" : ");
Serial.print(digitalRead(dir_pins[i]));
Serial.println();
}
// PWM to motors
for (int i = 0; i < num_pwm; i++)
{
SoftPWMSet(pwm_out[i], in_buff[1]);
}
}
在PC端,我有一些Python代码被设置为WebSocket客户端,该客户端从终端接收用户输入并将其传输到ESP芯片。
motor_control_WiFi.py
"""
Motor control over WiFi using Wemos EPS8266 & Mega board
Motor H-bridge direction flags
Both forwards - b'111001, d'57, ASCII 9
Both backwards - b'110110, d'54, ASCII 6
Clockwise (right) - b'111010, d'58, ASCII :
A/Clock (left) - b'110101, d'53, ASCII 5
"""
from ws4py.client.threadedclient import WebSocketClient
import time, requests
import struct
esp8266host = "ws://192.168.1.84:81/"
class DummyClient(WebSocketClient):
def opened(self):
print("Websocket open")
def closed(self, code, reason=None):
print("Connexion closed down", code, reason)
def received_message(self, m):
print(m)
if __name__ == '__main__':
try:
ws = DummyClient(esp8266host)
ws.connect()
print("Ready !")
direction = ""
while direction != "q":
direction = input("Direction: ")
if direction == "f":
payload = "9"
if direction == "b":
payload = "6"
if direction == "r":
payload = ":"
if direction == "l":
payload = "5"
ws.send(payload)
time.sleep(.20)
pwm_out = int(input("PWM: "))
pwm_out = struct.pack('<B', pwm_out)
ws.send(pwm_out)
time.sleep(.20)
print("Finished, close Websocket connexion now and exit script")
ws.send("0:0")
ws.close()
exit()
except KeyboardInterrupt:
ws.send("0:0")
ws.close()
一切正常。因此,我的下一步是制作一个Android应用来执行我的Python代码所执行的操作。我正在使用okhttp3
库,并将implementation 'com.squareup.okhttp3:okhttp:3.6.0'
添加到了Gradle构建文件中,并为清单添加了Internet权限。
MainActivity.java
package qdivision.org.websocketexample;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
public class MainActivity extends AppCompatActivity {
private Button start;
private TextView output;
private OkHttpClient client;
private final class EchoWebSocketListener extends WebSocketListener {
private static final int NORMAL_CLOSURE_STATUS = 1000;
@Override
public void onOpen(WebSocket webSocket, Response response) {
//webSocket.send("l");
webSocket.send(ByteString.decodeHex("23"));
webSocket.send(ByteString.decodeHex("32"));
webSocket.close(NORMAL_CLOSURE_STATUS, "Goodbye !");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
output("Receiving : " + text);
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
output("Receiving bytes : " + bytes.hex());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(NORMAL_CLOSURE_STATUS, null);
output("Closing : " + code + " / " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
output("Error : " + t.getMessage());
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.start);
output = (TextView) findViewById(R.id.output);
client = new OkHttpClient();
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
start();
}
});
}
private void start() {
Request request = new Request.Builder().url("ws://192.168.1.84:81").build(); //"ws://echo.websocket.org"
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket ws = client.newWebSocket(request, listener);
client.dispatcher().executorService().shutdown();
}
private void output(final String txt) {
runOnUiThread(new Runnable() {
@Override
public void run() {
output.setText(output.getText().toString() + "\n\n" + txt);
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="qdivision.org.websocketexample.MainActivity">
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Start !"
android:layout_marginTop="40dp"
android:textSize="17sp"/>
<TextView
android:id="@+id/output"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/start"
android:layout_centerHorizontal="true"
android:textSize="16sp"
android:layout_marginTop="30dp"/>
</RelativeLayout>
部署此程序后,我没有任何连接错误。发送的字节将回显到显示器,并且客户端无错误地断开连接。但是我没有通过Arduino串行监视器反馈任何东西已发送!
这里缺少什么?如果未发送/接收字节,怎么会没有连接错误?
编辑#1 我从Termux命令行在Android设备上运行了Python代码。代码运行,说插座是打开的,让我输入方向和PWM,但串行监视器仍然没有输入。
编辑#2 我可以使用Termux从Android设备ping ESP8266,且丢包率为0,但Python代码或应用仍未发送任何数据。
编辑#3 现在,Python代码可通过Android设备上的Termux命令行运行(不知道我如何进行任何更改,现在就可以正常使用!!! ??)。基于okhttp3
的应用程序仍然不发送任何数据。