Slow communication between Wemos and Raspberry via WiFi - python

I have got PTZ controller, Wemos D1 Mini (based on ESP8266-12F) and Raspberry and I want read data from PTZ using Wemos and send it via wifi to Raspberry. This is my code on RPi:
import socket
s = socket.socket()
# host = socket.gethostname()
host = '192.168.0.26'
port = 9999
s.connect((host, port))
try:
while True:
response1 = s.recv(1024).decode("utf-8")
print(response1)
except KeyboardInterrupt:
s.close()
And my code on Wemos:
#include "ESP8266WiFi.h"
int msg = 0;
String str = String(0,HEX);
bool startReading = false;
String command = "";
const char *ssid = "MyName";
const char *password = "MyPassword";
WiFiServer wifiServer(9999);
void setup() {
Serial.begin(9600);
Serial.setDebugOutput(true);
for(uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] BOOT WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
delay(1000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting..");
}
Serial.print("Connected to WiFi. IP:");
Serial.println(WiFi.localIP());
wifiServer.begin();
}
void loop() {
WiFiClient client = wifiServer.available();
if (client) {
while (client.connected()) {
msg = Serial.read();
if (msg != -1) {
command = String(msg,HEX);
client.print(command);
}
delay(1);
}
client.stop();
Serial.println("Client disconnected");
}
}
Everything work fine, reaading data from PTZ is immediate but sending data to RPi is slow, I can see significant delay. Reducing the distance from the router does not improve the situation. I tried use #include <WebSocketsServer.h> but this libary is even worse. My question is how I can increase communication speed? Will putting the server on rpi instead of wemos help? Are there any more suitable libraries that I could use?

Related

Two way communication between Unity and Python

So I want to send and receive from/to Unity and Python in the same run.
I have the following components for the communication.
TCPSendPipe - Sends data from Unity to Python
TCPListePipe - Receives data from Python
Python Script - Send (uses socket.connect) and Receive (uses socket.bind)
At the moment I can only use one at a time either,
TCPSendPipe with Python receive or,
TCPListenPipe with Python send
Following are the scripts:
TCPSendPipe.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using UnityEngine;
public class TCPSendPipe : MonoBehaviour
{
public String Host = "localhost";
public Int32 Port = 55000;
TcpClient mySocket = null;
NetworkStream theStream = null;
StreamWriter theWriter = null;
public GameObject robot;
public Vector3 robPos;
// Start is called before the first frame update
void Start()
{
robot = GameObject.Find("robot");
mySocket = new TcpClient();
if (SetupSocket())
{
Debug.Log("socket is set up");
}
}
// Update is called once per frame
void Update()
{
robPos = robot.transform.position;
Debug.Log(robPos);
if (!mySocket.Connected)
{
SetupSocket();
}
sendMsg();
}
public void sendMsg()
{
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
//Byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes("yah!! it works");
Byte[] sendBytes = procData();
mySocket.GetStream().Write(sendBytes, 0, sendBytes.Length);
}
public bool SetupSocket()
{
try
{
mySocket.Connect(Host, Port);
Debug.Log("socket is sent");
return true;
}
catch (Exception e)
{
Debug.Log("Socket error: " + e);
return false;
}
}
public Byte[] procData()
{
Byte[] bytes = new Byte[12]; // 4 bytes per float
Buffer.BlockCopy( BitConverter.GetBytes( robPos.x ), 0, bytes, 0, 4 );
Buffer.BlockCopy( BitConverter.GetBytes( robPos.y ), 0, bytes, 4, 4 );
Buffer.BlockCopy( BitConverter.GetBytes( robPos.z ), 0, bytes, 8, 4 );
return bytes;
}
private void OnApplicationQuit()
{
if (mySocket != null && mySocket.Connected)
mySocket.Close();
}
}
TCPListenPipe.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Globalization;
using System.Net.Sockets;
using UnityEngine;
public class TCPListenPipe : MonoBehaviour
{
public String Host = "localhost";
public Int32 Port = 55000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
private TcpListener listener = null;
private TcpClient client = null;
private NetworkStream ns = null;
string msg;
// Start is called before the first frame update
void Awake()
{
listener = new TcpListener(localAddr, Port);
listener.Start();
Debug.Log("is listening");
if (listener.Pending())
{
client = listener.AcceptTcpClient();
Debug.Log("Connected");
}
}
// Update is called once per frame
void Update()
{
if (client == null)
{
if (listener.Pending())
{
client = listener.AcceptTcpClient();
Debug.Log("Connected");
}
else
{
return;
}
}
ns = client.GetStream();
if ((ns != null) && (ns.DataAvailable))
{
StreamReader reader = new StreamReader(ns);
msg = reader.ReadToEnd();
float data = float.Parse(msg, CultureInfo.InvariantCulture);
Debug.Log(data);
}
}
private void OnApplicationQuit()
{
if (listener != null)
listener.Stop();
}
}
Python Script
import socket
import struct
import numpy as np
class comm(object):
TCP_IP = '127.0.0.1'
TCP_PORT = 55000
BUFFER_SIZE = 12 # Normally 1024, but we want fast response
conn = []
addr = []
s = []
def connect(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((self.TCP_IP, self.TCP_PORT))
self.s.listen(1)
self.conn, self.addr = self.s.accept()
print ('Connection address:', self.addr)
def receive(self):
byte_data = self.conn.recv(self.BUFFER_SIZE)
pos_data = np.array(np.frombuffer(byte_data, dtype=np.float32));
#print("bytes data:", byte_data)
print ("received data:", pos_data)
#conn.close()
return(pos_data)
def send(self):
cable_length = 25.123
MESSAGE = str(cable_length)
#MESSAGE = cable_length.tobytes()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.TCP_IP, self.TCP_PORT))
#s.send(MESSAGE)
s.send(MESSAGE.encode())
s.close()
return(MESSAGE)
So in order to send data from Unity to Python, I attach the TCPSendPipe.cs to the scene and within python script I just call receive after connecting.
comm_cl = comm()
comm_cl.connect()
while True:
data = comm_cl.receive()
Whereas to send data from Python to Unity, I have to detach TCPSendPipe.cs and attach TCPListenPipe.cs to the scene and within python script I just call send (without connect since connect has socket.bind).
send_data = aa.send()
My purpose is to have a 2 way communication between Unity and Python.
Can I use 2 different sockets to send and receive?, Is it even possible to create and connect to 2 different sockets at the same time?
Any suggestions or ideas on achieveing this is greatly appreciated.
Thank You.
Can I use 2 different sockets to send and receive?, Is it even possible to create and connect to 2 different sockets at the same time?

What is causing connection error 111 refused to connect

I am trying to have python connect to a tcp server written in C, the server and the client python script are running on the same machine (Linux). The C code compiles and runs without error. Yes they are using the same port of 27001. There can be no use of 3rd party libraries. Python says that the issue is on client.connect((HOST,PORT)), I get no read out from the C side of things. I've tried changing the ports, I know that these ports are unused as they are ports for many steam games, none of which are running while the server is online. I ran sudo netstat -ntlp in the terminal and I do not see my server, nor do I see the process id, or the port that I bound the server too.
Python:
import socket
def clientTest():
HOST=socket.gethostbyname("localhost")
print(HOST)
PORT=27001
client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST,PORT))
for i in range(5):
toSend="Data "
toSend+=str(i)
client.send(toSend)
print("Sent data")
time.sleep(2)
resp=client.recv(1024)
print(resp)
clientTest()
C:
char* serverListen(server *s, int *bytesWritten){
int listenRet=listen(s->socketFd, maxConnections);
if(listenRet==0){
unsigned int clientLen;
s->incomingSocket=accept(s->socketFd, (struct sockaddr*)&s->clientIn, &clientLen);
if(s->incomingSocket<0){
printf("Server Listen problem\n\tAccept issue: %i\n", s->incomingSocket);
close(s->incomingSocket);
return NULL;
}
char *buffer=(char*)calloc(s->bufferSize, sizeof(char));
int bytesRead=read(s->incomingSocket, buffer, s->bufferSize-1);
if(bytesRead<0){
printf("Server Listen Problem\n\tRead issue: %i\n", bytesRead);
free(buffer);
close(s->incomingSocket);
return NULL;
}
#ifdef DEBUG
printf("Bytes read: %i\nMessage:\t%s\n", bytesRead, buffer);
#endif
int writeRet=write(s->incomingSocket, "Message recived", 16);
if(writeRet<0){
printf("Server Listen Problem\n\tWrite issue: %i\n", writeRet);
close(s->incomingSocket);
return NULL;
}
*bytesWritten=bytesRead;
close(s->incomingSocket);
return buffer;
}
return NULL;
}
void* singleThreadServerFunc(void *params){
server *s=(server*)params;
char *retData;
int bytesWritten;
while(s->serverShouldRun){
retData=serverListen(s, &bytesWritten);
if(bytesWritten>0){
printf("%s", retData);
}
free(retData);
}
return NULL;
}
server *initServer(int port){
server *out=(server*)calloc(1, sizeof(struct server));
out->socketFd=socket(AF_INET, SOCK_STREAM, 0);
if(out->socketFd<0){
printf("Server init problem\n\tsockFd is less than 0!\n");
freeServer(out);
return NULL;
}
int opts=1;
int sockOption=setsockopt(out->socketFd, SOL_SOCKET, SO_REUSEADDR, &opts, sizeof(opts));
if(sockOption<0){
printf("Server init problem\n\tSocket Option issue\n");
freeServer(out);
return NULL;
}
out->portNumber=port;
out->serverIn.sin_family=AF_INET;
out->serverIn.sin_addr.s_addr=INADDR_ANY;
out->serverIn.sin_port=htons(out->portNumber);
memset(&out->serverIn.sin_zero, 0, sizeof(char));
int bindRet=bind(out->socketFd, (struct sockaddr*)&out->serverIn, sizeof(out->serverIn));
if(bindRet<0){
printf("Server init problem\n\tBind issue %i\n", bindRet);
freeServer(out);
return NULL;
}
out->bufferSize=1024;
pthread_create(&out->serverThread, NULL, singleThreadServerFunc, out);
return out;
}
int main(){
server *s=initServer(DefaultPort);
if(s!=NULL){
while(1){
char c[2];
scanf("%1s",c);
if(c[0]=='q')
break;
}
freeServer(s);
}
return 0;
}
I found the answer, it was in singleThreadServerFunc I did not have s->serverShouldRun set to true

Handshake Issues Tornado Server and ESP32 Client

I am unable to establish a websocket connection. I use an esp32 as an Client and an Tornado Webserver as Host.
I can connect to the Host with Javascript, but I can also connect the esp32 to websocket.org.
Only the connection between the esp32 and the Tornado Server doesn't work.
ESP32 Code (Arduino IDE):
#include <WiFi.h>
#include <WebSocketClient.h> //By Markus Sattler
const char* ssid = "hadome";
const char* password = "12345678";
char path[] = "/ws";
char host[] = "192.168.178.29";
WebSocketClient webSocketClient;
WiFiClient client;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(5000);
if (client.connect(host, 3333)) {
Serial.println("Connected");
} else {
Serial.println("Connection failed.");
}
webSocketClient.path = path;
webSocketClient.host = host;
if (webSocketClient.handshake(client)) {
Serial.println("Handshake successful");
} else {
Serial.println("Handshake failed.");
}
}
void loop() {
String data;
if (client.connected()) {
webSocketClient.sendData("Info to be echoed back");
webSocketClient.getData(data);
if (data.length() > 0) {
Serial.print("Received data: ");
Serial.println(data);
}
} else {
Serial.println("Client disconnected.");
}
delay(3000);
}
Python Code Excerpt (Tornado):
class WSHandler(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True
def open(self):
pass
def on_message(self, message):
self.write_message(message)
def on_close(self):
log('[WS] Connection was closed.')
application = tornado.web.Application([(r'/ws', WSHandler)])
# Main program logic follows:
if __name__ == '__main__':
# Tornado Server
try:
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(3333)
http_client = tornado.httpclient.AsyncHTTPClient()
http_client.initialize(1)
log("Tornado Server started")
tornado.ioloop.IOLoop.current().spawn_callback(loop)
tornado.ioloop.IOLoop.instance().start()
except:
log("Exception triggered - Tornado Server stopped.")
finally:
pass
The ESP32 Program outputs:
.......
WiFi connected
IP address:
192.168.2.8
Connected
Waiting...
Handshake failed.
I am very confused because this javascript program works flawlessly (https://www.mischianti.org/2020/12/07/websocket-on-arduino-esp8266-and-esp32-client-1/):
var wsUri = "ws://192.168.178.29:3333/ws";
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function (evt) {
onOpen(evt)
};
websocket.onclose = function (evt) {
onClose(evt)
};
websocket.onmessage = function (evt) {
onMessage(evt)
};
websocket.onerror = function (evt) {
onError(evt)
};
}
Sincerely Hannes
PS: Sorry for my bad english
I solved the problem by using another library. (I use the Library of Markus Sattler)

Arduino serial size

I'm trying to send message to arduino via usb cable with python.
#!python3
import serial
import time
import api
import sys
api = api.API()
arduino = serial.Serial('COM3', 115200, timeout=.1)
time.sleep(2)
while api['IsOnTrack'] == True:
if api['Gear'] == 3:
arduino.write('pinout 13')
print "Sending pinon 13"
msg = arduino.read(arduino.inWaiting())
print ("Message from arduino: ")
print (msg)
time.sleep(2)
Arduino:
// Serial test script
int setPoint = 55;
String command;
void setup()
{
Serial.begin(115200); // initialize serial communications at 9600 bps
pinMode(13,OUTPUT);
}
void loop()
{
while(!Serial.available()) {
}
// serial read section
while (Serial.available())
{
if (Serial.available() >0)
{
char c = Serial.read(); //gets one byte from serial buffer
if(c == '\n')
{
parseCommand(command);
command = "";
}
else
{
command += c; //makes the string command
}
}
}
if (command.length() >0)
{
Serial.print("Arduino received: ");
Serial.println(command); //see what was received
}
}
void parseCommand(String com)
{
String part1;
String part2;
part1 = com.substring(0, com.indexOf(" "));
part2 = com.substring(com.indexOf(" ") +1);
if(part1.equalsIgnoreCase("pinon"))
{
int pin = part2.toInt();
digitalWrite(pin, HIGH);
}
else if(part1.equalsIgnoreCase("pinoff"))
{
int pin = part2.toInt();
digitalWrite(pin, LOW);
}
else
{
Serial.println("Wrong Command");
}
}
Python shell looks like this:
http://i.imgur.com/IhtuKod.jpg
Can I for example make the arduino read the message once and the clear the serial?
Or can you spot a clear mistake I have made?
While using just the Arduino IDE serial monitor. The led lights up when I write "pinon 13", this doesn't work while using python. Or when I send "pinout 13" message from serial monitor, it will tell me that it is a "Wrong Command", this also won't happen while using python.
Do you guys have any ideas how I should make the python send the message just once and not contiunously?
In your Python code, you will have to write/send a \n after the command for the Arduino to recognize.
serial.write('pinon 13\n'); should work; note though, that \n may yield different results on different systems (eg. Windows vs. Linux), so you may want to explicitly use the same ASCII code on the Arduino and on the PC.
In Python this should be chr(10) and on the Arduino you may use if(c == 10) if you want.

ArduinoPI Python - SERIAL CONNECTION LOST DATA

Intent: Control arduino uno from serial port
Tools:
https://github.com/JanStevens/ArduinoPi-Python
I got the server working on both my mac and my Model b+ Raspberry.
The browser behaves as shown in the picture below in both situations.
To me it looks like the server sent the message to Arduino successfully. But the data somehow gets lost on the way. The Arduino board resets every time I access the url in my browser. I googled and found that a 10uF capacitor between ground and reset pins would prevent the reset from happening. It did, but pin 3 won't go "HIGH". I got a LED+RESISTOR plugged on pin 3 and ground accordingly. I can see the Rx led blinking every time I access the url. So it makes me think that the Arduino is misunderstanding the command from my Flask sever.
OG Arduino code:
String cmd;
bool cmdRec = false;
void setup()
{
//Start the connection with the Raspberry Pi
Serial1.begin(115200);
// Start the connection with the Laptop, for debugging only!
//Serial.begin(115200);
}
void loop()
{
handleCmd();
}
void serialEvent1() {
while(Serial1.available() > 0) {
char inByte = (char)Serial1.read();
if(inByte == ':') {
cmdRec = true;
return;
} else if(inByte == '#') {
cmd = "";
cmdRec = false;
return;
} else {
cmd += inByte;
return;
}
}
}
void handleCmd() {
if(!cmdRec) return;
// If you have problems try changing this value,
// my MEGA2560 has a lot of space
int data[80];
int numArgs = 0;
int beginIdx = 0;
int idx = cmd.indexOf(",");
String arg;
char charBuffer[20];
while (idx != -1) {
arg = cmd.substring(beginIdx, idx);
arg.toCharArray(charBuffer, 16);
data[numArgs++] = atoi(charBuffer);
beginIdx = idx + 1;
idx = cmd.indexOf(",", beginIdx);
}
// And also fetch the last command
arg = cmd.substring(beginIdx);
arg.toCharArray(charBuffer, 16);
data[numArgs++] = atoi(charBuffer);
// Now execute the command
execCmd(data);
cmdRec = false;
}
// For advanced function like switch all the leds in RGB
void execCmd(int* data) {
switch(data[0]) {
case 101:
{
for(int i = 2; i < (data[1]*2)+1; i+=2) {
pinMode(data[i], OUTPUT);
analogWrite(data[i], data[i+1]);
}
}
break;
case 102:
{
pinMode(data[1], INPUT);
int sensor = analogRead(data[1]);
Serial1.println(sensor);
}
break;
case 103:
{
String result = "";
int sensor = 0;
for(int j = 2; j < data[1]+2; j++) {
pinMode(data[j], INPUT);
sensor = analogRead(data[j]);
result += String(sensor)+",";
}
Serial1.println(result);
}
break;
default:
{
pinMode(data[0], OUTPUT);
analogWrite(data[0], data[1]);
}
break;
}
}
It does not compile this way. So I uncommented the second Serial.begin line and deleted all the "Serial1." appearances on the code. I can't see no action on the arduino IDE serial when I test it on my mac.
As the code was written with an Arduino Mega that got 2 or 3 serial ports, void serialevent1() is triggered when there is communication going on the the MEGA's SERIAL1 port. Since I am working on the UNO, that only have 1 serial port, all i had to do was delete the "1" before the parenthesis and all worked as supposed.
void serialEvent() { }

Categories