In my project my goal is to establish two-way data exchange between Arduino and Raspberry Pi via serial interface. The Raspberry Pi sends the Arduino command to execute, Arduino sends the Raspberry Pi sensor readings (currently a random number).
Currently, the project includes two scripts for Raspberry Pi, written on Python, and a program for Arduino. The first script for Raspberry Pi using the URWID library organizes the graphical interface and command input, the second script is used to communicate with a serial port. The sources are given below. The result of the operation is quite satisfactory, but maybe somewhere I'm doing something wrong? Is this solution of the problem correct?
Arduino software:
#define SERIAL_SPEED 19200 // the speed of the serial port
#define READ_SENSOR_INTERVAL 1000UL // frequency of output to the serial port
int IN1 = 7;
int IN2 = 6;
int IN3 = 5;
int IN4 = 4;
int ENA = 9;
int ENB = 3;
char command = 'S';
char prevCommand = 'A';
int velocity = (4 + 1) * 10 + 100; // the fill factor of the PWM
unsigned long timer0 = 2000;
unsigned long timer1 = 0;
long randNumber;
long myflag = 0;
void setup() {
Serial.begin(SERIAL_SPEED);
pinMode (ENA, OUTPUT);
pinMode (IN1, OUTPUT);
pinMode (IN2, OUTPUT);
pinMode (ENB, OUTPUT);
pinMode (IN4, OUTPUT);
pinMode (IN3, OUTPUT);
}
void loop()
{
static unsigned long prevSensorTime = 0;
if (millis() - prevSensorTime > READ_SENSOR_INTERVAL) {
prevSensorTime = millis();
if (myflag == 1)
{
randNumber = random(300);
Serial.print(command);
Serial.println(randNumber);
}
}
if (Serial.available() > 0) {
timer1 = millis();
prevCommand = command;
command = Serial.read();
myflag = 1;
if (command != prevCommand) {
switch (command) {
case 'W':
// Вперёд
analogWrite(ENA, 0);
analogWrite(ENB, 0);
delay(20);
digitalWrite (IN2, LOW);
digitalWrite (IN1, HIGH);
digitalWrite (IN4, LOW);
digitalWrite (IN3, HIGH);
analogWrite(ENA, velocity);
analogWrite(ENB, velocity);
break;
case 'A':
analogWrite(ENA, 0);
analogWrite(ENB, 0);
delay(20);
digitalWrite (IN2, LOW);
digitalWrite (IN1, HIGH);
digitalWrite (IN4, HIGH);
digitalWrite (IN3, LOW);
analogWrite(ENA, velocity);
analogWrite(ENB, velocity);
break;
case 'S':
analogWrite(ENA, 0);
analogWrite(ENB, 0);
delay(20);
digitalWrite (IN2, HIGH);
digitalWrite (IN1, LOW);
digitalWrite (IN4, HIGH);
digitalWrite (IN3, LOW);
analogWrite(ENA, velocity);
analogWrite(ENB, velocity);
break;
case 'D':
analogWrite(ENA, 0);
analogWrite(ENB, 0);
delay(20);
// A
digitalWrite (IN2, HIGH);
digitalWrite (IN1, LOW);
// B
digitalWrite (IN4, LOW);
digitalWrite (IN3, HIGH);
analogWrite(ENA, velocity);
analogWrite(ENB, velocity);
break;
case ' ':
//velocity = 0;
analogWrite(ENA, 0);
analogWrite(ENB, 0);
break;
default:
if ((command >= 48) && (command <= 57)) {
if (command == 48)
{
velocity = 0;
}
else
{
velocity = (command - 48 + 1) * 10 + 100;
}
}
}
}
}
else {
timer0 = millis(); // Получение текущего времени
if ((unsigned long)(timer0 - timer1) > 20000) {
analogWrite(ENA, 0);
analogWrite(ENB, 0);
prevCommand = ' ';
}
}
}
Python GUI script
from __future__ import print_function, absolute_import, division
import subprocess
import urwid
import serial
from subprocess import Popen, PIPE
from time import sleep
def exit_on_q(key):
global power
global ser
global spower
global p
global currc
if key in ('q', 'Q'):
p.stdin.write(b'Q\n')
p.stdin.flush()
sleep(1)
raise urwid.ExitMainLoop()
if key in ('w', 'W'):
# forward
currc = 'W - Forward'
p.stdin.write(b'W\n')
p.stdin.flush()
if key in ('a', 'A'):
# Left
currc = 'A - Left'
p.stdin.write(b'A\n')
p.stdin.flush()
if key in ('s', 'S'):
# Backward
currc = 'S - Backward'
p.stdin.write(b'S\n')
p.stdin.flush()
if key in ('d', 'D'):
# Right
currc = 'D - Right'
p.stdin.write(b'D\n')
p.stdin.flush()
if key in (' '):
# Stop
currc = 'Space - Stop'
p.stdin.write(b' \n')
p.stdin.flush()
if key in ('+'):
if (power < 99):
power = power + 10
spower = spower + 1
txt_CP.set_text(('banner', str(power)))
if key in ('-'):
if (power > 0):
power = power - 10
spower = spower - 1
txt_CP.set_text(('banner', str(power)))
txt_CCV.set_text(('banner', currc))
def enter_idle():
loop.remove_watch_file(pipe.stdout)
def update_text(read_data):
txt_Q.set_text(('banner', read_data))
if __name__ == '__main__':
currc = "No command"
palette = [
('banner', 'black', 'light gray'),
('streak', 'black', 'dark blue'),
('bg', 'black', 'dark blue'),]
# spower = 0..9 (48 .. 57)
spower = 4
power = spower * 10
txt_F = urwid.Text(('banner', u"W - Forward (\u2191)"), align='center')
txt_LRS = urwid.Text(('banner', u"\u2190 A - Left | Space - Stop | D - Right \u2192"), align='center')
txt_B = urwid.Text(('banner', u"S - Backward (\u2193)"), align='center')
txt_P = urwid.Text(('banner', u"'+' Increase motor power | '-' Decrease motor power"), align='center')
txt_C = urwid.Text(('banner', u"Current power:"), align='center')
txt_CP = urwid.Text(('banner', str(power)), align='center')
# current command
txt_CC = urwid.Text(('banner', u"Current command: "), align='center')
txt_CCV = urwid.Text(('banner', u"No command"), align='center')
txt_Log = urwid.Text(('banner', u"Log: "), align='center')
txt_LogV = urwid.Text(('banner', u""), align='center')
txt_Q = urwid.Text(('banner', u"Q - Quit"), align='center')
#empty string
txt_E = urwid.Text(('banner', u""), align='center')
pile = urwid.Pile([txt_F, txt_LRS, txt_B, txt_E, txt_P, txt_C, txt_CP, txt_E, txt_CC, txt_CCV, txt_E, txt_Log, txt_LogV, txt_E, txt_Q ])
top = urwid.Filler(pile, top = 5)
loop = urwid.MainLoop(top, palette, unhandled_input=exit_on_q, handle_mouse=False)
stdout = loop.watch_pipe(update_text)
stderr = loop.watch_pipe(update_text)
p = subprocess.Popen(['python3', 'shell_edt.py'], stdin = PIPE, stdout = stdout, stderr = stdout, shell = False)
loop.run()
Python communication script
import sys
import threading
import serial
from time import sleep
global currcomm
readtimer = 1 #
def read():
global serialport
global currcomm
threading.Timer(readtimer, read).start()
if (currcomm != -1):
data = serialport.read(10);
print(str(data) + " : " + str(len(data)))
sys.stdout.flush();
#sleep(0.5) '''
serialport = serial.Serial("/dev/ttyACM0", 19200, timeout=0.2)
data = serialport.read(100);
currcomm = -1
threading.Timer(readtimer, read).start()
sleep(1)
while True:
currcomm = input()
if (currcomm == 'S') or (currcomm == 'D') or (currcomm == 'W') or (currcomm == 'A') or (currcomm == ' '):
serialport.write(bytes(currcomm, encoding = 'utf-8'));
if (currcomm == 'Q'):
serialport.close() # Only executes once the loop exits
ser.write
line – c2huc2hu\r
or\n
perhaps) which the RasPi does not send? – Adrian W