None blocking bi serial communication between a microcontroller and SoC (e.g. RPI/Linkit/Yun)

If the yun bridge is not suffiecient for your, due to the fact that you would like to use bi directional communcation, you could disable the yun bridge and use the serial1 communcation between the MCU and SoC part of the Yun/Linkit. Or you want to setup a serial connection between an arduino and RPI, please see this post for the wiring.

For the software side you should install pyserial with: pip install pyserial

Please use the following code for bidirectional and none blocking communication.

The python part:

import serial
import time

s = serial.Serial("/dev/ttyS0", 57600, timeout=0.1)
s.write("Hello")
arduinodata = s.readline()

while (True):
    if (s.inWaiting()>0): #if incoming bytes are waiting to be read from$
                arduinodata = s.readline()
                print(arduinodata)

The C code:

String incoming_data;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600); 
  Serial1.begin(57600);
}

void loop() {
  // put your main code here, to run repeatedly:
  incoming_data  = Serial1.readStringUntil('\n');
  
  if(incoming_data!="") { 
    
    if(incoming_data=="Hello") {
      Serial1.println("World");
      Serial.println("World");
    }
  }
  Serial1.println("Writing in none blocking mode");
  delay(50);
  
}

I would like to thank Michael Kirsch for above code.

Arduino yun MQTT Tutorial

In this tutorial we will dive into the use of MQTT with the arduino yun (or linkit) to control the LED#13.

One of the common protocols used in the IOT world is MQTT. MQTT is a machine-to-machine (M2M)/”Internet of Things” connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is available.

MQTT
The MQTT protocol is based on the principle of publishing messages and subscribing to topics, or “pub/sub”. Multiple clients connect to a broker and subscribe to topics that they are interested in. Clients also connect to the broker and publish messages to topics. Many clients may subscribe to the same topics and do with the information as they please. The broker and MQTT act as a simple, common interface for everything to connect to.

The setup
1.) MQTT broker running on a RPI
2.) Python script on the arduino yun (openwrt)
3.) Sketch for the MCU

MQTT broker
To install the MQTT broker:

apt-get update
apt-get install mosquitto

To test it open two SSH connections. One for subscribing and the other for publishing.

mosquitto_sub -h 192.168.2.40 -t "arduino/led"
mosquitto_pub -h 192.168.2.40 -t "arduino/led" -m "1"
mosquitto_pub -h 192.168.2.40 -t "arduino/led" -m "0"

Result:

1
0

For debugging purposes you can also run mosquitto in a shell. So open up the third SSH connection. Execute “/etc/init.d/mosquitto stop” and then execute “mosquitto”. Output:

1468435883: mosquitto version 1.3.4 (build date 2014-08-22 06:10:51+0000) starting
1468435883: Using default config.
1468435883: Opening ipv4 listen socket on port 1883.
1468435883: Opening ipv6 listen socket on port 1883.
1468435883: New connection from 192.168.x.x on port 1883.

Python
Install the MQTT python client:
pip install paho-mqtt

And then use the following python code:


#!/usr/bin/python
import sys
import paho.mqtt.client as mqtt

sys.path.insert(0, '/usr/lib/python2.7/bridge/')

from bridgeclient import BridgeClient as bridgeclient

from tcp import TCPJSONClient
json = TCPJSONClient('127.0.0.1', 5700)

value = bridgeclient()


# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, rc):
    print("Connected with result code "+str(rc))
        # Subscribing in on_connect() means that if we lose the connection and
        # reconnect then subscriptions will be renewed.
    client.subscribe("arduino/led")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
        print(msg.topic+" "+str(msg.payload))
        json.send({'command':'put', 'key':'led', 'value':msg.payload})

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect("192.168.x.x", 1883, 60)

# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
client.loop_forever()

Normally I would use value.put() instead of using json.send() only I received a “Bad file descriptor” once in a while. As the arduino yun uses JSON via TCP to the bridge library I used this workaround instead.

Sketch
Upload the sketch. memset will set al the items in the array to zero.

#include <Bridge.h>
#include <stdio.h>
 
// Here we will hold the values coming from Python via Bridge.
char ledvalue[2];
 
void setup() {
  // Zero out the memory we're using for the Bridge.
  memset(ledvalue, 0, 2);
   
  // Initialize digital pins 13 as output.
  pinMode(13, OUTPUT); 
 
  // Start using the Bridge.
  Bridge.begin();
}
 
void loop() {
  
  
  // Write current value of D13 to the pin (basically turning it on or off).
  Bridge.get("led", ledvalue, 2);
  int ledD13 = atoi(ledvalue);
  digitalWrite(13, ledD13);
   
  delay(10);  
}

Please note that the delay for retreiving info from the bridge is rather low, causing heavy load on the linux side.

Update [29-12-2017]:
If you receive the following error: TypeError: on_connect() takes exactly 3 arguments (4 given) the following could help you. Paho-mqtt client has been updated and you need to change the following (1. on_connect and subscribe):

def on_connect(client, userdata, rc):
print(“Connected with result code “+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe(“arduino/led”)

Should be changed to:
def on_connect(self, client, userdata, rc):
print(“Connected with result code “+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
self.subscribe(“arduino/led”)

Arduino yun bridge Tutorial

The Yún has two processors on board. One is an ATmega32U4 like on the Arduino Leonardo (we call it MCU from now on). The other is an Atheros 9331 (we call it MPU from now on), running Linux and the OpenWRT wireless stack, which enables the board to connect to WiFi and Ethernet networks. This tutorial also works for the linkit 7688 Duo. To run it on a linkit, please enable the arduino yun bridge software. You can find it in my older posts.

The bridge has quite some options available, for me there are two use case who are practical for me:
1.) Sending sensor data from the MCU to a server
2.) Bi-directional communication between a server and the MCU

Sending sensor data from the MCU to a server
Say for example that you have a sensor which can measure the temperature and partical concentration and you want to upload it to a restfull api webserver. In this case you are only sending data from the MCU to a server. Easiest solution is to use the “runShellCommand”. As the functionname tells us, it runs a command in the shell.

There are two flavours, runShellCommandAsynchronously() and runShellCommand(). runShellCommand() is a blocking function. That is, once you call Process.runShellCommand(), nothing else will happen in your sketch until it has completed. The time depends on the nature of the command you are executing. For a non-blocking alternative, please use runShellCommandAsynchronously().

Now we have a solution to run from your sketch a shell command. Now we have access to the shell, we need a tool to upload our data to the server. We can use Curl for this. Curl is an open source command line tool and library for transferring data with URL syntax. Eg. you can download a webpage, or upload via json data to a restfull api.

#include <Process.h>

void setup(void) {
  Bridge.begin();
}

void loop(void) {
  String curlCmd;

  String resultConcentration;
  String resultTemperature;
 
  resultConcentration=5.5;
  resultTemperature=20.0;
  
  curlCmd = "curl -H \"Content-Type: application/json\" -X POST -d \'{\"concentration\": "+resultConcentration+", \"temperature\": "+resultTemperature+"}\' http://192.168.x.xx:8080/measurement";

  Process database;
  database.runShellCommand(curlCmd);
  delay(1000);
}

You need to include for the bridge communication. “Bridge.begin()” starts Bridge, facilitating communication between the MCU and MPU. This should be called once in setup(). begin() is a blocking function. Once you call Bridge.begin(), nothing else will happen in your sketch until it has completed. This process takes approximately three seconds.
Process is the base class for all Bridge based calls for communicating with the Yun’s shell. Followed by run() or runAsynchronously(). The named process does not start executing until run() is called.

Bi-directional communication between a server and the MCU
For bi-directional communication you need to have a program/script running on the MPU. This will have a connection to a server (Eg. MQTT broler) and read/writes to the bridge. On the MCU you will need to have a sketch which can read/write to the bridge.

Sketch
The put() function allows you to store data on the MPU using a Key/Value structure. The Key field is like a label and you can associate a value to it. The key name must be unique in order to identify the correct value. On the MPU side there is a data store where all the keys and the values are saved.

The datastore is saved in the RAM of the MPU (AR9331), you will lose the datastore when you restart the bridge software on the Linux side (through power cycling, resetting the Linux processor, or uploading a sketch through WiFi or Ethernet). You will not lose the datastore if you reset the MCU (ATMega32u4 processor).

get() allows you to read a key/value item previously saved on the MPU. You can request for a value stored in the datastore by passing get() the Key you want to search for, the support buffer, and its size. The Key is similar to a label, used to identify an associated value. The key name must be unique in order to identify the correct value.

#include <Bridge.h>

unsigned long timer;
unsigned long counter = 0L;

void setup()
{
    Bridge.begin();     // this launches /usr/bin/run-bride on Linino
    timer = millis();
    Serial.begin(9600);
}

void loop()
{
    /* Every 200ms: */
    char bridge_Value[6];
    
    if (millis() - timer > 200) {
        timer = millis();

        Bridge.put("counter", String(counter++));
        Bridge.put("random1", String(random(1, 100)));
        Serial.println(counter);
        Bridge.get("hello", bridge_Value, 6);
        Serial.println(bridge_Value);
    }
}

Python script
For the MPU I’ve chosen to use a python script. You need to import the bridge library. The code is rather self explaining. You can also access the data via the API of the arduino Yun. In our case you can use http://192.168.x.xx/data/get/counter to read the value of counter, or write to counter via http://192.168.x.xx/data/put/counter/4

#!/usr/bin/python
import time
import sys

sys.path.insert(0, '/usr/lib/python2.7/bridge/')

from bridgeclient import BridgeClient as bridgeclient

value = bridgeclient()


while True:
        message = value.get("counter")
        print message
        value.put('hello','world')
        time.sleep(1)
        value.put('hello','you')

The sketch code is based on code from Jan-Piet Mens. The python from alnitak1000. I combined both the bridge.put()/bridge.get() and value.put()/value.get() together.