I have the following problem. An Arduino Uno is controlling the hardware components on the system. I use a PC, connected via a USB-serial device to send commands to the Arduino.
The problem: When I reconnect the Arduino to the PC(connect USB so it powers up), I first have to reprogram the application before I can perform any serial connection to the Arduino with my application (written in C++).
In the setup of my Arduino application, I turn a led to a specific color(LED is attached to the arduino). Based on the color I know that when I power the Arduino the correct software is loaded by the arduino.
The question:
Why do I need to reprogram the Arduino first after connecting it to the PC, before I can perform any serial communication to the device?
-> Do I need to program it differently?
-> Do I need to modify something on the board in order to make this work?
I tried to search for this on Google which said something about connecting a RX pin however that this does not apply for the Arduino Uno?
Any advice or pointers in this matter would be appreciated.
Regards,
Jan Jaap
PS: In addition, this is the code I use to connect to the Arduino:
SerialLowLevel::SerialLowLevel(char* serialDevice)
{
m_serialFD = INVALID_SERIALFD;
struct termios Opt;
// @NOTE: O_NONBLOCK results in less stable write() actions on serial bus.
m_serialFD = open(serialDevice, O_RDWR | O_NOCTTY);
// Check validity:
if (-1 == m_serialFD) {
LOG(LUNA::LOG_CRIT, "SerialLowLevel::SerialLowLevel - Could not open serial connection to the Magabot.\n");
m_serialFD = INVALID_SERIALFD;
return;
}
// Let Arduino boot after open() call.
LOG(LUNA::LOG_INFO, "SerialLowLevel::SerialLowLevel - Delay for Arduino boot.\n");
sleep(4);
tcgetattr(m_serialFD, &Opt);
cfsetispeed(&Opt,UNO_BAUDRATE);
cfsetospeed(&Opt,UNO_BAUDRATE);
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS8;
if (0 > tcsetattr(m_serialFD, TCSANOW, &Opt))
{
LOG(LUNA::LOG_ERROR, "SerialLowLevel::SerialLowLevel - Could not set serial settings.\n");
return;
}
m_extensiveDebug = false;
}
When you reconnect the Arduino to the USB connection it causes a reset and the first thing that happens is the bootloader listens to see if it there is a new sketch on its way.
I think your problem is that your program expects to be able to communicate with the Arduino immediately and isn't waiting for the bootloader to finish.
If this is the problem a good tactic is to get the Arduino to send a message to the PC during setup() and program the PC to do nothing until it has received that message.
If I'm wide of the mark you will need to provide more information explaining how things are connected and what your code is trying to do.
I based my serial connection code on this article:
Based on that article I added the sleep(4) (4 seconds of sleep) to my code in order to allow the Arduino to boot, after calling the open signal.
I'll describe the problem in steps:
Arduino is Unconnected, to any kind of device. (except for sensors and LED's of the system)
I connect Arduino to the PC -> my application boots as the connected LED to Arduino turns on and shows the correct color.
I start my serial test application and try to connect to the Arduino.
I do not get any response from the Arduino.
--- To fix:
I start the SDK for Arduino and either:
--> Upload a new sketch
--> Start the serial console
Now if I retry to connect with my serial test application, it works.
I suspect that the serial application provided with the Arduino SDK does some additional initialisation step in order to notify the Arduino regarding the boot loader waiting for a Sketch, as you mentioned in your reply.
The reason I ask this, is that eventually, the Arduino gets connected to a Raspberry Pi and I don't have access to either of those tools and my C++ application needs to have proper communication right away. It does not matter if the Arduino does a reset on connection, it just needs to work after I reapply power (using powered USB - Hub) to it.
Hope this gives a bit more insight into the problem I am having.
Regards,
Jan Jaap
EDIT:::
In addition I tried your approach regarding the signalling from the Arduino site:
However this does not solve the problem. I receive the Ready, also including the 4 second sleep. But after it, I still cannot get the serial connection to work. I first need to either use the Arduino SDK to upload a sketch or make a connection using the provided terminal tool.
I don't think you have said what operating system you are using on your PC.
I have had no problems like you describe with Ubuntu Linux - which should behave very similar to a PI. But my PC programming is in JRuby which uses the JVM. I try to avoid C and Java.
I wonder if the problem is that your code is not correctly identifying or does not have the correct permissions for the serial connection, and the Arduino IDE solves that problem. Maybe you could include some debugging code in your PC program to check this.
I'm pretty sure the problem is NOT in the Arduino because I have a standalone 328 to which I connect with a FTDI cable and it works fine whether I connect it so it causes a reset or so it doesn't (I have two sets of connectors).
You can also use any other serial terminal - such as Putty - in place of the Arduino IDE.
Thank you for your reply. I now added some initial settings to the serial interface, putting it in RAW mode and adding settings to the termios.c_cc settings.
This solves the issue, that it was not able to connect properly on the first time. In addition it also made the serial connection much more stable, having less to none failures in the communication.
The initialisation code: (for reference if others encounter similar issues).
Important are the settings in "tOptions"
m_serialFD = INVALID_SERIALFD;
struct termios tOptions;
// @NOTE: O_NONBLOCK results in less stable write() actions on serial bus.
m_serialFD = open(serialDevice, O_RDWR | O_NOCTTY);
// Check validity:
if (-1 == m_serialFD) {
LOG(LUNA::LOG_CRIT, "SerialLowLevel::SerialLowLevel - Could not open serial connection to the Magabot.\n");
m_serialFD = INVALID_SERIALFD;
return;
}
// Let Arduino boot after open() call.
if (0 > tcgetattr(m_serialFD, &tOptions))
{
LOG(LUNA::LOG_ERROR, "SerialLowLevel::SerialLowLevel - Could not obtain current serialport settings.\n");
}
cfsetispeed(&tOptions,UNO_BAUDRATE);
cfsetospeed(&tOptions,UNO_BAUDRATE);
tOptions.c_cflag &= ~PARENB;
tOptions.c_cflag &= ~CSTOPB;
tOptions.c_cflag &= ~CSIZE;
tOptions.c_cflag |= CS8;
// ----- SOME ADDITIONAL SETTINGS, That may be required (NO FLOW CONTROL) -----//
tOptions.c_cflag &= ~CRTSCTS;
tOptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
tOptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
tOptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
tOptions.c_oflag &= ~OPOST; // make raw
// see: http://unixwiz.net/techtips/termios-vmin-vtime.html
tOptions.c_cc[VMIN] = 0; // Don't expect bytes, we handle this in our read function.
tOptions.c_cc[VTIME] = 1; // tenth of a second: VTIME * 100ms.
// ----- END ADDITIONAL SETTINGS -----//
if (0 > tcsetattr(m_serialFD, TCSANOW, &tOptions))
{
LOG(LUNA::LOG_ERROR, "SerialLowLevel::SerialLowLevel - Could not set serial settings.\n");
return;
}
LOG(LUNA::LOG_INFO, "SerialLowLevel::SerialLowLevel - Delay for Arduino boot.\n");
sleep(3);
m_cmd[0] = 0; // To make sure that we get the proper value.
LOG(LUNA::LOG_INFO, "SerialLowLevel::SerialLowLevel - Check if we receive a ready signal from Arduino\n");
if (-1 == readResponse(m_cmd, 6, 'R'))
{
LOG(LUNA::LOG_ERROR, "SerialLowLevel::SerialLowLevel - Did not receive a response.\n");
}
m_cmd[6] = 0;
LOG(LUNA::LOG_INFO, "SerialLowLevel::SerialLowLevel - Received from Arduino: %s\n", m_cmd);