Skip navigation

Arduino

3 Posts authored by: ftruzzi    

In the previous days I have built the code for all my clients (the light spots): they receive TCP commands from the Yún and control the lights accordingly.

 

1. The 3W RGB LED.

 

The first one is an Arduino Uno connected to a custom, constant-current RGB LED driver that can handle 3-10W LEDs (maybe even 20W). Here's a picture of it (yes, bad soldering job):

 

HEy7tLe.jpg

 

This has 3 PWM inputs which are connected to 3 pins on the Arduino. It gets 12V from any power supply which then also goes to the VIN pin on the Arduino, powering it.

I then soldered an ESP8266 module on a protoboard, along with an LM1117 for bringing 5V down to 3.3V (the onboard regulator of the Arduino doesn't supply enough current) and a resistor circuit for level shifting.

 

Here it is:

 

IMG_20150105_141723.jpg

 

 

Here is the full Arduino code that controls the lights: there is still some work to do but the main functions are there and working. It has EEPROM saving so that the last value is automatically retrieved at boot. I got the ESP8266 control code from a website then tweaked it, but it was a couple of months ago so I don't remember where.

 

// TCP STRING SYNTAX
// Manual Mode - M,COLOR_R,COLOR_G,COLOR_B$ (e.g. M,255,128,0$ for orange)
// Strobe Mode - S,DELAY$ (e.g. S,200$ for a random color every 200ms)
// Fade Mode - F,R_START,G_START,B_START,R_END,G_END,B_END,DELAY_TIME$ (e.g. F,255,0,0,0,0,255,5$ fades from red to blue waiting 5ms between every fade "step")
// Options (0 or 1) - TODO


#include <EEPROM.h>
#include <AltSoftSerial.h>


#define BUFFER_SIZE 30
#define SSID "TP-LINK"
#define PASSWORD "topolottolo"
#define PORT 8080


AltSoftSerial debugSerial;


enum {WIFI_ERROR_NONE=0, WIFI_ERROR_AT, WIFI_ERROR_RST, WIFI_ERROR_SSIDPWD, WIFI_ERROR_SERVER, WIFI_ERROR_UNKNOWN};


char dataIn[BUFFER_SIZE];
char dataOut[BUFFER_SIZE];
char buff[BUFFER_SIZE];
char options[2];
char *dataPtr = dataIn;
char *data2Ptr, *mode, *word1, *word2, *word3, *word4, *word5, *word6, *word7;


int addr = 0, index = 0, red = 6, green = 3, blue = 11, debugLED = 13, strSize = sizeof(dataIn);




boolean dataComplete = false, newData = false, first = false, wifi = false;


byte setupWiFi() {
  digitalWrite(debugLED, HIGH);


  // reset WiFi module
  Serial.println("AT+RST");
  delay(500);
  if(!Serial.find("ready")) {
  return WIFI_ERROR_RST;
  }


  // set mode 3
  //Serial.println("AT+CWMODE=3");
  delay(500);
  Serial.print("AT+CWJAP=\"");
  Serial.print(SSID);
  Serial.print("\",\"");
  Serial.print(PASSWORD);
  Serial.println("\"");
  delay(2000);
  if(!Serial.find("OK")) {
  return WIFI_ERROR_SSIDPWD;
  }
  delay(500);


  // start server
  Serial.println("AT+CIPMUX=1");
  if(!Serial.find("OK")){
  return WIFI_ERROR_SERVER;
  }
  delay(500);


  Serial.print("AT+CIPSERVER=1,"); // turn on TCP service
  Serial.println(PORT);
  if(!Serial.find("OK")){
  return WIFI_ERROR_SERVER;
  }
  delay(500);






  return WIFI_ERROR_NONE;
}


char* getIP() {
  Serial.println("AT+CIFSR");
    Serial.readBytesUntil('\r', buff, 20);
    Serial.readBytesUntil('\r', buff, 20);
    Serial.readBytesUntil('\r', buff, 20);


    return buff;
}


void setup() {
  Serial.begin(115200);
  debugSerial.begin(9600);
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(debugLED, OUTPUT);
  EEPROMReadString(addr, dataIn);
  first = false;
  delay(1000);
  //wifi setup
  if(wifi = true){
    debugSerial.println("Enabling WiFi...");


  while (byte err = setupWiFi()) {
  digitalWrite(debugLED, LOW);


    // error
    debugSerial.print("Setup error:");
    debugSerial.println((int)err);
    debugSerial.println("Retrying...");
    }


    // connected
    debugSerial.print("Connected to AP!");
    // char *ip = getIP();
    // debugSerial.print(" IP address is: ");
    // debugSerial.println(ip);
  }

}


void loop() {

  while(Serial.available() > 0 && first == false && Serial.find(":")){
  if (dataComplete == true || newData == true){


  debugSerial.println("New data found! Erasing array...");


  //erase data array
  for (int i=0; i<sizeof(dataIn); i++){
  dataIn[i] = NULL;
  }


  //erase eeprom
  for (int i = 0; i < BUFFER_SIZE; i++){
    EEPROM.write(i, 0);
  }


  dataComplete = false;
  newData = false;
  }


  // if(wifi == false){


  // char character = Serial.read();
  // dataIn[index] = character;
  // index++;


  // if (character == '$'){
  // dataIn[index-1] = 0;
  // index = 0;
  // } //old serial input mode
  // }



  Serial.readBytesUntil('$', dataIn, BUFFER_SIZE);
  dataComplete = true;
  debugSerial.print("New data received: ");
  debugSerial.println(dataIn);
  EEPROMWriteString(addr, dataPtr);
  data2Ptr = strdup(dataIn);
  splitSerialString();
  }


  if(strcmp(mode, "M") == 0){
  setRGB(atoi(word1), atoi(word2), atoi(word3));
  if(first == true){
  first = false;
  }
  }


  if(strcmp(mode, "S") == 0){
  strobe(atoi(word1));
  if(first == true){
  first = false;
  }
  }


  if(strcmp(mode, "F") == 0){
  fade(atoi(word1), atoi(word2), atoi(word3), atoi(word4), atoi(word5), atoi(word6), atoi(word7));
  if(first == true){
  first = false;
  }
  }


  if(first == true){
  first = false;
  }
}


void setRGB(int r, int g, int b){
  analogWrite(red, r);
  analogWrite(green, g);
  analogWrite(blue, b);
}


void strobe(int timeDelay){
  long r, g, b;
    r = random(0, 256);
    g = random(0, 256);
    b = random(0, 256);
    analogWrite(red, r);
    analogWrite(green, g);
    analogWrite(blue, b);
    delay(timeDelay);
}


void fade(int rstart, int gstart, int bstart, int rend, int gend, int bend, int delayTime){
  int r = rstart;
  int g = gstart;
  int b = bstart;


  int rSteps = calcSteps(rstart, rend);
  int gSteps = calcSteps(gstart, gend);
  int bSteps = calcSteps(bstart, bend);


  int redVal = calcSign(rSteps);
  int greenVal = calcSign(gSteps);
  int blueVal = calcSign(bSteps);


  for(int i=1; i<=1020; i++){
  if(checkSerial() == true){
  setZero();
  break;
  }
  if(i % rSteps == 0){
  rstart+=redVal;
  if(rstart >= 0){
  analogWrite(red, rstart);
  }
  }
  if(i % gSteps == 0){
  gstart+=greenVal;
  if(gstart >= 0){
  analogWrite(green, gstart);
  }


  }
  if(i % bSteps == 0){
  bstart+=blueVal;
  if(bstart >= 0){
  analogWrite(blue, bstart);
  }
  }
  delay(delayTime);
  }


  float aux;
  aux=rstart;
  rstart=rend;
  rend=aux;
  aux=gstart;
  gstart=gend;
  gend=aux;
  aux=bstart;
  bstart=bend;
  bend=aux;


  redVal = -redVal;
  greenVal = -greenVal;
  blueVal = -blueVal;


  for(int i=1; i<=1020; i++){
  if(checkSerial() == true){
  setZero();
  break;
  }
  if(i % rSteps == 0){
  rstart+=redVal;
  if(rstart >= 0){
  analogWrite(red, rstart);
  }
  }
  if(i % gSteps == 0){
  gstart+=greenVal;
  if(gstart >= 0){
  analogWrite(green, gstart);
  }


  }
  if(i % bSteps == 0){
  bstart+=blueVal;
  if(bstart >= 0){
  analogWrite(blue, bstart);
  }
  }
  delay(delayTime);
  }
}


int calcSign(int steps){
  int val;
  if(steps > 0){
  val = 1;
  }
  else if(steps == 0){
  val = 0;
  }
  else{
  val = -1;
  }
  return val;
}


int calcSteps(int startValue, int stopValue){
  if(stopValue-startValue != 0){
  return 1020/(stopValue-startValue);
  }
  else{
  return 0;
  }
}


void EEPROMWriteString(int startAddr, const char *string){


  debugSerial.print("Writing data to EEPROM... ");


  for (int i = 0; i < BUFFER_SIZE; i++) {
    EEPROM.write(startAddr + i, string[i]);
    if(string[i]  != NULL)
    debugSerial.print(string[i]);

  }
  debugSerial.println("");
}


void EEPROMReadString(int addr, char* string){


  debugSerial.println("Reading data from EEPROM...");


  for(int i=0; i<BUFFER_SIZE; i++){


  char character = EEPROM.read(addr);
  string[i] = character;
  if(string[i]  != NULL)
  debugSerial.print(string[i]);
  addr++;


  }
  //Serial.println();
  addr = 0;
  dataComplete = true;
  splitSerialString();
}


void splitSerialString(){
  debugSerial.print("\nSplitting string...");
  data2Ptr = strdup(dataIn);
  mode = strtok(data2Ptr, ",");
  word1 = strtok(NULL, ",");
  word2 = strtok(NULL, ",");
  word3 = strtok(NULL, ",");
  word4 = strtok(NULL, ",");
  word5 = strtok(NULL, ",");
  word6 = strtok(NULL, ",");
  word7 = strtok(NULL, ",");
  debugSerial.println("done!");
  first = true;
}


boolean checkSerial(){
  if (Serial.available() > 0){
  newData = true;
  return true;
  }
}


void setZero(){
  analogWrite(red, 0);
  analogWrite(green, 0);
  analogWrite(blue, 0);
}











 

 

 

2. The Infineon shield + RGB strips.

 

I have also installed and configured the Infineon RGB shield.

I immediately noticed that there were no "shield headers" included... and I only had standard male headers, so I soldered them on.

 

I then had to connect the ESP8266 module to the RX and TX pins (as well as to 5V and GND) so I had to do this ugly hack:

8XogENel.jpg

 

Sure enough, the Infineon shield expressed its disappointment by self-bending its pins! :O

 

IMG_20150102_185623.jpg

 

Everything is powered by an ATX breakout board (another nice summer project!).

 

One of the difficulties I encountered was converting 0-255 values into hex 0-4096 ones. Apart from that, the code is the same I posted a few lines before. This was my solution and it works, yet I'm not sure if I have done this right...

 

void setRGB(int r, int g, int b){
  //converts 0-255 values into i2c compatible values
  r = map(r, 0, 255, 0, 4095);
  g = map(g, 0, 255, 0, 4095);
  b = map(b, 0, 255, 0, 4095);
  char buffer[10];
  String red = String(r, HEX);
  String green = String(g, HEX);
  String blue = String(b, HEX);
  red = "0x" + red;
  green = "0x" + green;
  blue = "0x" + blue;
  red.toCharArray(buffer, 10);
  unsigned long r1 = strtoul(buffer, NULL, 16);
  green.toCharArray(buffer, 10);
  unsigned long g1 = strtoul(buffer, NULL, 16);
  blue.toCharArray(buffer, 10);
  unsigned long b1 = strtoul(buffer, NULL, 16);
  I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, r1, g1, b1);
}




 

Feels very redundant, maybe because I haven't fully understood int->hex conversions. Is there a better way of doing it apart from converting to strings?

 

I like the Infineon shield: it's packed of features and relatively easy to use, yet it seems to have this "hard-coded fade".

 

Right now, if I set the shield to be a single color (e.g. 255,0,0), the lights automatically fade from the previous color to red, according to the fade settings. I'm now working to integrate the fading in a better way with my web interface.

 

Thanks for reading! I will post a video in a few days, in the meanwhile I'm writing the review of the components!

It's been a while since I last wrote here but I was busy developing my project!

 

I set up the Arduino Yún and it's fantastic. The Linux side is very handy, but I nearly ran out of memory on the Atmega chip (LCD driving libraries and fonts are resource-heavy!).

While I'm still working on the different clients, I am nearly finished developing the web interface and the Arduino communication code.

 

The Web Interface

 

It’s coded in Python (CherryPy as backend) and Javascript and is hosted on the linux-side of the Yún. It can connect to any of the lights so that you can control them as you want. Here's a screenshot:

 

HaMCNHX.png

 

It’s pretty basic and I plan on adding more features. It’s also my first experience with Javascript. On the upper right, there is a button you can use to choose which client to connect to: it turns green if the connection is successful, red otherwise.

I found the color picker on Google and tweaked it a little bit: unfortunately, I don’t remember who made it as it was a few weeks ago.

The Web Interface is sending commands in the following form, which will then be read by the Arduinos: MODE,R,G,B$. For example, if you want to set the orange color, the command would be “M,255,128,0$”, with ‘$’ as the terminating character. This is a Python test server running on my desktop, receiving commands from the web interface.

 

UiZSV5b.png

 

The ‘F’ stands for fade and the following numbers are the starting and ending values for each color. The last one, ‘5’ in this case, is the delay between each fade step in milliseconds.

‘S’ is strobe mode, and ‘100’ is the delay between each color change in milliseconds.

As you can see, the code is now opening a new connection for each command sent. This is quite bad practice, so I’ll need to fix it.

 

Python server and script (+ Arduino communication).

 

These are running on the Linux side of the Yún and they are called and started by the setup() function in the Arduino sketch. There is a set of useful commands from the Bridge and Process classes which can be used to run Linux commands from the Arduino.

 

In this case, I’m using runShellCommandAsynchronously() to start a non-blocking Python process (i.e. the Arduino sketches continues to run, without waiting for its completion).

 

I’m calling it twice, to run both the webUI application and the script that connects to the various clients and sends the needed strings.

 

Here’s the file that sends commands to the various clients. It sends the string received from the Arduino only if it’s different from the previous one.

 

import socket
import string
import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
from bridgeclient import BridgeClient


def send(host, port, command):
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


  if(sock.connect_ex((host, port)) == 0): #if connection is successful
  print ("Connected to %s:%d") % (host, port)
  print ("Sending command %s") % command
  sock.send(command) #send the string
  sock.close() #and close the socket
  return 0
  else:
  print ("Connection failed :(")
  return 1


bridge = BridgeClient()
last_command = "0"


while 1:
  if(bridge.get("status") != "0"): #check if we need to update
  IP = bridge.get("IP") #get the IP
  port = int(bridge.get("port")) #get the port and convert it to an integer
  command = bridge.get("data") #get the string we need to send
  if(command != last_command): #if it's different than the previous one...
  if(send(IP, port, command) == 0): #...send it and check the result
  last_command = command #the string we just sent becomes the last sent
  bridge.put("response", "0")
  else:
  bridge.put("response", "1")





 

That’s how it works: when you call the Bridge.put(“destination”, “value”) function in the Arduino sketch, it puts your value into a “destination” variable. This value can then be retrieved from the Python script after declaring a BridgeClient object and using the command bridge.get(“destination”).

 

I'm now working on the Yún controller, and here's a (very messy) picture!

 

IMG_20141228_220326.jpg

 

Also, tomorrow I will setup the Uno and the Infineon shield, and maybe share the clients code (which receives the commands and controls the lights accordingly).

Hello everybody!

 

I'm very happy to be one of the 20 lucky competitors in the IoT holiday challenge and I'm here to describe my project.

I want to build different light controlling devices (which would be Arduinos) which can be controlled via both a web interface and another "controller box" (which guess what, will be another Arduino).

 

I heard you like sketches, so here's one of my project. Please excuse my terrible drawing skills and image quality.

 

IMG_20141209_180310.jpg

 

Each "light spot" (uh, I don't know how to call these) can be connected to analog RGB led strips, using the Infineon shield, or to 3/10W RGB LEDs, using a custom-built, constant-current driver. One will be placed in my room, and I may add some sensors for interactivity. About the others I have yet to decide, but if those WS2812B strips reach me on time, I could build a nice LED christmas tree to put on my balcony.

 

I already have an Arduino Uno and two ESP8266 Wi-Fi modules, along with a LinkIt ONE (an Arduino-compatible board by Seeed, with integrated Wi-Fi) that, with the Yùn and the new Uno, make 4 Wi-Fi Arduinos. So I could have 1 controller + 3 light spots.

 

The controller can choose among the different light spots and connect to them. It will have an analog joystick for user input, three potentiometers for accurate color-choosing and an I2C display for displaying menus and additional information. I only have a small, 0.96" OLED for now but it will be enough.

 

Available lighting modes are manual (you choose the colors with the pots), fade from color A to B, strobe mode with user-definable delay, and standard colors mode (you can choose among pre-set colors). I may add some funnier modes such as police-strobe if I have time.

 

This project isn't going to be easy and the time schedule is tight. Also, it's my first road test and I don't know how long it will take for the boards to get here. However, I have already written some of the code and will try to include all the features I mentioned in this post.

 

The only doubt I have is choosing which board will do what. I don't know if it's better to use the Yùn as the controller or as one of the light spots (maybe the better one) and, consequently, if the webUI (hosted on the Yùn, can't wait to mix Arduino & Python!) will be able to control all the lights or only the one that is connected to the Yùn itself. Also, I don't know if the Yùn has enough memory to handle the LCD strings and images: in that case, the LinkIt would be the controller. Some advice here would be appreciated!

 

Thank you for making it this far. Please let me know what you think of my project: criticism is encouraged!

 

Happy holidays,

Francesco

Filter Blog

By date: By tag: