Communication from PySerial to Arduino: corrupted data - python

I need to send orders from a python code (computer) to an Arduino using PySerial via USB. The orders are strings of coma separated values, ended with a termination line character, i.e. "199,8,0,1,12345,0,0\n". The maximum size for an order is 32 bytes.
Here is the code used to send 10 times the same order from python to an Arduino (for debugging purpose).
import serial
ser = serial.Serial('/dev/cu.usbmodemFA141', 57600)
for i in range(10):
ser.write("199,8,0,1,12345,0,0\n")
On the Arduino side, the order is received, processed, and reformulated using this code:
char c = 0;
int it = 0;
bool newData = false;
String lastMessage;
String orderNumber, slaveNumber, singleOrReturn, order, orderComplement, valueI, valueII;
void saveSubStr(String subStr, int iterator){
switch (iterator) {
case 1: orderNumber = subStr; break;
case 2: slaveNumber = subStr; break;
case 3: singleOrReturn = subStr; break;
case 4: order = subStr; break;
case 5: orderComplement = subStr; break;
case 6: valueI = subStr; break;
case 7: valueII = subStr; break;
default: break; // it might be that some bugs leads the code here
}
}
void formulateLastMessage(){
lastMessage = orderNumber+","+slaveNumber+","+singleOrReturn+","+order+","+orderComplement+","+valueI+","+valueII+"\n";
}
void setup() {
Serial.begin(57600);
delay(1000);
}
void loop() {
it = 0;
while (Serial.available()){
c = Serial.read();
if (c!= '\n'){
if (c != ','){
subStr += c;
}
else {
it ++;
saveSubStr(subStr, it);
subStr = ""
}
}
else {
it ++;
saveSubStr(subStr, it);
subStr = "";
newData = true;
it = 0;
}
}
if (newData) {
formulateLastMessage();
}
newData = false;
}
If I send the same order from python 10 time for instance, here are the values I get for the global variable lastMessage in the Arduino:
199,8,0,1,12345,0,0
199,8,0,1,12345,0,0
199,8,0,1,12345,0,0
0,1,12345,0,0,0,0
199,8,0,1,12345,0,0
199199,8,0,1,12345,0,0
12345,0,0,1,12345,0,0
199,8,0,1,12345,0,0
199,8,0,1,12345,0,0
I don't understand why most of the time I receive the data correctly, but sometime the string order is broken. Does anyone has an idea what could cause this problem?

Related

Trying to program ESP32 with manual switch feedback

i want to make a program where i can manage appliances using MQTT messages as well as i want to take feedback using normal switches, i tried the following code but in that case switch one and relay on is operating as expected but switch2 & switch 3 are getting called in loop and switch 2 is automatically getting converted from 0 to 1 and hence if condition is getting verified and its getting in loop, please help
#include <WiFi.h>
#include <PubSubClient.h>
#include "ArduinoJson.h"
#define relayOne 15
#define switchOne 32
#define relayTwo 2
#define switchTwo 35
#define relayThree 4
#define switchThree 34
#define relayFour 22
#define switchFour 39
const char* ssid = "*******";//replace this with your wifi access point
const char * password = ""*******";//"; //replace with your wifi password
const char * host = "*.*.*.*"; //IP address of machine on which broker is installed
const int port = 1883;
const char * mqttUser = "user";
const char * mqttPassword = "user";
WiFiClient espClient;
PubSubClient client(espClient);
StaticJsonBuffer < 55 > jsonBuffer;
void callback(char * topic, byte * payload, unsigned int length) {
Serial.print("Message received in topic: ");
Serial.print(topic);
Serial.print(" length is:");
Serial.println(length);
Serial.print("Data Received From Broker:");
String messageTemp;
for (int i = 0; i < length; i++) {
messageTemp += (char) payload[i];
}
//Serial.println(messageTemp);
const size_t capacity = JSON_OBJECT_SIZE(2) + 20;
DynamicJsonBuffer jsonBuffer(capacity);
//const char* json = "{\"pin\":14,\"value\":1}";
const char * json = messageTemp.c_str();
JsonObject & root = jsonBuffer.parseObject(json);
int pin = root["pin"];
int value = root["value"];
Serial.println(pin);
Serial.println(value);
digitalWrite(pin, value);
}
void setup() {
Serial.begin(115200);
pinMode(relayOne, OUTPUT);
pinMode(switchOne, INPUT_PULLUP);
pinMode(relayTwo, OUTPUT);
pinMode(switchTwo, INPUT_PULLUP);
pinMode(relayThree, OUTPUT);
pinMode(switchThree, INPUT_PULLUP);
pinMode(relayFour, OUTPUT);
pinMode(switchFour, INPUT_PULLUP);
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi..");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
yield();
}
Serial.println("Connected to the WiFi network");
client.setServer(host, port);
client.setCallback(callback);
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ESP8266Client", mqttUser, mqttPassword)) {
Serial.println("connected to MQTT broker");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(500);
}
}
Serial.println("ESP32 AS SUBSCRIBER");
client.subscribe("IOT"); //topic name="Sub"
}
void MQTTPOST(int pin, int value)
{
Serial.println("in mqttpost");
//payload formation begins here
String payload ="{";
payload +="\"Pin\":"; payload +=pin; payload +=",";
payload +="\"Value\":"; payload +=value;
payload +="}";
char attributes[1000];
payload.toCharArray( attributes, 1000 );
client.publish("IOT1", attributes); //topic="Pub" MQTT data post command.
Serial.println( attributes );
Serial.println("");
}
int switchOneValue = 0;
int switchTwoValue = 0;
int switchThreeValue = 0;
int switchFourValue = 0;
void loop() {
client.loop();
int valueSwitchOne = digitalRead(switchOne);
Serial.println(valueSwitchOne);
Serial.println(switchOneValue);
if(valueSwitchOne == 0 && switchOneValue == 0){
digitalWrite(relayOne, 1);
switchOneValue = 1;
MQTTPOST(relayOne, 1);
Serial.println("on");
delay(200);
}else if(valueSwitchOne == 1 && switchOneValue == 1) {
digitalWrite(relayOne, 0);
switchOneValue = 0;
MQTTPOST(relayOne, 0);
Serial.println("off");
delay(200);
}
int valueSwitchTwo = digitalRead(switchTwo);
Serial.println(valueSwitchTwo);
Serial.println(switchTwoValue);
delay(1000);
if(valueSwitchTwo == 0 && switchTwoValue == 0){
digitalWrite(relayTwo, 1);
switchTwoValue = 1;
MQTTPOST(relayTwo, 1);
Serial.println("on2");
delay(200);
}else if(valueSwitchTwo == 1 && switchTwoValue == 1) {
digitalWrite(relayTwo, 0);
switchTwoValue = 0;
MQTTPOST(relayTwo, 0);
Serial.println("off2");
delay(200);
}
int valueSwitchThree = digitalRead(switchThree);
if(valueSwitchThree == 0 && switchThreeValue == 0){
digitalWrite(relayThree, 1);
switchThreeValue = 1;
MQTTPOST(relayThree, 1);
Serial.println("on");
delay(200);
}else if(valueSwitchThree == 1 && switchThreeValue == 1) {
digitalWrite(relayThree, 0);
switchThreeValue = 0;
MQTTPOST(relayThree, 0);
Serial.println("off");
delay(200);
}
}
here is a quote from documentation on esp32:
Appendix A – ESP32 Pin Lists
A.1. Notes on ESP32 Pin Lists
Table 24: Notes on ESP32 Pin Lists
GPIO pins 34-39 are input-only. These pins do NOT feature an output
driver or internal pull-up/pull-down circuitry.
digitalRead() can return arbitrary value for those pins because there are no built-in pull-up resistors there - they are effectively dangling in the air.
It means that following code CAN NOT WORK without external pull-up resistors:
#define switchTwo 35
#define switchThree 34
#define switchFour 39
pinMode(switchTwo, INPUT_PULLUP); // THIS DOES NOT WORK for GPIOs: 34-39!!!
pinMode(switchThree, INPUT_PULLUP); // THIS DOES NOT WORK for GPIOs: 34-39 !!!
pinMode(switchFour, INPUT_PULLUP); // THIS DOES NOT WORK for GPIOs: 34-39 !!!
// unpredictable values are here when button is not pressed
int valueSwitchTwo = digitalRead(35);
int valueSwitchThree = digitalRead(34);
Solution:
either use different pins for the switches
or add real hardware resistors into your schematics

How to send a decimal number from python to arduino

i am trying to send a decimal number from python to arduino, the problems is data is sent in an other type (i don't know which one maybe binary), so i did not get the desired response!
here is my arduino code
void setup() {
// put your setup code here, to run once:
pinMode(10, OUTPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
char k = Serial.read();
if (k > 500) {
analogWrite(10, 255);
delay(1000);
}
if (150 < k < 500) {
analogWrite(10, 128);
}
else if (k < 150) {
analogWrite(10, 0);
delay(1000);
}
Serial.print(k);
}
}
& here is python code
import serial
import struct
arduinoData = serial.Serial('com3',9600)
data = 0
while(1==1):
serialcmd = input("serial command: ")
arduinoData.write (struct.pack('>B',serialcmd))
data = arduinoData.readline()
print(data)

Memory issue with ctypes and multiprocessing in Python

I have a python code which uses ctypes to do some heavy lifting. It also uses multiprocessing. After realising I'd made an engineering (rather than programming) mistake in some code, I updated the c sub function and I now get a
WindowsError: exception: access violation reading 0x09AA1000
which only occurs with the new c code and when multiprocessing is enabled. The address at the end is different every time, and the code will run succesfully for varying lengths of time before throwing the error. Here is the old (working) c code:
void rfnies(double *array_ext, int tot_num, double *array_out) {
double *pr, *po, a[16384], ampl, mean;
int index, j, cNr;
pr = array_ext;
po = array_out;
j = -1;
cNr = 1;
for (index=0; index<tot_num; index++) {
a[++j]=*pr++;
while ( (j >= 2) && (fabs(a[j-1]-a[j-2]) <= fabs(a[j]-a[j-1])) ) {
ampl=fabs( (a[j-1]-a[j-2])/2 );
switch(j)
{
case 0: { break; }
case 1: { break; }
case 2: {
mean=(a[0]+a[1])/2;
a[0]=a[1];
a[1]=a[2];
j=1;
if (ampl > 0) {
*po++=ampl;
*po++=mean;
*po++=0.50;
}
break;
}
default: {
mean=(a[j-1]+a[j-2])/2;
a[j-2]=a[j];
j=j-2;
if (ampl > 0) {
*po++=ampl;
*po++=mean;
*po++=1.00;
cNr++;
}
break;
}
}
}
}
for (index=0; index<j; index++) {
ampl=fabs(a[index]-a[index+1])/2;
mean=(a[index]+a[index+1])/2;
if (ampl > 0){
*po++=ampl;
*po++=mean;
*po++=0.50;
}
}
return;
}
And here is the new code which causes the access violation. I can't see what the problem is and it is driving me insane!
void rf3(double *array_ext, int tot_num, double *array_out) {
double *pr, *po, E[tot_num], ampl, mean, XX, YY;
int index, j, cNr, nn;
pr = array_ext;
po = array_out;
j=0;
nn = -1;
while (j<=tot_num){
nn++;
E[nn] = *(pr+j);
j++;
while (nn >= 2){
XX = fabs(E[nn] - E[nn - 1]);
YY = fabs(E[nn - 1] - E[nn - 2]);
if (XX<YY){break;}
ampl=YY/2.0;
mean=(E[nn - 1] + E[nn - 2])/2.0;
*po++=ampl;
*po++=mean;
*po++=1.00;
nn = nn - 2;
E[nn] = E[nn + 2];
}
}
}
The fact that it will run for varying lengths of time suggests that something is being left in memory and one of the other processes is trying to read the same memory. I can't post a working example as I can't even reproduce it in the full code on some runs!
Any help will be much appreciated.

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() { }

Rate-limiting in python/arduino client/server communication

I'm trying to make a python client communicate with an arduino server. The python client asks the server to take a measurement from the sonar, and then server just sends a confirmation message and then takes the message.
The client:
client.py
import socket
import time
while True:
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("192.168.0.250", 10220))
data = "GET\nSONAR\n\n"
print 'send to server: ' + data
client_socket.send(data)
receive = client_socket.recv(2048)
print receive
client_socket.close()
time.sleep(0.1)
except Exception as msg:
print msg
and the server:
server.ino
#include <avr/wdt.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SoftwareSerial.h>
//localClient parameters, for sending data to the server.
byte mac[] = {0x90, 0xA2, 0xDA, 0x0F, 0x03, 0x58};
byte ip[] = {192,168,0,250};
byte server[] = {192, 168, 0, 100};
int serverPort = 8220;
//Server parameters, for acting like a server.
int pollPort = serverPort + 2000;
EthernetServer pollServer = EthernetServer(pollPort);
//char inString[32]; // string for incoming serial data
//sonar stuff
String content_string;
int NUM_SONARS = 1;
int sonarPin[] = {2, 3, 4, 5};
int triggerPin = 6;
int sonarThreshold = 12.0;
int sonarState[] = {0, 0, 0, 0};
long pulse;
int numPulses = 3;
int pulseArray[] = {0,0,0,0,0};
int filteredMode = 0;
float time;
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
wdt_enable(WDTO_8S);
pollServer.begin();
for(int i = 0; i < NUM_SONARS; i++) {
pinMode(sonarPin[i], INPUT);
}
pinMode(triggerPin, OUTPUT);
digitalWrite(triggerPin, LOW);
time = 0;
}
void loop() {
wdt_reset();
time = millis();
EthernetClient pollClient = pollServer.available();
if (pollClient) {
boolean currentLineIsBlank = true;
String receivingString = "";
while (pollClient.connected()) {
//while the socket is open
if(pollClient.available()) {
//and there is something to read on the port, then read the available characters
char c = pollClient.read();
receivingString += c;
if (c == '\n' && currentLineIsBlank) {
Serial.print("String received -- ");
Serial.print(receivingString);
Serial.print("at ");
Serial.println(time);
pollClient.println("Received message.");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// parse the incoming data
String command = split(receivingString,'\n',0);
String payload = split(receivingString,'\n',1);
String key = split(payload,'=',0);
String value = split(payload,'=',1);
//PARSE THE KEY AND VALUE NOW
if(command == "GET") {
//if I received a GET command, send a response to the client.
if(key == "SONAR") {
pingSonars();
}
}
}
String split(String data, char delimiter, int index) {
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==delimiter || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void isort(int *a, int n) {
for (int i = 1; i < n; ++i) {
int j = a[i];
int k;
for (k = i - 1; (k >= 0) && (j < a[k]); k--) {
a[k + 1] = a[k];
}
a[k + 1] = j;
}
}
int mode(int *x,int n){
int i = 0;
int count = 0;
int maxCount = 0;
int mode = 0;
int bimodal;
int prevCount = 0;
while(i<(n-1)){
prevCount=count;
count=0;
while(x[i]==x[i+1]){
count++;
i++;
}
if(count>prevCount&count>maxCount){
mode=x[i];
maxCount=count;
bimodal=0;
}
if(count==0){
i++;
}
if(count==maxCount){//If the dataset has 2 or more modes.
bimodal=1;
}
if(mode==0||bimodal==1){//Return the median if there is no mode.
mode=x[(n/2)];
}
return mode;
}
}
void printArray(int *a, int n) {
for (int i = 0; i < n; i++)
{
Serial.print(a[i], DEC);
Serial.print(' ');
}
Serial.println();
}
void pingSonars() {
digitalWrite(6, HIGH);
for(int i = 0; i < NUM_SONARS; i++) {
for(int j = 0; j < numPulses; j++) {
pulse = pulseIn(sonarPin[i], HIGH);
pulseArray[j] = pulse/147; //convert to inches -- 147 uS per inches
delay(5);
}
isort(pulseArray, numPulses);
filteredMode = mode(pulseArray,numPulses);
//printArray(pulseArray,numPulses);
Serial.print("Filtered distance for Sonar ");
Serial.print(i);
Serial.print(": ");
Serial.println(filteredMode);
if((filteredMode < sonarThreshold) && !sonarState[i]) {
//if we are closer than the threshold and previously were not, this is a rising edge:
Serial.print("Sonar ");
Serial.print(i);
Serial.println(" triggered!");
sonarState[i] = 1;
}
else if (filteredMode > sonarThreshold && sonarState[i]) {
//if we are greater than the threshold and previously were, this is a falling edge:
Serial.print("Sonar ");
Serial.print(i);
Serial.println(" falling!");
sonarState[i] = 0;
}
}
}
The client sends requests at about a 100 millisecond interval, but the server seems to be able to respond much slower than that -- maybe at 2-3 times per second. What's limiting the rate of communication? Is it possible that the serial printouts are actually limiting it? Or does it have to do with how I'm opening/closing/listening to the port in the server code?
thanks for your help!

Categories