Arduino takes 1-2 seconds to process serial input, how can I speed this up? - python

I am almost entirely new to arduino/C++ so forgive me if this seems stupid. I am using a python program that detects faces in the camera frame and sends the x and y coordinate of the face to the arduino via serial (I have not implemented any code to deal with y yet). This works so long as I limit how often it sends the coordinates, however if they are sent too fast, the arduino seems to simply stop responding. My hypothesis as to why is that it is not able to read the data fast enough and it is lost before it can be processed. I know ultimately 1-2 seconds is not that big of a deal but unfortunately for me I'm a bit of a perfectionist and a 1-2 second delay really gets on my nerves.
As for the python script:
while True:
# Facial recognition stuff here
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
print(x, y)
if i == 30:
coord = f'{x} {y}'
arduinoData.write(coord.encode())
i = 0
i += 1
and the code running on my arduino:
#include <Servo.h>
Servo myservo;
int gLED = 2;
int rLED = 3;
String words[2];
void setup() {
Serial.begin(115200);
pinMode(rLED, OUTPUT);
pinMode(gLED, OUTPUT);
myservo.attach(8);
myservo.writeMicroseconds(1450);
}
void loop() {
while (Serial.available() > 0) {
String input = Serial.readStringUntil('\r');
int spaceIndex = input.indexOf(' ');
if (spaceIndex != -1) {
words[0] = input.substring(0, spaceIndex);
words[1] = input.substring(spaceIndex + 1);
} else {
words[0] = input;
words[1] = "";
}
int pos1 = words[0].toInt();
if (pos1 > 300) {
digitalWrite(gLED, HIGH);
digitalWrite(rLED, LOW);
myservo.writeMicroseconds(1400);
}
if (pos1 < 240) {
digitalWrite(rLED, HIGH);
digitalWrite(gLED, LOW);
myservo.writeMicroseconds(1510);
}
if (pos1 >= 240 && pos1 <= 300) {
digitalWrite(gLED, LOW);
digitalWrite(rLED, LOW);
myservo.writeMicroseconds(1450);
}
}
}
Does anyone have any tips on how I can speed up the response? Is it slow because of something stupid that I'm doing or is there maybe a different protocol that is faster? I briefly looked into i2c but I'm not sure if it's a better option.

#Roman is true. May be better to monitor the serial at regular interval and get data as they arrive:
unsigned long timer;
void loop() {
if (millis() - timer > 200) { //tick every 200mS
timer=millis();
String input = serialListen();
// etc.....
}
}
String serialListen() {
String SerMsg = "";
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
if (inChar == '\n') { //end char
return SerMsg;
} else {
// add it to the inputString:
SerMsg += inChar;
}
}
}

Related

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)

how to receive only 1 single value form python to arduino

I'm new to this!!
python code
i = results[1]
i *= 100
if i >= 75:
print('Recognised as owner!')
arduino.write(str.encode('1'))
else:
print('not matches')
serial monitor
111111111111111111111111111111111111111111111111111111111111111111...
Arduino code
#include <Servo.h>
Servo servo;
char value1;
void setup()
{
servo.attach(8);
servo.write(0);
Serial.begin(9600);
}
void loop()
{
if(Serial.available() > 0)
value1 = Serial.read();
Serial.print(value1);
if (value1 == '1') {
digitalWrite(13, HIGH);
servo.write(90);
delay(100);
}
for (int i = 10; i > 0; i--){
Serial.println("go inside!!, hurry up !!");
delay(1000);
}
servo.write(0);
Serial.println("door is closed");
delay(1000);
}
question:
this program can handle the door system based on face recognition
the Arduino takes the value of "1" over and over. so later servo always looping every 10 s. because the program cant handles 1 single value.
my goal is to make sure that the Arduino only get 1 single input. so later the servo is running well
ty

Stepper motor connected with arduino is not listening to the initial state send by python

I'm sending data from a python script to my Arduino board. I can succesfully communicate with the board. Based on the data send by the python, the stepper motor connected should either move forward or backward. If python is sending '0' the motor should rotate forward and if python is sending '1' then the motor should rotate backward. When i type '0' in the serial monitor the stepper moves forward and on '1' stepper moves backward. But when python is sending data at first, stepper is not moving forward or backward. Only when the state change happens(if state changes from '1' to '0' or '0' to '1'), the stepper either moves forward or backward. I tried to see if data is send from python, the arduino is receiving data from python. Suggestion will be heavily appreciated.
Ardunio code
static const int SELENOID_PIN = 2;
static const int OPEN = '0';
static const int CLOSE = '1';
static const int STEPS = 30;
static const int delaylegnth = 10;
void setup() {
//establish motor direction toggle pins
pinMode(12, OUTPUT); //CH A -- HIGH = forwards and LOW = backwards???
pinMode(13, OUTPUT); //CH B -- HIGH = forwards and LOW = backwards???
//establish motor brake pins
pinMode(9, OUTPUT); //brake (disable) CH A
pinMode(8, OUTPUT); //brake (disable) CH B
Serial.begin(9600);
while(!Serial){}//wait until the serial port is connected
Serial.write('1');
pinMode(SELENOID_PIN ,OUTPUT);
}
void polarisingA()
{
digitalWrite(9, LOW); //ENABLE CH A
digitalWrite(8, HIGH); //DISABLE CH B
digitalWrite(12, HIGH); //Sets direction of CH A
analogWrite(3, 255); //Moves CH A
delay(delaylegnth);
}
void polarisingB()
{
digitalWrite(9, HIGH); //DISABLE CH A
digitalWrite(8, LOW); //ENABLE CH B
digitalWrite(13, HIGH); //Sets direction of CH B
analogWrite(11, 255); //Moves CH B
delay(delaylegnth);
}
void polarisingC()
{
digitalWrite(9, LOW); //ENABLE CH A
digitalWrite(8, HIGH); //DISABLE CH B
digitalWrite(12, LOW); //Sets direction of CH A
analogWrite(3, 255); //Moves CH A
delay(delaylegnth);
}
void polarisingD()
{
digitalWrite(9, HIGH); //DISABLE CH A
digitalWrite(8, LOW); //ENABLE CH B
digitalWrite(13, LOW); //Sets direction of CH B
analogWrite(11, 255); //Moves CH B
delay(delaylegnth);
}
void stepRight()
{
polarisingA();
polarisingB();
polarisingC();
polarisingD();
}
void stepLeft();
{
polarisingD();
polarisingC();
polarisingB();
polarisingA();
}
void spin(bool dir,int tickes)
{
//Serial.print(dir);
for(int i =0 ; i < tickes; i++)
{
if(dir == true)//right
{
stepRight();
}
else
{
stepLeft();
}
}
}
void loop() {
if(Serial.available() > 0)
{//there is incoming data form the serial and serial is setted up
handleData();
}
delay(5);
}
void handleData()
{
unsigned char a = Serial.read();
Serial.write("new data");
int action = -1;
if(a == OPEN)
{
action = 1;
}
else if(a == CLOSE)
{
//Serial.print("close");
action = 0;
}
if (action != -1)
{
bool dir = action == 1 ? HIGH : LOW ;
spin(dir,STEPS);
digitalWrite(SELENOID_PIN ,action ? HIGH : LOW );
Serial.write(a);//ack
}
}
Python code(Part only sending data to arduino):
def openthedoor(set_accepted_list,set_list_ant_id,set_forbidden_list,set_accepted_list_frozen):
if(((len(set_accepted_list)) >0) & (set_forbidden_list == set()) & ((set_accepted_list_frozen == None) or ((set_accepted_list_frozen & set_accepted_list)== set_accepted_list))):
print"yes,open the gate"
use_step(1)
else:
print"no,close the gate"
use_step(0)
def establishing_connection():
#serial.Serial("COM1",9600)
print ser.read();
last_action = -1
def use_door(activate):
global last_action
#global serial
if(last_action != activate):
send_data(activate)
last_action = activate
def send_data(data):
global ser
try:
if(ser == None):
ser = serial.Serial("COM1",9600,timeout = 0)
print "reconnect"
if(data==0):
ser.write('0')
print "python is telling the arduino to move stepper forward"
else:
ser.write('1')
print "python is telling the ardunio to move stepper backward"
time.sleep(0)
except IOError:
time.sleep(0)
ser.close()
#continue
ser = None
print "after read"

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