C++ Boost::asio serial communcation with Arduino can't write - c++

I tried to communicate with my Arduino Uno using the Boost Asio library. Somehow I can't send data to my Arduino, and I have no idea what i'm doing wrong. Reading works fine, but writing only works when i open a terminal and say:
cat /dev/ttyACM0
When this terminal window is open, and I run my C++ application it works otherwise it doesn't work.
Code of the test application (C++):
#include <iostream>
#include <boost/asio.hpp>
char* message;
int main()
{
boost::asio::io_service ioservice;
boost::asio::serial_port serial(ioservice, "/dev/ttyACM0");
serial.set_option(boost::asio::serial_port_base::baud_rate(115200));
serial.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
serial.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
serial.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
serial.set_option(boost::asio::serial_port::character_size(boost::asio::serial_port::character_size(8)));
std::string s = "u";
boost::asio::streambuf b;
std::ostream os(&b);
os << s;
boost::asio::write(serial, b.data());
if (serial.is_open()) {
serial.close();
}
return 0;
}
Code of my Arduino application:
#include "Servo.h"
Servo servo;
void setup() {
Serial.begin(115200);
servo.attach(9);
servo.write(0);
}
void loop() {
if(Serial.available()) {
char c = Serial.read();
if(c == 'u') {
servo.write(180);
} else if (c == 'v') {
servo.write(0);
}
}
}
I tried this both on my Ubuntu 18.04 and Debian 10 installation to rule out a permission issue, so I think there is something wrong with my code.
Update:
I found the issue, the Arduino is restarting when making a serial connection. When I add a thread sleep for for example 5 seconds and after that resent the data it works (because then it keeps the serial connection alive). I'm still looking for a permanent solution, so that I don't have to do a write before I really want to write something.
Update 2:
Apparently I don't even have to do a write, but where must be a small delay before I can start writing, because when after opening the port the Arduino is still restarting.

I fixed it with adding a small delay before writing to the serial port. As I also wrote in my comment above, the Arduino is restarting when you start a serial communication.
This can be disabled on several ways: https://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection/
Another option is to send a "ready" signal from the Arduino to know in your application that the Arduino is rebooted. So then start in your application with reading, and when you received that message, you can start writing.

Related

How to properly write a Win32 application using boost::asio to communicate over serial connection

I'm developing a Windows application that has to communicate (both input and output) with an Arduino through its serial port. I'm using boost::asio for portability reasons and I want to keep using it. What happens is that the first time I run my application it works perfectly, but if I run it a second time, no data comes from the Arduino anymore and the application stucks on the read operation. The only way to recover is to unplug and replug the Arduino USB cable from the computer.
This behavior is Windows-specific. The same code works perfectly on Linux.
The compiler is Visual Studio 2017 Community Edition.
Here is an example code to reproduce the issue:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>
int main() {
boost::asio::serial_port port(ioctx, "COM3"); // "/dev/ttyACM0" on Linux
port.set_option(boost::asio::serial_port::baud_rate(9600));
port.set_option(boost::asio::serial_port::character_size(8));
port.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
port.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
port.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
char c = 'e';
auto const s = boost::asio::write(port, boost::asio::buffer(&c, 1));
std::cout << "sent " << s << " bytes" << std::endl;
boost::asio::streambuf response;
boost::asio::read_until(port, response, "\r\n");
std::istream response_stream(&response);
std::string line;
std::getline(response_stream, line);
std::cout << line << std::endl;
port.close(); // last-ditch effort to get it working
}
Here is an Arduino sketch (got from the Arduino website):
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Is there a way to restore the correct state of the connection? Am I missing something?
After having learned a couple of things, here is the solution:
Arduino uses its USB communication for both burning the sketch and performing data transmission back and forth the PC. The boot sequence foresees that for 2 seconds (for new Arduino versions and standard boot loader) the communication towards the boot loader is active. After that time, the sketch is executed.
Windows API allows to set all connection parameters at once via the SetCommState function and to retrieve them in a similar fashion with the GetCommState one. That is the method the set_option function uses to set the parameters, but it happens that calling GetCommState-SetCommState multiple times in a row slows down the process a lot (maybe by resetting the Arduino multiple times).
I ended writing the following function:
#include <Windows.h>
#include <chrono>
void init_arduino(boost::asio::serial_port& port, std::chrono::milliseconds const& sleep = 2000)
{
DCB dcbSerialParams = { 0 };
GetCommState(port.native_handle(), &dcbSerialParams);
// this is the optimal way to set the whole serial port configuration
// just in one shot.
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
//Setting the DTR to Control_Enable ensures that the Arduino is properly
//reset upon establishing a connection
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
SetCommState(port.native_handle(), &dcbSerialParams);
PurgeComm(port.native_handle(), PURGE_RXCLEAR | PURGE_TXCLEAR);
// Wait for Arduino to boot the sketch
Sleep(sleep.count());
}
and using it to replace the port.set_option( lines in the question example.
I also set the flow control to DTR_CONTROL_ENABLE instead of the original none in order to reset the Arduino upon connection.
USB serial adaptors can have device driver bugs and hardware problems. The fact that you have to unplug and plug the device to get it working again is indicative of a device driver bug.
Look for an updated driver. It will probably a Prolific or FTDI chipset, make sure you get the driver from the chip maker. See Prolific or FTDI
If it is a flow control related hardware problem you can wire together the DTR, DSR and CD pins, and wire together the RTS and CTS pins on the RS-232 connector on the USB adaptor. I have seen USB adaptors where this is necessary, despite setting no flow control in software.

Boost serial port 100% cpu usage

My problem seems to be related to https://svn.boost.org/trac10/ticket/10496.
Simply opening a boost serial port and waiting for data cause one of the cpu
core of the embedded cpu to have 100% usage.
My hardware is the redpitaya STEMLAB 125-14 running Ubuntu 16.04. Some relevant
code snippets below:
// In the header
namespace ba = boost::asio;
typedef std::shared_ptr < boost::asio::serial_port serial_port_ptr;
typedef std::shared_ptr<boost::asio::io_service::work> work_ptr;
class SerialPort {
boost::asio::io_service m_io_service;
serial_port_ptr m_port;
work_ptr m_work;
bool open(const std::string &portname);
};
// in the source file,
bool SerialPort::open(const std::string &portname) {
m_port = serial_port_ptr(new ba::serial_port(m_io_service));
m_work = work_ptr(new ba::io_service::work(m_io_service));
m_port->open(portname, ec);
if (ec) {
std::cout << "open failed" << std::endl;
return false;
}
m_io_service.reset();
std::thread t(boost::bind(&ba::io_service::run, &m_io_service));
t.detach();
}
If I comment out the last two lines, I get 0% cpu utilization. The code works
fine, I can read and send from the serial port. The serial port is a usb to
serial device (can this have any effect?).
Has anyone else experience this before and is there a workaround before it is
‘fixed’ by the boost developers or am I doing something wrong?
EDIT: I initially thought maybe the hardware is not ‘powerful enough’, so I installed Ubuntu on VMWare on my i7 laptop. And run only the serial code on it with the USB serial device and I obtained the same result - 100% CPU usage on one core.
I understand it is difficult to help without seeing the full code, so I created a simple code that demonstrate the problem: this can be downloaded from goo.gl/FD5RNE . For simplicity, the code is only looking for USB serial device and will try to open the first device it found.
If you remove the comment from sp.open(), you will see the cpu usage go close to full utilisation. Thanks.
Edit: Still no solution to this but since I am not expecting the serial device to send unsolicited messages to the client, I have changed the program to always close the port i.e. the write/read are executed together with port opened before write and closed after read.
This has worked well so far and I am getting an average CPU of around 0-0.8%. Maybe a future updates to boost will solve the issue.

Arduino Uno Wifi library not working

I have recently purchased an Arduino Uno WIFI. It says it already has the ESP8266 wifi module integrated making it WIFI ready. I have successfuly connected to my wifi and wifi console. I have also used the test WebServer Blink test to play around with the pin 13 rest api commands. The problem im having is going beyond this example. I searched for WIFI documentation but can only find this documentation for the WIFI-Shield which is not working for my arduino.
I see in the example they import the #include <ArduinoWiFi.h> but i cannot find this libraries documentation. Is there anyother library I can use with this new arduino wifi? Does anyone have experience with this? I have tried to use the #include <WIFI.h> but it says that I don't have the wifi sheild.
ERROR:
WebServerBlink.ino:14:23: error: 'class ArduinoWifiClass' has no member named 'status'
CODE:
#include <Wire.h>
#include <ArduinoWiFi.h>
/*
on your borwser, you type http://<IP>/arduino/webserver/ or http://<hostname>.local/arduino/webserver/
http://labs.arduino.org/WebServerBlink
*/
void setup() {
pinMode(13,OUTPUT);
Wifi.begin();
Wifi.println("WebServer Server is up");
Wifi.println(Wifi.status()); //Line 14:23:: This will not work
}
void loop() {
while(Wifi.available()){
process(Wifi);
}
delay(50);
}
void process(WifiData client) {
// read the command
String command = client.readStringUntil('/');
// is "digital" command?
if (command == "webserver") {
WebServer(client);
}
if (command == "digital") {
digitalCommand(client);
}
}
void WebServer(WifiData client) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.println("<html>");
client.println("<head> </head>");
client.print("<body>");
client.print("Click<input type=button onClick=\"var w=window.open('/arduino/digital/13/1','_parent');w.close();\"value='ON'>pin13 ON<br>");
client.print("Click<input type=button onClick=\"var w=window.open('/arduino/digital/13/0','_parent');w.close();\"value='OFF'>pin13 OFF<br>");
client.print("</body>");
client.println("</html>");
client.print(DELIMITER); // very important to end the communication !!!
}
void digitalCommand(WifiData client) {
int pin, value;
// Read pin number
pin = client.parseInt();
// If the next character is a '/' it means we have an URL
// with a value like: "/digital/13/1"
if (client.read() == '/') {
value = client.parseInt();
digitalWrite(pin, value);
}
// Send feedback to client
client.print(F("Pin D"));
client.print(pin);
client.print(F(" set to "));
client.print(value);
client.print(EOL);
}
There is a big difference between Arduino Uno WIFI (http://www.arduino.org/products/boards/arduino-uno-wifi) from arduino.org and the Arduino WiFi Shield (www.arduino.cc/en/Main/ArduinoWiFiShield) from arduino.cc.
This is a good starting point for your Arduino Uno WIFI:
http://www.arduino.org/learning/getting-started/getting-started-with-arduino-uno-wifi
The next important point is, that you need to use Arduino 1.7 (from arduino.org) especially for OTA programming. Arduino 1.6.x from arduino.cc doesn't work.
Unfortunately they don't really develop their arduinowifi-library well.
I had the same problem on Linux IDE 1.8.1 and I solved it like this:
get https://github.com/arduino-org/Arduino/tree/master/libraries/ArduinoWiFi
add it in .....arduino-1.8.1/libraries/ArduinoWiFi/
restart the IDE. You shall be able to open and run the example sketch under File->Examples->ArduinoWiFi.
I suppose that it will work with any IDE on any platform.

C++ Serial Communication Issue

I am trying to make a Console C++ program that will be able to communicate through the serial port with my Arduino microcontroller, however I am having a problem with the ReadFile() function:
This is the ReadFile() function code from my C++ Console Program:
if(ReadFile(myPortHandle, &szBuf, 1, &dwIncommingReadSize, NULL) != 0)
{
cout<<"FOUND IT!"<<endl;
Sleep(100);
}
else
{
cout<<".";
Sleep(100);
}
The ReadFile function is consistently returning the "False" value, meaning it is not finding anything in the serial port. On the other side of the serial port, I have my Arduino Hooked up with the following code:
int switchPin = 4; // Switch connected to pin 4
void setup() {
pinMode(switchPin, INPUT); // Set pin 0 as an input
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop() {
if (digitalRead(switchPin) == HIGH) { // If switch is ON,
Serial.write(1); // send 1 to Processing
} else { // If the switch is not ON,
Serial.write(0); // send 0 to Processing
}
delay(100); // Wait 100 milliseconds
}
And every time I press a push button, I would send a "1" value to the serial port, and a "0" every time I don't press a push button. Basically, I got the Arduino code from a tutorial I watched on how to do serial communication with the program Processing (which worked perfectly), though I am unable to do the same with a simple Console Application I made with C++ because for some reason the ReadFile() function isn't finding any information in the serial port.
Anyone happen to know why?
P.S.: The complete code in the C++ Console Program can be found here:
https://stackoverflow.com/questions/27844956/c-console-program-serial-communication-arduino
The ReadFile function is consistently returning the "False" value, meaning it is not finding anything
No, that is not what it means. A FALSE return value indicates that it failed. That is never normal, you must implement error reporting code so you can diagnose the reason. And end the program since there is little reason to continue running. Unless you setup the serial port to intentionally fail by setting a read timeout.
Use GetLastError() to obtain the underlying Windows error code.
You look to use MS Windows so try to catch the arduino output using portmon first, then you can debug your C++ code.

QextSerialPort connection problem to Arduino

I'm trying to make a serial connection to an Arduino Diecimila board with QextSerialPort. My application hangs though everytime I call port->open(). The reason I think this is happening is because the Arduino board resets itself everytime a serial connection to it is made. There's a way of not making the board reset described here, but I can't figure out how to get QextSerialPort to do that. I can only set the DTR to false after the port has been opened that's not much help since the board has already reset itself by that time.
The code for the connection looks like this:
port = new QextSerialPort("/dev/tty.usbserial-A4001uwj");
port->open(QIODevice::ReadWrite);
port->setBaudRate(BAUD9600);
port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setDtr(false);
port->setRts(false);
Any ideas on how to get this done. I don't necessarily need to use QextSerialPort should someone know of another library that does the trick.
I'm new to C++ and Qt.
UPDATE:
I noticed that if I run a python script that connects to the same port (using pySerial) before running the above code, everything works just fine.
I had a similar problem.
In my case QExtSerial would open the port, I'd see the RX/TX lights on the board flash, but no data would be received. If I opened the port with another terminal program first QExtSerial would work as expected.
What solved it for me was opening the port, configuring the port settings, and then making DTR and RTS high for a short period of time.
This was on Windows 7 w/ an ATMega32u4 (SFE Pro Micro).
bool serialController::openPort(QString portName) {
QString selectPort = QString("\\\\.\\%1").arg(portName);
this->port = new QextSerialPort(selectPort,QextSerialPort::EventDriven);
if (port->open(QIODevice::ReadWrite | QIODevice::Unbuffered) == true) {
port->setBaudRate(BAUD38400);
port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setTimeout(500);
port->setDtr(true);
port->setRts(true);
Sleep(100);
port->setDtr(false);
port->setRts(false);
connect(port,SIGNAL(readyRead()), this, SLOT(onReadyRead()));
return true;
} else {
// Device failed to open: port->errorString();
}
return false;
}
libserial is an incredible library I use for stand-alone serial applications for my Arduino Duemilanove.
qserialdevice use!
Example:
http://robocraft.ru/blog/544.html
Can you just use a 3wire serial cable (tx/rx/gnd) with no DTR,RTS lines?