Hello everyone,
I am experiencing very odd behavior in my arduino code. I do not believe the python code i wrote is the issue since it acts the same way with the serial monitor through the IDE. I am using an uno at the moment.
The comments in command_exec_test.ino outline much of the behavior for each line commented in/out.
I am basically just trying to pass Serial into a class and be able to call things like print. I have tried doing it as a pointer and a reference but both have the same behavior.
I am passing it as a stream object into the class.
Outside of the class using sprintf to construct a message and print to print it the code works as expected. I then commented this out for printing in the class.
Once entering the class it repeatedly reads "setup complete" from the setup code in the arduino but i do not see the arduino resetting via the led lights.
I also put a third test which doesn't include the sprintf and it reads twice from my python code. (both reads read, "in loop")
I can only imagine this is some sort of buffer issue? Or something with hardware vs software serial and the stream class. But i am unsure and haven't been able to figure it out. The code is basic enough i didn't expect to have these issues.
The behavior is similar if not the same from using the serial monitor from the arudino IDE although the python code reads twice without sending two messages.
Note: In the python code (arduino_serial.py) we wait for "setup complete" to send before continuing with the rest of the code. This is not printed. Therefore we should not see "setup complete" sent in the output. (unless on IDE serial monitor)
Arduino code:
command.h
#ifndef _COMMAND_H
#define _COMMAND_H
#include <stdint.h>
#include <Arduino.h>
#define S0_ANGLE 0x0
class command {
public:
command(Stream &serial);
~command();
void parse_msg(uint8_t *msg);
void exec_command(uint8_t *msg);
private:
Stream &my_serial;
};
#endif
command.cpp (you can ignore parse_msg it is not used)
#include "command.h"
#define PARAM_BUFF 100
command::command(Stream &serial)
{
my_serial = serial;
}
command::~command()
{
}
void command::parse_msg(uint8_t *msg)
{
int i = 0;
uint8_t msg_type = 0;
uint8_t cmd = 0;
uint8_t param[PARAM_BUFF] = {'\0'};
// parse msg type
msg_type = msg[0];
// parse cmd type
cmd = msg[1];
if (cmd == S0_ANGLE) {
// 1 uint8_t param for S0_ANGLE
param[0] = msg[2];
}
}
void command::exec_command(uint8_t *msg)
{
my_serial.print("printing from exec_command() in command class\n");
}
command_exec_test.ino
/*
* Program to test sending and recieving data from serial.
* written by: James Ross
*/
#include "command.h"
#define BAUD_RATE 115200
#define MSG_BUFF 256
#define S_IN_BUFF 10 // serial input buffer size
uint8_t serial_in[S_IN_BUFF] = {'\0'};
char serial_msg[MSG_BUFF] = {'\0'};
// initialize cmd class with serial
command cmd = command(Serial);
void setup()
{
Serial.begin(BAUD_RATE);
while (!Serial) {} // wait for serial interace to connect
Serial.setTimeout(1);
Serial.print("Setup Complete\n"); // let serial com know setup complete
}
void loop()
{
int i = 0;
int num_recv = 0;
if (Serial.available()) {
num_recv = Serial.readBytes(serial_in, S_IN_BUFF-1); // room for '\0'
serial_in[num_recv] = '\0';
/* Below two lines work fine with python code */
//sprintf(serial_msg, "serial available, %s\n", serial_in);
//Serial.print(serial_msg);
/* printing in class does not work. Behavior makes me see
* "setup complete" each read from the setup function for some reason.
* (when above two lines are commented out)
*/
cmd.exec_command(serial_in);
/* if above 3 lines are removed and line below is uncommented, i can
* read it multiple times from the python code.
*/
//Serial.println("in loop");
}
}
Python Code (if needed, though this code should be working as expected)
arduino_serial.py (connects to the arduino via serial)
import serial
import time
class arduino_com:
def __init__(self, port, baudrate, rtimeout):
self.port = port
self.baudrate = baudrate
self.rtimeout = rtimeout
self.arduino = 0 # will be serial object
def begin(self, delay=2):
self.arduino = serial.Serial(port=self.port, baudrate=self.baudrate,
timeout=self.rtimeout)
# arduino resets after serial connection, wait for arduino to setup
time.sleep(delay)
while (not self.read_line()):
pass
def write(self, msg, delay=0.05):
self.arduino.write(msg)
time.sleep(delay)
def read(self):
return self.arduino.read()
def read_line(self):
return self.arduino.readline()
command.py (just builds a message to send to the arduino)
import struct
class command_msg:
S0_ANGLE = 0x0 # change servo 1 angle
# private
_SHIFT_BYTE = 8
_CMD_MSG = 2
_msg = 0
def __init__(self):
pass
def build_cmd_msg(self, cmd, *argv):
if (cmd == self.S0_ANGLE):
arg = argv
self._msg = struct.pack("bbb", self._CMD_MSG, cmd, arg[0])
return self._msg
main.py (sends and receives the messages from the arduino)
from arduino_serial import arduino_com
from command import command_msg
from command import command_interface
import time
BAUD_RATE = 115200
SERIAL_PORT = "/dev/ttyACM0"
RTIMEOUT = 0.5 # read serial timeout
if __name__ == "__main__":
command = command_interface()
cmd_msg = command_msg()
arduino_serial = arduino_com(SERIAL_PORT, BAUD_RATE, RTIMEOUT)
arduino_serial.begin()
msg = cmd_msg.build_cmd_msg(cmd_msg.S0_ANGLE, 90)
arduino_serial.write(msg)
print("reading message from arduino")
time.sleep(1)
data = arduino_serial.read_line()
print(data)
# data should read empty in this iteration based on arduino code
# It is NOT empty and repeats previous read when arduino sends "in loop" in
# its code
data = arduino_serial.read_line()
print(data)
Hopefully the code isnt overwhelming. Its not too in depth of code just organized in classes.
Any help or insight as to what could be causing this would be greatly appreciated.