Friday, June 16, 2017

Python run on Raspberry Pi (and PC running Ubuntu) to plot serial data from ESP8266/NodeMCU

Last post show a simple program run on ESP8266/NodeMCU to read Analog Input and send to Serial. And display the data on Raspberry Pi 3 using Arduino IDE Serial Plotted. This post show a Python example run on Raspberry Pi 3/Raspbian Jessie with PIXEL, to plot the serial data graphically using matplotlib library.



pyserialplot.py
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import serial
import platform

print("Python version: " + platform.python_version())
print("matplotlib version: " + mpl.__version__)

fig, ax = plt.subplots()
line, = ax.plot(np.random.rand(10))
ax.set_ylim(0, 1030)
xdata, ydata = [0]*100, [0]*100
SerialIn = serial.Serial("/dev/ttyUSB0",9600)

def update(data):
    line.set_ydata(data)
    return line,

def run(data):
    global xdata, ydata
    x,y = data
    if (x == 0):
        xdata = [0]*100
        ydata = [0]*100
    del xdata[0]
    del ydata[0]
    xdata.append(x)
    ydata.append(y)
    line.set_data(xdata, ydata)
    return line,

def data_gen():
    x = 9
    while True:
        if (x >= 9):
            x = 0
        else:
            x += 0.1
            
        try:
            inRaw = SerialIn.readline()
            inInt = int(inRaw)
        except:
            inInt = 0
            
        yield x, inInt

ani = animation.FuncAnimation(fig, run, data_gen, interval=0, blit=True)
plt.show()


This python example can be run on both Python 2 and 3. To run this on Raspberry Pi/Raspbian Jessie with PIXEL, matplotlib library is need.

For Python 2:
$ sudo apt-get install python-matplotlib

For Python 3:
$ sudo apt-get install python3-matplotlib

In the following code, we have to get the port connected.
SerialIn = serial.Serial("/dev/ttyUSB0",9600)

In Raspberry Pi/Raspbian Jessie with PIXEL, it is /dev/ttyUSB0 normal. We can check it with:
$ ls /dev/ttyUSB0*




Run on Ubuntu:

The Python script work on PC/Ubuntu also. This video show running on Ubuntu 17.04/Payton 3.6 (actually behind Windows 10/VirtualBox).


In order to run with newest Python 3.6 on Ubuntu 17.04, you have to install Python 3.6 and corresponding IDLE and pip.

And install packages using command:
$ sudo python3.6 -m pip install numpy
$ sudo python3.6 -m pip install matplotlib
$ sudo python3.6 -m pip install pyserial


About Saving graph of matplotlib:

Suppose I can click the Save button on matplotlib navigation toolbar to save the graph to file (reference: matplotlib - Interactive navigation).

But when I test it on Raspberry Pi with matplotlib 1.4.2, it is not work.

When test it on PC running Ubuntu 17.04/Python 3.6 with matplotlib 2.0.2, I can save the graph. But the navigation toolbar disappear after saved.



Thursday, June 15, 2017

ESP8266/NodeMCU read Analog Input and send to Raspberry Pi via Serial/USB

This example of ESP8266/NodeMCU read input from A0, and output to Serial. The receiving side is a Raspberry Pi 3 running Raspbian Jessie with PIXEL and Arduino IDE installed, the result is display graphically using Arduino IDE's Serial Plotter. All job done on Raspberry Pi 3. ESP8266/NodeMCU connect to the Raspberry Pi 3 with USB.


To run the whole in Raspberry Pi, you have to:
- Install Arduino IDE on Raspberry Pi/Raspbian Jessie with PIXEL
Add Arduino core for ESP8266 to Arduino IDE

The simple program run on ESP8266/NodeMCU, ESP8266_AnalogIn_SerialOut.ino. (Suppose it work on other Arduino also, such as Uno.)
const int analogIn = A0;
int analogVal = 0;
bool led = 1;

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {

  digitalWrite(LED_BUILTIN, led);
  led = !led; 
  analogVal = analogRead(analogIn);
  Serial.println(analogVal);
  delay(500);
}

Next:
A Python example run on Raspberry Pi 3/Raspbian Jessie with PIXEL, to plot the serial data graphically using matplotlib library.

Add Arduino core for ESP8266 to Arduino IDE (run on Raspberry Pi/Raspbian Jessie with PIXEL)

Last post show how to "Install and run Arduino IDE on Raspberry Pi/Raspbian Jessie with PIXEL". We can add Arduino core for ESP8266 to Boards Manager, such that we can develop ESP8266/NodeMCU program on Raspberry Pi directly, without using PC. For sure, the compiling time will be longer than on PC.

Add Additional Board Manager URL for ESP8266 board:
> File > Preference
> Add "http://arduino.esp8266.com/stable/package_esp8266com_index.json" in Additional Board Manager URLs.

Add ESP8266 board to Arduino IDE:
- Open Boards Manager in Arduino IDE
- Search "esp8266" or "NodeMCU", you will find "esp8266 by ESP8266 Community". Install it.

This video show how to, and run the Blink example on ESP8266/NodeMCU. The Raspberry Pi 3 connect to a 4" 800x480 HDMI IPS LCD Display, so it display in low resolution.

Next:
ESP8266/NodeMCU read Analog Input and send to Raspberry Pi via Serial/USB
A Python example run on Raspberry Pi 3/Raspbian Jessie with PIXEL, to plot the serial data graphically using matplotlib library.


Tuesday, June 13, 2017

ESP32/Arduino core for ESP32 example, simple Web control RGB LED

My former post show how to program ESP32 with Arduino core for ESP32 to output PWM to GPIO using ledcWrite(). This exercise modify from the post of "NodeMCU/ESP8266 Arduino Core example, simple http server to output PWM", port to ESP32/Arduino core for ESP32, to implement a simple web control RGB LED.


NodeMCU32_WebRGBLED.ino
/* 
 *  This sketch run on ESP32 with Arduino core for ESP32,
 *  demonstrates how to set up a simple HTTP-like server.
 *  The server will set a GPIO pins depending on the request,
 *  to control the brightness of RGB LED connected to:
 *    23 : BLUE
 *    22 : GREEN
 *    21 : RED
 *    
 *    http://server_ip/rgb/rrggbb/
 *    where rr is the value set RED
 *    where gg is the value set GREEN
 *    where bb is the value set BLUE
 *    then terminate with '/'
 *  server_ip is the IP address of the ESP32, will be 
 *  printed to Serial when the module is connected.
*/
#include <WiFi.h>

const char* ssid = "ssid";
const char* password = "password";
WiFiServer server(80);

#define MAX_LED_VALUE 99
// use first 3 channels of 16 channels (started from zero)
#define LEDC_CHANNEL_0_R  0
#define LEDC_CHANNEL_1_G  1
#define LEDC_CHANNEL_2_B  2

// use 13 bit precission for LEDC timer
#define LEDC_TIMER_13_BIT  13

// use 5000 Hz as a LEDC base frequency
#define LEDC_BASE_FREQ     5000

// LED PINs
#define LED_PIN_R   21
#define LED_PIN_G   22
#define LED_PIN_B   23

/*
Because Multiple libraries were found for "WiFi.h",
Arduino IDE will: 
 Used: ...\Arduino\hardware\espressif\esp32\libraries\WiFi
 Not used: C:\Program Files (x86)\Arduino\libraries\WiFi

And exit with error:
'min' was not declared in this scope

So I have to program my own min()
 */
uint32_t min(uint32_t num1, uint32_t num2){
  if(num1 < num2){
    return num1;
  }else{
    return num2;
  }
}

// Arduino like analogWrite
// value has to be between 0 and valueMax
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = MAX_LED_VALUE) {
  // calculate duty
  uint32_t duty = (LEDC_BASE_FREQ / valueMax) * min(value, valueMax);

  // write duty to LEDC
  ledcWrite(channel, duty);
}

void setup() {
  Serial.begin(115200);
  delay(10);
  
  // Setup timer and attach timer to a led pins
  ledcSetup(LEDC_CHANNEL_0_R, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(LED_PIN_R, LEDC_CHANNEL_0_R);
  ledcSetup(LEDC_CHANNEL_1_G, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(LED_PIN_G, LEDC_CHANNEL_1_G);
  ledcSetup(LEDC_CHANNEL_2_B, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(LED_PIN_B, LEDC_CHANNEL_2_B);

  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  // Match the request
  int valR, valG, valB;
  String subStringR, subStringG, subStringB;
  int index = req.indexOf("/rgb/");
  if(index != -1){
    if(req.charAt(index+11)=='/'){
      subStringR = req.substring(index+5, index+7);
      subStringG = req.substring(index+7, index+9);
      subStringB = req.substring(index+9, index+11);
      Serial.println("R: " + subStringR);
      Serial.println("G: " + subStringG);
      Serial.println("B: " + subStringB);

      valR = subStringR.toInt();
      valG = subStringG.toInt();
      valB = subStringB.toInt();
      Serial.println("valR: " + String(valR));
      Serial.println("valG: " + String(valG));
      Serial.println("valB: " + String(valB));
      
    }
    else{
      Serial.println("Not terminated with /");
      client.stop();
      return;
    }
  }
  else {
    Serial.println("No /rgb/ found");
    client.stop();
    return;
  }

  // Set GPIOs according to the request
  // No check valid of the requested setting
  ledcAnalogWrite(LEDC_CHANNEL_0_R, valR);
  ledcAnalogWrite(LEDC_CHANNEL_1_G, valG);
  ledcAnalogWrite(LEDC_CHANNEL_2_B, valB);
  
  client.flush();

  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIOs of RGB is now ";
  s += String(valR) +":" + String(valG) + ":" + String(valB);
  s += "</html>\n";

  // Send the response to the client
  client.print(s);
  delay(1);
  Serial.println("Client disonnected");

  // The client will actually be disconnected 
  // when the function returns and 'client' object is detroyed
}



Connection:


Install and run Arduino IDE on Raspberry Pi/Raspbian Jessie with PIXEL


This video show how to download, install and run Arduino IDE Linux ARM version (1 JUNE 2017 release), on Raspberry Pi 3 with Raspbian Jessie with PIXEL (2017-04-10 release). The Raspberry Pi connect to a 4" 800x480 HDMI IPS LCD Display, so it display in low resolution.

(All steps run on Raspberry Pi, remotely via VNC Viewer)

- Visit Arduino Software page. Scroll download to HOURLY BUILDS section, click to download Linux ARM version. It's release 1 JUNE 2017 currently.

- Extract the downloaded file.

- Change to the extracted directory.

- Run the install shell script.
$ sudo ./install.sh

- A short-cut will be added in MENU -> Programming -> Arduino IDE

You can also update library and board in the installed Arduino IDE.


Test with a simple program to read/write between Raspberry Pi and Arduino via Serial/USB.


testUsb.ino
int byteIn;

void setup() {
  Serial.begin(9600);
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.print("Program started\n");
}

// the loop function runs over and over again forever
void loop() {
  if(Serial.available() > 0){
    byteIn = Serial.read();
    if(byteIn == '0'){
      digitalWrite(LED_BUILTIN, LOW);
      Serial.print("LED OFF\n");
    }else if(byteIn == '1'){
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.print("LED ON\n");
    }else{
      Serial.print("unknown!\n");
    }
  }
}

Next:
Add Arduino core for ESP8266 to Arduino IDE (run on Raspberry Pi/Raspbian Jessie with PIXEL)

Monday, June 5, 2017

Arduino core for ESP32, output PWM to GPIO using ledcWrite()


For ESP-32 Wifi/Bluetooth module with Arduino core for ESP32, to output PWM to GPIO, we can call ledcWrite(), something like Arduino analogWrite() function.

It's a example to output PWM to GPIO 21, 22 and 23, to control color/brightness of RGB LED.
/*
 Arduino core for ESP32 example: output PWM to GPIO using ledcWrite()
 Modify from the example code:
 /ESP32/examples/AnalogOut/LEDCSoftwareFade
*/

// use first 3 channels of 16 channels (started from zero)
#define LEDC_CHANNEL_0_R  0
#define LEDC_CHANNEL_1_G  1
#define LEDC_CHANNEL_2_B  2

// use 13 bit precission for LEDC timer
#define LEDC_TIMER_13_BIT  13

// use 5000 Hz as a LEDC base frequency
#define LEDC_BASE_FREQ     5000

// LED PINs
#define LED_PIN_R   21
#define LED_PIN_G   22
#define LED_PIN_B   23

// Arduino like analogWrite
// value has to be between 0 and valueMax
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
  // calculate duty
  uint32_t duty = (LEDC_BASE_FREQ / valueMax) * min(value, valueMax);

  // write duty to LEDC
  ledcWrite(channel, duty);
}

void setup() {
  // Setup timer and attach timer to a led pins
  ledcSetup(LEDC_CHANNEL_0_R, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(LED_PIN_R, LEDC_CHANNEL_0_R);
  ledcSetup(LEDC_CHANNEL_1_G, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(LED_PIN_G, LEDC_CHANNEL_1_G);
  ledcSetup(LEDC_CHANNEL_2_B, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(LED_PIN_B, LEDC_CHANNEL_2_B);
}

void loop() {
  ledcAnalogWrite(LEDC_CHANNEL_0_R, 0);
  ledcAnalogWrite(LEDC_CHANNEL_1_G, 0);
  ledcAnalogWrite(LEDC_CHANNEL_2_B, 0);
  delay(1000);

  for(int i = 0; i < 255; i++){
    ledcAnalogWrite(LEDC_CHANNEL_0_R, i);
    delay(10);
  }
  for(int i = 255; i > 0; i--){
    ledcAnalogWrite(LEDC_CHANNEL_0_R, i);
    delay(10);
  }

  for(int i = 0; i < 255; i++){
    ledcAnalogWrite(LEDC_CHANNEL_1_G, i);
    delay(10);
  }
  for(int i = 255; i > 0; i--){
    ledcAnalogWrite(LEDC_CHANNEL_1_G, i);
    delay(10);
  }

  for(int i = 0; i < 255; i++){
    ledcAnalogWrite(LEDC_CHANNEL_2_B, i);
    delay(10);
  }
  for(int i = 255; i > 0; i--){
    ledcAnalogWrite(LEDC_CHANNEL_2_B, i);
    delay(10);
  }

  for(int i = 0; i < 255; i++){
    ledcAnalogWrite(LEDC_CHANNEL_0_R, i);
    ledcAnalogWrite(LEDC_CHANNEL_1_G, i);
    ledcAnalogWrite(LEDC_CHANNEL_2_B, i);
    delay(10);
  }
  for(int i = 255; i > 0; i--){
    ledcAnalogWrite(LEDC_CHANNEL_0_R, i);
    ledcAnalogWrite(LEDC_CHANNEL_1_G, i);
    ledcAnalogWrite(LEDC_CHANNEL_2_B, i);
    delay(10);
  }
}


Connection:
Reference:
Example at /ESP32/examples/AnalogOut/LEDCSoftwareFade
or here.

Next:
ESP32/Arduino core for ESP32 example, simple Web control RGB LED

Thursday, June 1, 2017

NodeMCU/ESP8266 Arduino Core example, simple http server to output PWM

Last post show a dummy example of NodeMCU/ESP8266 Arduino Core to output PWM to control color/brightness of RGB LED.

It's another example to setup a simple HTTP-like server, to receive request from client, output PWM, to control color/brightness of RGB LED.


NodeMCU_WiFiWebServer_RGB.ino
/*
 *  This sketch run on NodeMCU (ESP8266),
 *  demonstrates how to set up a simple HTTP-like server.
 *  The server will set a GPIO pins depending on the request,
 *  to control the brightness of RGB LED connected to:
 *    D0 : BLUE
 *    D1 : GREEN
 *    D2 : RED
 *    
 *    http://server_ip/rgb/rrggbb/
 *    where rr is the value set RED
 *    where gg is the value set GREEN
 *    where bb is the value set BLUE
 *    then terminate with '/'
 *  server_ip is the IP address of the NodeMCU, will be 
 *  printed to Serial when the module is connected.
 */

#include <ESP8266WiFi.h>

const char* ssid = "Xtation";
const char* password = "password";

int ledB = D0;
int ledG = D1;
int ledR = D2;

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  delay(10);

  // prepare GPIOs for RGB LED
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  analogWriteRange(99); //PWM: 0~99
  
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  // Match the request
  int valR, valG, valB;
  String subStringR, subStringG, subStringB;
  int index = req.indexOf("/rgb/");
  if(index != -1){
    if(req.charAt(index+11)=='/'){
      subStringR = req.substring(index+5, index+7);
      subStringG = req.substring(index+7, index+9);
      subStringB = req.substring(index+9, index+11);
      Serial.println("R: " + subStringR);
      Serial.println("G: " + subStringG);
      Serial.println("B: " + subStringB);

      valR = subStringR.toInt();
      valG = subStringG.toInt();
      valB = subStringB.toInt();
      Serial.println("valR: " + String(valR));
      Serial.println("valG: " + String(valG));
      Serial.println("valB: " + String(valB));
      
    }
    else{
      Serial.println("Not terminated with /");
      client.stop();
      return;
    }
  }
  else {
    Serial.println("No /rgb/ found");
    client.stop();
    return;
  }

  // Set GPIOs according to the request
  // No check valid of the requested setting
  analogWrite(ledR, valR);
  analogWrite(ledG, valG);
  analogWrite(ledB, valB);
  
  client.flush();

  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIOs of RGB is now ";
  s += String(valR) +":" + String(valG) + ":" + String(valB);
  s += "</html>\n";

  // Send the response to the client
  client.print(s);
  delay(1);
  Serial.println("Client disonnected");

  // The client will actually be disconnected 
  // when the function returns and 'client' object is detroyed
}


Connection same as in last post:



Compare with ESP32 version: ESP32/Arduino core for ESP32 example, simple Web control RGB LED

NodeMCU/ESP8266 Arduino Core analog output PWM

Example of NodeMCU with ESP8266 Arduino Core to output PWM by calling analogWrite(), to control brightness of RGB LED.



NodeMCU_PWM.inf
int ledB = D0;
int ledG = D1;
int ledR = D2;

void setup() {
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  //Set PWM frequency 500, default is 1000
  //Set range 0~100, default is 0~1023
  analogWriteFreq(500);
  analogWriteRange(100);
}

// the loop function runs over and over again forever
void loop() {
  analogWrite(ledR, 0);
  analogWrite(ledG, 0);
  analogWrite(ledB, 0);
  delay(500);
  analogWrite(ledR, 100);
  analogWrite(ledG, 100);
  analogWrite(ledB, 100);
  delay(500);
  analogWrite(ledR, 0);
  analogWrite(ledG, 0);
  analogWrite(ledB, 0);
  delay(500);

  int i;
  for(i=0; i<100; i++){
    analogWrite(ledR, i);
    delay(10);
  }
  analogWrite(ledR, 0);
  
  for(i=0; i<100; i++){
    analogWrite(ledG, i);
    delay(10);
  }
  analogWrite(ledG, 0);
  
  for(i=0; i<100; i++){
    analogWrite(ledB, i);
    delay(10);
  }
  analogWrite(ledB, 0);

  for(i=0; i<100; i++8){
    analogWrite(ledR, i);
    analogWrite(ledG, i);
    analogWrite(ledB, i);
    delay(10);
  }

  for(i=100; i>0; i--){
    analogWrite(ledR, i);
    analogWrite(ledG, i);
    analogWrite(ledB, i);
    delay(10);
  }

}

Reference:
analogWrite(pin, value) enables software PWM on the given pin. PWM may be used on pins 0 to 16. Call analogWrite(pin, 0) to disable PWM on the pin. value may be in range from 0 to PWMRANGE, which is equal to 1023 by default. PWM range may be changed by calling analogWriteRange(new_range).

PWM frequency is 1kHz by default. Call analogWriteFreq(new_frequency) to change the frequency.

Next:
simple http server to output PWM, to control color/brightness of RGB LED.