Posts with «featured» label

GSM GPS shield for Arduino

-->-->-->-->

Shield for Arduino designed and based on the module GSM/GPRS SIM900 or the GSM/GPRS & GPS module SIM908, to make calls, voice and data connections via GPRS.

 

 

HARDWARE INNOVATIONS


This new version (old Arduino GSM shield) has several new hardware features, that allow maximum customization and provide many configurations.

We begin with the supply circuit a simple LM7805. To work, it is necessary to provide an input voltage between 7.5V and 12V. As shown in the circuit diagram, the input voltage, after being stabilized at 5 V, is reduced to 4.3 V by using a diode and provide power to modules that need a voltage between the 3.2 and 4.8 V. During the operations such as the use of GPRS, the module absorbs a current of about 1 A, therefore it is necessary that the power source is able to provide this current intensity.

An important technical feature is the serial adapter for the communication between the GSM module and Arduino. To reduce the tension has been used a simple voltage divider, while for raising the voltage from the GSM module to Arduino we chose a MOSFET BS170.

The news that is immediately evident is the presence of two jacks for audio. With a microphone and a headset with a 3.5 mm jack (just the standard headphones for computers), you can make a voice call

To preserve compatibility with the Arduino Mega, we changed the selection method for the serial communication. The two different serial communication modes (hardware or software) are selectable by jumper, leaving the user the choice between the two configurations ( for serial software in this new version we adopted pins 2 and 3) or possibly use the pin to your choice with a simple wire connection. With this solution you can use the Arduino Mega using two of the four serial that it has, or possibly carry out the communication through a serial software via two pins of your choice.

Always to preserve maximum flexibility and customization, there are some pins on the back of PCB, which allow to make the connections from the Arduino digital ports and the control signals data flow (CTS, RTS) or alerts for incoming calls or unread SMS (RI). In this new version, you can then disable these connections to save inputs or outputs pins.

Comparing the new card with the previous one, you can see the presence of two connectors on the top.These additional connections allow the use of the shield also with the new small breakout for SIM900 and SIM908. The new module Simcom SIM908, is characterized by the presence of a GPS with 42 channels.

The scenery offered by this new module SIMCOM, in addition to GSM GPRS shield, it is quite remarkable: the creation of a GPS tracking device that can communicate the location via the Internet (or SMS) is now available to everyone, avoiding all the problems due to assembly and low-level programming.

A further feature of this new version, concerns the presence of a supercap for circuit dedicated to the RTC (Real Time Clock). Inside the SIM900, as well as the SIM908, there is a circuit that is responsible for updating the clock even without power.

 

GSM GPS SHIELD SCHEMATICS


R1: 10 kohm
R2: 10 kohm
R3: 10 kohm
R4: 10 kohm

C1: 100 nF
C2: 470 µF 25 VL
C3: 100 nF
C4: 220 µF 16 VL
C5: 47 pF
C6: 47 pF
C7: 47 pF
C8: 47 pF
C9: 47 pF
C10: 47 pF
C11: 220 µF 16 VL
C12: 100 nF

CRCT:  0,1F

U1: 7805

T1: BS170

D1: 1N4007

P1: Microswitch

MIC: jack 3,5 mm
SPK: jack 3,5 mm

 

SOFTWARE INNOVATIONS

The software library related to the GSM GPRS shield has been updated.  The library is open-source and uses the hosting service Google Project, located at http://code.google.com/p/gsm-shield-arduino/ . The library is constantly updated and improved with the addition of new features, so please check that you always have the latest release.

The main enhancement is the TPC/IP communication support through GPRS.

With a simple function, you can connect Arduino to internet using the APN (Access Point Name) you choose. After that we will automatically get an IP address by the provider.

To establish communication you must define which device performs the function of the server (still waiting for some connection), such as that client (requires a connection to the server according to the information you want to achieve) and that leads to exchange data .

In the library there are two functions that allow us to set the device to listen on a particular port for connections (server), or to establish a connection based on the server address and port chosen (client) .

Once connected, you can send the data, which can be command strings or just the data you want to monitor, for this action there is a high-level function, which simplifies the management.

 

LIBRARY FUNCTIONS GSM GPRS

First, you must have the folder libraries, in the root directory of the Arduino, the folder GSM_GPRS containing all the functions you can use.

Now if you want to change the serial port, through the jumper, you have to modify the file GSM.cpp.

To save memory, we decided to divide the functions into different classes contained in different files, to allow you to include or not the code parts needed, thus going to save memory RAM, leaving it free for the rest of the program. For the basic operation is always necessary to include files SIM900.h and SoftwareSerial.h, while depending on the needs you may include call.h (for call handling), sms.h (for sending, receiving and saving SMS) and inetGSM.h (containing functions related to HTTP, and GPRS).

SIM900.h

You should always include this file. It contains the basic functions for starting and configuring the GSM module.  Simply call the functions using “GSM.” As a prefix.

int gsm.begin(int baudrate) Turn the power on and sets the baud rate for communication. gsm.TurnOn(9600);
void SimpleRead() Reads a byte from the serial buffer. gsm.SimpleRead();
void SimpleWrite(char* cmd) Writes the string (or an integer) on the serial port. gsm.SimpleRead(“AT+CSQ”);
char SendATCmdWaitResp (char const* AT_cmd_string, uint16_t start_comm_tmout, uint16_t max_interchar_tmout, char const* response_string,byte no_of_attempts) Sends an AT command passed as a parameter, controlling the time of timeout for the receipt of a response and between one character and another. After receiving the response, compares it with that expected, if different resends the command for the set number of times.The possible outputs are shown below, with the relative enumeration. AT_RESP_ERR_NO_RESP or -1: No response received.AT_RESP_ERR_DIF_RESP or 0: Response different from that expected.AT_RESP_OK or 1: The response contains the expected string. If (gsm.SendATCmdWaitResp (“AT”,500,50,”OK”,3)== AT_RESP_OK)
Serial.println(“OK”);

 

call.h

In case you want to make a call, or simply refuse to answer an incoming call, you must use this class. To use these functions simply instantiate the object in the sketch. The functions listed in the table below refers to an object created with the following command at the beginning of the sketch: CallGSM call;

void Call(char* number_string) Makes a call to the number contained in the string call.Call(“+393471234567”)
void PickUp(void) During an incoming call, it responds and activates the audio communication. call.PickUp();
void HangUp(void) During an active call, hang up and disables audio communication. call.HangUp();
byte CallStatus(void); Returns the state about the phone calls.The possible output byte are listed under the following names:CALL_NONE or 0: No call.CALL_INCOM_VOICE or 1: An incoming call.CALL_ACTIVE_VOICE or 2: Active Call. If (call.CallStatus()== CALL_ACTIVE_VOICE)
Serial.println(“CALL ACTIVE”);
byte CallStatusWithAuth (char* phone_number,                             byte first_authorized_pos, byte last_authorized_pos); Unlike the previous distinguish if the active call, or incoming belongs to a number stored on the SIM in a position between the start and end, passed as parameters.  The possible output byte are listed under the following names:CALL_NONE or 0: No call.CALL_INCOM_VOICE_AUTH or 3: Incoming call from a number authenticated. CALL_INCOM_VOICE_NOT_AUTH or 4: Incoming call from a number not authenticated. If (call.CallStatusWithAuth() == CALL_INCOM_VOICE_AUTH)
Serial.println (“INCOMING CALL FROM A AUTH NUMBER”);

 

SMS.h

For managing text messages must use this special class. As before, it is necessary to recall it within the sketch and then instantiate an object. For example, in the following functions refers to an object created at the beginning of the sketch, with the command SMSGSM sms;

char SendSMS(char *number_str, char *message_str) Using the following command is sent an SMS to the number contained in the first string passed as a parameter with the text in the second. sms.SendSMS (“+393471234567” , ”Hello Arduino”);
char SendSMS(byte sim_phonebook_position, char *message_str) Send an SMS as before, where instead of the string is passed to the recipient’s contact position stored on the SIM. sms.SendSMS(1,”Hello Arduino”);
char GetSMS(byte position, char *phone_number, char *SMS_text, byte max_SMS_len) Reads the SMS stored on the SIM in the position passed as a parameter, saving the sender’s number in the first string passed in the second and the content of specified length. char number[13];
char text[200];
sms.GetSMS(1,number,text,200);

 

inetGSM.h

In this class are included functions to connect and manage communications via HTTP protocol. In the following examples was an object created with the command InetGSM inet;

int httpGET(const char* server, int port, const char* path, char* result, int resultlength) Send a GET request to the specified server on the specified port, requiring a certain path and saving the response to a string of the specified length. Returns the number of bytes read. char text[200];
inet.httpGET (“www.open-electronics.org”, 80,”/”,text,200);
int httpPOST(const char* server, int port, const char* path, const char* parameters, char* result, int resultlength) Send a POST request to the specified server on the specified port, requiring a certain path, passing the parameters set and saving the response string of the specified length. Returns the number of bytes read. char text[200];
inet.httpGET (“www.open-electronics.org”, 80,”/”,text,200);
int attachGPRS(char* domain, char* dom1, char* dom2) Initiates the connection using the GPRS APN passed as the first parameter.  The second and third arguments are two strings that contain the username and password. If no authentication is required, just pass the last two strings empty. inet.attachGPRS (“internet.wind”,””,””);
int deattachGPRS(void) Disconnects the module from the GPRS network. inet.deattachGPRS();
int connectTCP(const char* server, int port) Establishes a connection as a client to the server passed as a parameter on the port defined by the second parameter. inet.connectTCP (“www.open-electronics.org”, 80);
int disconnectTCP(void) Closes the communication with the server. inet.disconnectTCP();
int connectTCPServer(int port) Puts the module listens on the specified port waiting for a connection from a client. inet.connectTCPServer(80);
boolean connectedClient(void) Returns true if a client is connected to the module, otherwise false. inet.connectedClient();

 

EXAMPLE FOR CALLS AND SMS WITH THE GSM GPRS SHIELD 

Let us now, step by step, our first sketch to use the shield using the Arduino IDE version 1.00. We will write a program that when it receives a call from a preset number (stored in a specific location on the SIM), rejects the call and sends an SMS in response to the caller with the value read from an input.

First you have to extract the files from the compressed folder within the Library folder libraries contained within the installation folder of Arduino.

To first load the libraries using the following commands

#include “SIM900.h”

#include <SoftwareSerial.h>

Then load, uncomment properly, the files related to classes containing functions that we want to use for the management of phone calls and SMS.

#include “sms.h”

#include “call.h”

We will perform the initialization procedure in the setup. Set the pin to read the value which will then be sent via SMS, configure the serial communication and initialize the module with the function gsm.begin, and set the baud rate (usually for proper communication of data through GPRS is advisable not rise above 4800 baud).

At this point we enter the heart of the program, which will periodically check the status of incoming calls. To do this within the cycle loop will use the function call.CallStatusWithAuth saving the byte returned. In the case of incoming or in progress call, the sender (or recipient) number is stored in the string number.

Compared with the value stored CALL_INCOM_VOICE_AUTH, which describes an incoming call by a number in that set, we reject the call using the GSM.Hangup and after waiting 2 seconds, read the input value and send the message.The value read is an integer and must be first converted into a string using the function itoa.

Let us remember to insert a delay, inside the loop function, to ensure that the module is interrogated at intervals of not less than a second. Commands sent in rapid sequence could corrupt the stability of the module.

If we do not receive the result of proper initialization, you will need to check the power supply. Remember that it is recommended to use an external power source because the only power supplied by the USB port is not enought.

If the power is found to be correct, you should check that the file GSM.cpp, in the library are declared properly pin for the serial. Basically the new version uses pins 2 and 3, while the old version used pins 4 and 5.

#define _GSM_TXPIN_ 2

#define _GSM_RXPIN_ 3

The full program is as follows:

#include "SIM900.h"
#include <SoftwareSerial.h>
//carichiamo i file necessari allo sketch
#include "sms.h"
#include "call.h"

CallGSM call;            
SMSGSM sms;              

char number[20];
byte stat=0;
int value=0;
int pin=1;
char value_str[5];

void setup()
{
  pinMode(pin,INPUT);
  Serial.begin(9600);
  Serial.println("GSM GPRS Shield");
  //init the module
  if (gsm.begin(2400))
    Serial.println("\nstatus=READY");
  else Serial.println("\nstatus=IDLE");
};

void loop()
{
  stat=call.CallStatusWithAuth(number,1,3);
  if(stat==CALL_INCOM_VOICE_AUTH){
    call.HangUp();
    delay(2000);
    value=digitalRead(1);
    itoa(value,value_str,10);
    sms.SendSMS(number,value_str);
  }
  delay(1000);
};

 

EXAMPLE FOR INTERNET

We analyze one of the examples contained within the library to connect Arduino to the internet with GPRS connection.

We will make a program capable of receiving HTML content from a web page and save the first 50 characters.

Because we use only the functions relating to the Internet and HTTP, we load in addition to the standard library file, the file inetGSM.h

Instantiate an object management functions

InetGSM inet;

and as before we execute the initialization routine. Then we establish a GPRS connection. In this step you need to run the command “AT+CIFSR” that requires the provider the IP address assigned to the GSM module. This step is important. Some providers garantee the connection only if previously it’s made this request. Through the function gsm.WhileSimpleRead contained in the GSM class, we read the entire contents of the buffer. Once emptied the buffer, the sketch will go to the following functions.

At this point we are connected, we have to establish a TCP connection with the server, send a GET request to a web page and store the contents of the response in a previously declared array. All this is done by the function HttpGet in class inetGSM. In addition to the server and port (80 in the case of HTTP protocol), we have to indicate the path which contains the requested page.For example if you want to download the Wikipedia page on the Arduino to be reached at the following address it.wikipedia.org/wiki/Arduino_(hardware), the path will be /wiki/Arduino_ (hardware) while the server is it.wikipedia.org.

numdata=inet.httpGET(“it.wikipedia.org “, 80, “/wiki/Arduino_(hardware) “, msg, 50);

Obviously if we wish to save a greater number of characters of the answer, it is sufficient to initialize a string of larger dimensions, taking care not to saturate the RAM is made available by Arduino, otherwise we risk getting abnormal behavior, such as stalls or restarts.

#include "SIM900.h"
#include <SoftwareSerial.h>
#include "inetGSM.h"

InetGSM inet;              

char msg[50];
int numdata;
char inSerial[50];
int i=0;
boolean started=false;

void setup()
{
  Serial.begin(9600);
  Serial.println("GSM Shield testing.");
  if (gsm.begin(2400)){
    Serial.println("\nstatus=READY");
    started=true; 
  }
  else Serial.println("\nstatus=IDLE");

  if(started){
    if (inet.attachGPRS("internet.wind","", ""))
      Serial.println("status=ATTACHED");
    else Serial.println("status=ERROR");
    delay(1000);

    gsm.SimpleWriteln("AT+CIFSR");
    delay(5000);
    gsm.WhileSimpleRead();
    numdata=inet.httpGET("www.google.com", 80, "/", msg, 50);
    Serial.println("\nNumero di byte ricevuti:");
    Serial.println(numdata); 
    Serial.println("\nData recived:");
    Serial.println(msg);
  }
};
void loop()
{
};

 

The shield has various connectors to accept more GSM/GPRS modules manufactured by SIMCOM and mounted on breakout board. In addition to the popular SIM900, our new shield for Arduino supports the recent SIM908, which is an evolution and aims to capture the market of GSM/GPRS quad-band providing a variety of additional features that make it unique, especially in the field of low-cost products. The SIM908 implements a GPS with 42 channels, characterized by an excellent accuracy and by a very reduced time required to perform the first fix (1 second in mode “hot start” and 30 seconds with the mode “cold start”).
This module can be used powered by a lithium battery, and can charge it, greatly simplifying this process that would require dedicated hardware.

The SIM908 has two serial, used one for the GSM and the other for the GPS. More exactly, the first serial interface is provided with a UART which belongs to the lines TXD, RXD, DTR, which go outside through the contacts, respectively, 12, 14, 10 of connector; for the GPS, instead, the serial is GPSTXD (contact 4) and GPSRXD (pin 5). The first serial port is actually intended for total control of SIM908, then it can also configure the GPS receiver and ask him to provide data on the location, the number of satellites hooked, etc. From the second serial port (GPSTXD / GPSRXD) instead, go out continuously strings in standard NMEA GPS system.

 

 

THE GSM SHIELD LIBRARY

Providing also use the SIM908, the library for the management of this module has been modified to provide a quick access to all the new features made available, the new library is derived from that used for the SIM900 module, and is available on the Internet at http://code.google.com/p/gsm-shield-arduino/ .

Note that you can use the new library for managing mobile SIM900, provided you do not call functions dedicated to SIM908. While it is completely compatible using the sketch for the version without GPS with this new one.

Let’s consider some new features introduced: first of all has been added the function ForceON(); used to check the status of the module and to force the power on. The SIM908 supports the charge of lithium batteries, the module can be started to perform the charger without the management of the GSM network. If we want to avoid this mode and make sure it’s really turned on then you need to call the function mentioned above.

gsm.forceON();

Intended for the use of GPS (and battery), we made a class which you can instantiate an object with GPSGSM gps, after including its # include files “gps.h“, in order to invoke their functions by prefixing “GSM.” to the desired function.

This subdivision into different files is designed to minimize RAM usage: in fact, for example, all the variables used by the class on the GPS will not be allocated in memory will not be included if the relevant files using #include “gps.h”.This allows you to choose which variables to use.

As already mentioned, also for the management of the battery there ara functions which enable the measurement of the voltage and battery temperature; for practical reasons, occupying little memory, these have been included in the class of GPS. For use them, after including the file #include “gps.h” you must instantiate the object related with GPSGSM gps. In the next sections will show the control functions of the GPS and battery.

 

HOW TO USE THE SIM908 GPS 

Before using GPS, you need to make a small set-up: first let’s make a bridge on jumper J1 on the SIM908 Breakout (cod. FT971).

The bridge on J1 enables power to the GPS antenna.

This serves to bring power to the active GPS antenna. Next, load the sketch example (in the examples directory) called GSM_GPRS_GPS_Library_AT (or even GSM_GPRSLibrary_AT) and once launched and completed initialization send the following commands:

 

AT

AT+CGPSPWR=1

AT+CGSPRST=0

 

We wait a minute, at which point the GPS should be working, to verify

continue sending the command:

 

AT+CGPSINF=0

 

If you can see the coordinates, it means that everything is working and we can proceed with the standard use by the implemented functions.

 

char attachGPS() Follow the steps to activate the GPS: turn on the power and set the mode to “hot start”. gps.attachGPS()
char deattachGPS() power off, disabling the power supply to save energy. gps.deattachGPS()
char getStat() Check the GPS status, the possible outputs are:0: GPS not started.1: Fix not performed (can be caused by a signal of poor quality).2: Fix 2D run.3: Fix 3D executed. char stat;
stat=gps.getStat();
if(stat==3)
Serial.println(“FIXED”);
char getPar(char* str_long, char* str_lat, char* str_alt, char* str_time, char* speed); Save in variables, respectively, longitude, latitude, altitude, time and speed. char lon[10];
char lat[10];
char alt[10];
char time[15];
char vel[10];
gps.getPar(lon,lat,alt,time,vel);

 

Now we proceed with a simple example that allows us to understand how to get the coordinates from the GPS module SIM908 mounted on the shield, the firmware is described here:

 

#include "SIM900.h"

#include <SoftwareSerial.h>

#include "gps.h"              

GPSGSM gps;                   

char lon[10];   
char lat[10];   
char alt[10];   
char time[15];  
char vel[10];   
char stat;      
boolean started=false;

void setup()
{
  //Serial connection.
 Serial.begin(9600);

  Serial.println("GSM GPRS GPS Shield");

  if (gsm.begin(2400)){

    Serial.println("\nstatus=READY");
    gsm.forceON();              
    started=true; 
  }
  else Serial.println("\nstatus=IDLE");

  if(started){
    if (gps.attachGPS())
      Serial.println("status=GPSON");
    else Serial.println("status=ERROR");

    delay(20000);              

    stat=gps.getStat();        

              if(stat==1)
                            Serial.println("NOT FIXED");
              else if(stat==0)
                            Serial.println("GPS OFF");
              else if(stat==2)
                            Serial.println("2D FIXED");
              else if(stat==3)
                            Serial.println("3D FIXED");
              delay(5000);

              gps.getPar(lon,lat,alt,time,vel);
              Serial.println(lon);
              Serial.println(lat);
              Serial.println(alt);
              Serial.println(time);
              Serial.println(vel);
  }
};

void loop()

{

};

 

THE BATTERY

In order to use the lithium battery as the power source for our FT971 module that houses the SIM908 (note: the SIM900 is not able to manage the barrery charge) is sufficient to close the bridge on this shield called with CHRG and set on VEXT the second bridge near the battery connector.

Through the two library functions is possible to obtain the percentage of remaining charge, the battery voltage and the voltage read by the temperature sensor. In the case of applications poorly ventilated, with prolonged periods of work and in climatic conditions not exactly optimal, it is advisable to monitor this value to make sure that the battery works within the limits for a correct operation. The temperature can be calculated according to the relationship voltage/temperature sensor.

It is also possible to set the module so that automatically determine if the battery is working outside the permissible range, with consequent shutdown of the same.

To activate this mode, you need to send the command:

 

AT+CMTE=1

 

To disable it you have to send the command:

 

AT+CMTE=0

 

While to know which mode is configured must issue the command:

 

AT+CMTE?

 

To know the exact syntax of the functions and their return refer to Table:

 

char getBattInf(char* str_perc, char* str_vol); Save the remaining battery in percentage terms, and battery voltage. char str_perc[5];
char str_vol[6];
gps.getBattInf(str_perc,str_vol);
Serial.print(“BATTERY: ”);
Serial.print(str_perc);
Serial.println(“%”);
char getBattTVol(char* str_vol); Saves the voltage value of the temperature sensor. char str_Tvol[6];
gps.getBattTVol(str_Tvol);
Serial.println(str_Tvol);

Also in this case we see how to implement these functions in a sketch, referring to this sketch, which contains the corresponding code.

 

 

#include "SIM900.h"

#include <SoftwareSerial.h>

#include "inetGSM.h"

#include "gps.h"           

GPSGSM gps;                

char perc[5];              
char volt[6];              
char tvolt[6];             

long prevmillis=millis();              
int interval=10000;               

void setup()
{

  Serial.begin(9600);
  Serial.println("GSM GPRS GPS Shield.");
  if (gsm.begin(4800)){
    Serial.println("\nstatus=READY");
    gsm.forceON();  }

  else Serial.println("\nstatus=IDLE");

};

void loop()

{

  if(millis()-prevmillis>interval){     

    gps.getBattInf(perc,volt);          
    gps.getBattTVol(tvolt);             

    Serial.print("Battery charge: ");
    Serial.print(perc);
    Serial.println("%");

    Serial.print("Battery voltage: ");
    Serial.print(volt);
    Serial.println(" mV");

    Serial.print("Temperature sensor voltage: ");
    Serial.print(tvolt);
    Serial.println(" mV");  

    Serial.println("");

    prevmillis=millis();
  }
}

 

DEBUG MODE GSM & GPS SHIELD

During the use of the shield, sometimes you fail to get the desired results without understanding why, for help, libraries can be configured to provide output some debug messages during the execution of functions called. Inside the file GSM.h there is the following line:

 

//#define DEBUG_ON

 

Uncomment it, you are going to enable this mode, commenting, no diagnostic message will be shown on the serial output.

 

HOW TO USE THE GSM & GPS SHIELD WITH ARDUINO MEGA

For problems with the RAM, or simply for projects that require a larger number of input/output, we can use with the GSM/GPRS & GPS shield the Arduino Mega.  Thanks to four serial port, we can use one of these instead of the serial software to communicate with the shield.

With the latest release, the library can be used completely with Arduino Mega. You must open the file GSM.h and select the tab used appropriately commenting lines of code.

Using the shield with Arduino Mega we comment as follows:

 

//#define UNO

#define MEGA

If we want to use Arduino UNO:

#define UNO

//#define MEGA

 

Similarly, also the file HWSerial.h, must be configured. As before, we see the first example for Arduino Mega:

 

#define MEGA

 

Using the file HWSerial.h is not necessary to define the possible use with Arduino Uno, as implemented in the class it is only used by the hardware serial.

The library uses the serial Serial0 (TX 1 RX 0) for external communication and the serial Serial1 (RX 18 TX 19) to communicate with SIM900 and SIM908. Nothing prevents you replace every occurrence of Serial1 with Serial2 or one that you prefer.

Please note that to use the serial hardware you need to create the connection between the shield and Arduino Mega using a bridge: the TX pin of the shield must be connected to TX1 18 and the RX pin with the RX1 19.

 

 

THE STORE

 

 

 

 

-->-->-->-->-->-->
-->-->

Robot shield for Arduino

-->-->-->-->

 

The idea behind this post is to bring together some robot designs and trasform them in a new device with new hardware and standard software (arduino of course) and so easier to use.  These robots have three things in common: a mechanical structure, the hardware and the software. While the mechanical part is necessarily different, we wanted to understand if there was a hardware board that could be common, with a unique development system. The choice, quite obviously, has the Arduino board, which with its development environment is perfect to create similar projects. The first consideration that came to our mind is like the Arduino board can manage a large number of servos, eight in the case of the robot SPIDER. Arduino can be powered through the plug with a voltage between 6 to 12 volts, his voltage regulator provides the 5 V stabilized, necessary for the operation of our shield. We could  power our robot with rechargeable batteries. A standard servo requires a supply voltage of 4.8 to 6 volts, easily obtainable with four batteries in series, at full charge, provide 1.5 x 4 = 6 volts but towards the complete discharge provide just 1.0 x 4 = 4 volts. We are not in optimal conditions for the servos.  Throughout this reasons we decided to create a special shield, already prepared for all these functions, it is easy to install and use.

We see now the considerations that led us to the design of this shield:

        must have a high voltage range

        will provide a stabilized output for the servos

        will provide power to the Arduino

        must be equipped with an obstacle sensor

        must have a receiver for remote control

        must read the battery

 

We can assume to power our robot with a single battery pack with a voltage between 6 and 12 volts, so for example two cells or 6-8 LiPo NiMh or NiCd cells. The servos works at 5Volt, so we should get this stabilized voltage starting from input voltage of 6-12 volts. The optimal solution is the use of a switching step-down regulator which ensures efficiency exceeding 80% in every situation.

Just the integrated LM2576-5 contains all the elements to build a switching power supply, just add an inductor, a diode and a capacitor. It can deliver a maximum current of 3A and accepts input voltages between 4 and 40volt.

 

 

Analysing the wiring diagram you can see the connector BAT which will connect the battery pack to the switch and the voltage regulator LM2576, the resistance R5 and the led LD1 are used only to detect the presence of the voltage. The stabilized voltage output from the LM2576 will be used to power all the servos, while the Arduino is powered directly from the battery pack, taking the tension just after the switch (Vin).

For reading the battery voltage will use an analog input of Arduino (A0). The two resistors R1 and R2 reduce the voltage to a value between 0 and 20 volts to a value of 0-5Volt. We chose these specific values of resistance because, by reading the analog voltage with Arduino, it is sufficient to divide the data acquired by 50 to obtain the value of the voltage in volts.

As obstacle sensor we chose the ultrasonic sensor model SRF05 that, thanks to its shape, recalls two eyes and improves the aesthetic appearance of our robot. To operate, we use a digital line connected to PIN11.

As remote control we opt for a economical infrared system; is sufficient to install an IR receiver compatible with the normal commercial remote controls, such as the integrated PNA4602. It will be sufficient a normal remote control of those used for TVs or VCRs to send commands to our robot in a simple and economic way. The shield provides the Arduino reset button, a button for general use and a LED connected to pin 13 of Arduino.

 

 

BOM

R1: 56 kohm
R2: 18 kohm
R3: 470 ohm
R4: 100 ohm
R5: 470 ohm

C1: 10 µF 63 VL
C2: 470 µF 25 VL
C3: 1000 µF 16 VL
C4: 100 nF
C5: 100 nF
C6: 10 µF 63 VL

LD1: LED 3 mm red
LD2: LED 3 mm green

U1: LM2576-5

SW1: switch

P1: Microswitch
RST: Microswitch

IR: IR38DM

L1: 100 µH 2A

D1: 1N5819

SRF05: SRF05

 

 

The Robot are three, corresponding to the robots Filippo, Bipe and Spider.

 

Filippo robot

Filippo is a biped robot whose movements are assigned to only two servos, but with this robot you can experiment with robotics without spending large sums. It is able to walk and turn around, then you can direct it in any direction, enabling those who are beginning to become familiar with the servos and how they can interact with mechanical parts. Its assembly is facilitated because all the pieces fit over each other and it is sufficient sorder to fix them permanently, as an alternative you can use the epoxy glue.

 

After the mechanical assembly, fix the Arduino board, with its shield, on top, the sensor SRF05 must look in front of the robot. The servos have to be wired as indicated in Table.

 

Connecting servos with Filippo robot

Servo

Arduino Pin Connector shiled Role
Servo 0 2 S1 Tilt (front servo)
Servo 1 3 S2 Step (servo in the bottom)


 

For the power use 6 or 8 NiCd or NiMh rechargeable batteries size AA, they should be entered in two separate holder and connected in series.  The battery holder are positioned one on the right and one on the left of the two servos, for their wiring must use two clips for batteries connected in series to 9 V.

We recommend you to program the Arduino before connecting the servos to prevent any previous program provides the wrong signals to the servos that might go crazy.

 

Program Arduino with the sketch

// FILIPPO ARDUINO
// by Segatello Mirco per ElettronicaIN 
// compilato con Arduino21

#include <Servo.h> 
#include <IRremote.h> 
#include <EEPROM.h>

#define RECV_PIN 10   // pin per sensore IR
#define PING_PIN 11   // pin per sensore RADAR
#define       P1 12   // pin per pulsante

#define STNB_CODE1 0x81D    // Stop Philips TV remote (AZIONE STOP)
#define STNB_CODE2 0x1D     // Codice alternativo
#define WALK_CODE1 0x81C    // Play Philips TV remote (AZIONE CAMMINA)
#define WALK_CODE2 0x1C     // Codice alternativo
#define SPEEDUP_CODE1 0x820 // Prg+ Philips TV remote (AZIONE PIù VELOCE)
#define SPEEDUP_CODE2 0x20  // Codice alternativo
#define SPEEDDW_CODE1 0x821 // Prg- Philips TV remote (AZIONE PIù LENTA))
#define SPEEDDW_CODE2 0x21  // Codice alternativo
#define LEFT_CODE1    0x2C  // Left Philips remote (RUOTA SX)
#define LEFT_CODE2    0x82C  // Codice alternativo
#define RIGHT_CODE1    0x2B  // Right Philips remote (ROUTA DX)
#define RIGHT_CODE2    0x82B  // Codice alternativo

#define MODE_OFF       0    // Servi OFF
#define MODE_STANDBY   1    // Servi armati in posizione di riposo
#define MODE_INWALK    2    // Assume la posizione di partenza
#define MODE_WALK      3    // Cammina in avanti
#define MODE_INSTANDBY 4    // Assume la posizione di standby
#define MODE_LEFT      5    // Si gira verso sinistra
#define MODE_RIGHT     6    // Si gira a destra
#define MODE_REVWALK   7    // Cammina all'indietro

IRrecv irrecv(RECV_PIN);
decode_results results;

int RobotMode = MODE_OFF;   
int TimeOneStep = 2000;     // Velocità di esecuzione
int AmpPasso = 30;          // Ampiezza del passo (da 5 a 40)
int IncPasso = 15;          // Inlinazione durante la camminata (da 5 a 20)
int AmpRuota = 30;          // Ampiezza delle gambe durante la rotazione (da 5 a 40)
int IncRuota = 18;          // Inclinazione durante la rotazione (da 5 a 20)

Servo servo0, servo1;       // oggetti servo

int leg_ntr[8] = {90, 90};  //posizione neutrale dei servi
int leg_old[8] = {90, 90};  //posizione precedente dei servi
int leg[8];                 //posizione attuale dei servi
int i;

void setup() 
{ 
  Serial.begin(9600);       // Start seriale
  Serial.println("FILIPPO Aduino V1.0");
  irrecv.enableIRIn();      // Start ricevitore IR  
  irrecv.blink13(true);     // Lampeggio LED in ricezione IR attivo
  pinMode(P1, INPUT);       // Pulsante 
  digitalWrite(P1, HIGH);   // Abilita pull-up
  levelBat();               // Verifica stato batteria  
  Serial.println("Livello batteria OK.");  
  Serial.println("Recupero dati posizione neutro servi...");
  readNeutral();
  Serial.println("Inizializzo Servi...");  
  initServo();              // Inizializza servi
  Serial.println("Invia 'obs' per testare il sensore di ostacoli");
  Serial.println("Invia 'lev' per testare il livello della batteria"); 
  inStandby();              // Robot in attesa di comando  
} 

void loop() 
{ 
  if (irrecv.decode(&results)) IRcommand();
  if (RobotMode==MODE_WALK)   walk();
  if (RobotMode==MODE_LEFT)   leftWalk();  
  if (RobotMode==MODE_RIGHT)   rightWalk();

  if (digitalRead(P1)==0) P1Press(); 

  if (RobotMode==MODE_STANDBY) 
  {
    if (Serial.available() > 2 )  ReceiveData();  
  }  
  else 
  {  
    // verifica livello batteria e presenza ostacoli
    levelBat();    
    int obstacle = readDistance();    
    if (obstacle < 20){
      Serial.println("Rilevato ostacolo!");   
      inStandby();  }
  }  
} 

void readNeutral()
{
  // Recupera dalla EEPROM la posizione neutrale dei servi
  byte value;
  Serial.print("Neutro dei Servi: ");      
  for (byte adress=0; adress<2; adress++) 
  {
     value = EEPROM.read(adress);
     if ((80<value) && (value<100))
     {
          leg_ntr[adress] = value;
          Serial.print(value, DEC);
          Serial.print("  ");
     }     
     else     
     {
       leg_ntr[adress] = 90;
     }  
   }
   Serial.println();
}  

void ReceiveData() 
{
    // Arrivati dati dalla USB
    byte startbyte, data_hight, data_low, data;    
    Serial.print("Receive data USB     "); 
    startbyte = Serial.read();
    data_hight = Serial.read();    
    data_low= Serial.read();
    // richiesta livello batteria
    if ( (startbyte=='l') && (data_hight=='e') && (data_low=='v'))
    {
      levelBat();     
      Serial.flush();  // svuota il buffer in ricezione  
      exit;
    }
    // richiesta distanza ostacolo
    if ( (startbyte=='o') && (data_hight=='b') && (data_low=='s'))
    {
      int obstacle = readDistance();
      Serial.print("Ostacolo a ");
      Serial.print(obstacle, DEC);    
      Serial.println(" cm");
      if (obstacle<20)  inStandby();  
      Serial.flush();  // svuota il buffer in ricezione 
      exit;
    }    
    // impostazione neutro servo
    if ((data_hight >= '0') && (data_hight <= '9') && (data_low >= '0') && (data_low <= '9')) {      
      data = (data_hight-48)*10+(data_low-48);
      if ((80 <= data) && (data <= 100)) {
         if (startbyte=='a') {
           leg_ntr[0] = data;
           EEPROM.write(0, data);
           printValue('a', data);
         }  
         if (startbyte=='b') {
           leg_ntr[1] = data;
           EEPROM.write(1, data);
           printValue('b', data);           
         }
      inStandby();         // aggiorna posizione neutro dei servi
      }
    }
    Serial.flush();  // svuota il buffer in ricezione   
}  

void printValue(byte servo, byte dt)
{
  Serial.print ("Set Servo: ");
  Serial.print (servo);
  Serial.print (" to ");
  Serial.println(dt,DEC);        
}  

void IRcommand()
{
    // E' arrivato un comando via IR
    Serial.print("IR code= ");
    Serial.println(results.value, HEX);  // ECO su serial monitor per sapere il codice arrivato

    if (results.value == WALK_CODE1 || results.value == WALK_CODE2)  inWalk();
    else if (results.value == LEFT_CODE1 || results.value == LEFT_CODE2)  inLeft();     
    else if (results.value == RIGHT_CODE1 || results.value == RIGHT_CODE2)  inRight();       
    else if (results.value == STNB_CODE1 || results.value == STNB_CODE2)  inStandby();   

    else if (results.value == SPEEDUP_CODE1 || results.value == SPEEDUP_CODE2) {
      if (TimeOneStep > 1000) TimeOneStep -= 500; }
    else if (results.value == SPEEDDW_CODE1 || results.value == SPEEDDW_CODE2) {
      if (TimeOneStep < 4000) TimeOneStep += 500; }
    Serial.print("TimeOneStep= ");      
    Serial.println(TimeOneStep);
    irrecv.resume(); // Resume decoding   
}  

void P1Press()
{
  // E' stato premuto il pulsante   
  while (digitalRead(P1)==0) delay(100);  
  if (RobotMode==MODE_WALK)  inStandby();            
  else if (RobotMode==MODE_STANDBY) inWalk(); 
}  

void levelBat()
{
  // controllo livello batteria  
  int VbatRAW = analogRead(A0);
  float Vbat = float(VbatRAW)/50;
  Serial.print("Vbat= ");
  Serial.println(Vbat, DEC);     
  if (Vbat<6.0)   {
    Serial.println("Livello batteria basso!");    
    inOff();    
  }  
}

void initServo()  
{
  // posizione iniziale dei servi
  servo0.attach(2);  // connette servo 
  delay(200);
  servo1.attach(3);  // connette servo 
  delay(200);    
  Serial.println("Servi inizializzati.");  
}

void inOff()
{
  // Spegne tutti i servi
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1]; 
  setServo();  
  servo0.detach();  // sconnette servo 
  servo1.detach();  // sconnette servo 
  RobotMode = MODE_OFF;     
  // Da questo modalità si deve spegnere il robot e ricaricare le batterie
}  

void inStandby()
{
  // Posiziono tutti i servi in posizione neutrale
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1];      
  setServo();  
  RobotMode = MODE_STANDBY;  
  Serial.println("Sono in Standby...");  
}  

void inWalk()
{
  // Si porta in posizione di passo partendo da fermo  
  leg[0] = leg_ntr[0]+IncPasso;//inclinazione
  leg[1] = leg_ntr[1];
  setServo();  

  RobotMode = MODE_WALK;
  Serial.println("Walk Mode...");   
}

void walk()
{
  // Coordinate per eseguire un passo  
  leg[0] = leg_ntr[0]+IncPasso;//piede SX in avanti
  leg[1] = leg_ntr[1]+AmpPasso;
  setServo();  

  leg[0] = leg_ntr[0]-IncPasso;//inclinazione
  leg[1] = leg_ntr[1]+AmpPasso;       
  setServo();   

  leg[0] = leg_ntr[0]-IncPasso;//passo DX
  leg[1] = leg_ntr[1]-AmpPasso;  
  setServo();

  leg[0] = leg_ntr[0]+IncPasso;//inclinazione
  leg[1] = leg_ntr[1]-AmpPasso;       
  setServo();         
}

void inLeft()
{
  // Si porta in posizione per ruotare  
  leg[0] = leg_ntr[0]+IncRuota;//inclinazione
  leg[1] = leg_ntr[1];
  setServo();         

  RobotMode = MODE_LEFT;
  Serial.println("Left Mode...");   
}

void leftWalk()
{
      //passo 1      
  leg[0] = leg_ntr[0]+IncRuota;//fa un passo
  leg[1] = leg_ntr[1]-AmpRuota;      
  setServo();        

      //passo 2      
  leg[0] = leg_ntr[0];//piedi paralleli
  leg[1] = leg_ntr[1]-AmpRuota;      
  setServo();   

      //passo 3      
  leg[0] = leg_ntr[0];//sforbiciata
  leg[1] = leg_ntr[1]+AmpRuota;     
  setServo(); 

      //passo 4      
  leg[0] = leg_ntr[0]-IncRuota;//inclinazione
  leg[1] = leg_ntr[1]+AmpRuota;     
  setServo();    

      //passo 5      
  leg[0] = leg_ntr[0]-IncRuota;//passo
  leg[1] = leg_ntr[1]-AmpRuota;     
  setServo();         

       //passo 6      
  leg[0] = leg_ntr[0];//piedi paralleli
  leg[1] = leg_ntr[1]-AmpRuota;     
  setServo();       

      //passo 7      
  leg[0] = leg_ntr[0];//sforbiciata
  leg[1] = leg_ntr[1]+AmpRuota;     
  setServo();      

      //passo 8      
  leg[0] = leg_ntr[0]+IncRuota;//sforbiciata
  leg[1] = leg_ntr[1]+AmpRuota;     
  setServo();     
}

void inRight()
{  
  // Si porta in posizione per ruotare  
      //passo 0  inclinazione
  leg[0] = leg_ntr[0]+IncRuota;
  leg[1] = leg_ntr[1];
  setServo();         

  RobotMode = MODE_RIGHT;
  Serial.println("Right Mode...");   
}

void rightWalk()
{
      //passo 1  passo    
  leg[0] = leg_ntr[0]+IncRuota;
  leg[1] = leg_ntr[1]+AmpRuota;      
  setServo();        

      //passo 2 piedi paralleli     
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1]+AmpRuota;      
  setServo();   

      //passo 3  sforbiciata    
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1]-AmpRuota;     
  setServo();

      //passo 4 inclinazione     
  leg[0] = leg_ntr[0]-IncRuota;
  leg[1] = leg_ntr[1]-AmpRuota;     
  setServo();    

      //passo 5  passo    
  leg[0] = leg_ntr[0]-IncRuota;
  leg[1] = leg_ntr[1]+AmpRuota;     
  setServo();         

       //passo 6 piedi paralleli     
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1]+AmpRuota;     
  setServo();       

      //passo 7 sforbiciata
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1]-AmpRuota;     
  setServo();         

      //passo 8 inclinazione     
  leg[0] = leg_ntr[0]+IncRuota;
  leg[1] = leg_ntr[1]-AmpRuota;     
  setServo();   
} 

void setServo() 
{  
   // Posiziona i servi alle coordinate specificate da leg[]  
   for (i=0; i<18; i++) {
       servo0.write(leg_old[0] + i*(leg[0]-leg_old[0])/18);  
       servo1.write(leg_old[1] + i*(leg[1]-leg_old[1])/18);        
       delay(TimeOneStep/4/18);
    }   
    leg_old[0]=leg[0];
    leg_old[1]=leg[1];       
}

long readDistance()
{
  // Procedura per leggere la presenza di ostacoli
  // Viene generato un PING di 2usec ed atteso l'ECO di risposta
  long duration, cm;
  pinMode(PING_PIN, OUTPUT);
  digitalWrite(PING_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(PING_PIN, HIGH);
  delayMicroseconds(5);
  digitalWrite(PING_PIN, LOW);

  // Lo stesso pin che genera il trigger è usato per la lettura
  // del segnale di ritorno
  pinMode(PING_PIN, INPUT);
  duration = pulseIn(PING_PIN, HIGH);

  // ritorna distanza ostacolo in cm
  return duration / 29 / 2;
}

Send the serial command ‘obs‘ for read the sensor SRF05 and the command ‘lev‘ to check the battery level. Make sure that the voltage read corresponds to the real value of the batteries, simply make a voltage measurement with a multimeter. Now set the neutral of the servos, in fact the robot to function properly must be perfectly centered. To center the servo which acts to tilt the robot you have to send the command ‘axx‘ where xx is the position. This data can assume values between 80 and 100 with the center point 90, if you can not set the servo to remain within these values you have to physically move the servo. You can modify this value if it found a tendency to deviate from the straight line when walking. Now regulate the step servo and sets the neutral with bxx command, where xx is the position to be allocated (value between 80 and 100). You are now ready for test, you can use the remote control to activate functions or use the button on the shield but it will only start the walk.

 

All functions have a speed of execution that can be changed by remote control with keys prog+ and prog-, many other parameters can be modified to adapt the software to different operating requirements.

The sketch begins by including the libraries dedicated to the use of the servos, the IR control and management of EEPROM:

 

Code 1

#include <Servo.h>
#include <IRremote.h>
#include <EEPROM.h>

 

The servo library is already implemented in the IDE of Arduino.

The EEPROM library, also available, provides controls to manage the non-volatile memory, we use it to save the position of the neutral servos so as not having to set each time.

The third library IRremote is used to manage the robot by remote control and must be downloaded from http://github.com/shirriff/Arduino-IRremote, for its operation is sufficient to specify which pin is connected to the sensor receiving IR signals (D10 in our shield). To find out if they arrived from the sensor data must test the status of the variable irrecv.decode (& results), but the code is contained in the variable came results.value.

Just compare the code recived with the reference code for the remote to know which button was pressed, so we specify at the beginning of the sketch of the codes for each button.

 

Code 2

#define STNB_CODE1 0x81D    // Stop Philips TV remote (STOP)
#define STNB_CODE2 0x1D     // alternative code
#define WALK_CODE1 0x81C    // Play Philips TV remote (WALK)
#define WALK_CODE2 0x1C // alternative code
#define SPEEDUP_CODE1 0x820 // Prg+ Philips TV remote (+ SPEED)
#define SPEEDUP_CODE2 0x20  // alternative code
#define SPEEDDW_CODE1 0x821 // Prg- Philips TV remote (-SPEED)
#define SPEEDDW_CODE2 0x21  // alternative code
#define LEFT_CODE1    0x2C  // Left Philips remote (SX wheel)
#define LEFT_CODE2    0x82C  // alternative code
#define RIGHT_CODE1    0x2B  // Right Philips remote (DX wheel)
#define RIGHT_CODE2    0x82B  // alternative code

 

As you can see each button is associated with two codes (CODE1 and CODE2) this is because the codes are sent alternately every time you press the button, instead of repeating the same code if the button is pressed. So if you press the play button will send the code 0x81C and so long as the button is pressed, if you release the button and press it sends the code 0x1C, so alternately.

The sketch is intended for use with remote controls which use the encoding Philips, the most commonly used in television. If you use a different remote control the code of the buttons do not match and you have to change the codes listed above.

Now let’s see what parameters can be modified by the program to adapt the movements:

 

Code 3

int TimeOneStep = 2000;    
int AmpPasso = 30;         
int IncPasso = 15;         
int AmpRuota = 30;       
int IncRuota = 18;

 

 

TimeOneStep is the initial value of the time taken to perform a step, can be changed by remote control from a minimum of 1 sec to a maximum of 4 sec.

AmpPasso is the maximum amplitude in degrees of opening of the legs during walking, its value can vary from a minimum of 5 to a maximum of 40.

IncPasso is the maximum inclination of the robot during the walk, its value can vary from a minimum of 5 to a maximum of 20. This value is to ensure the robot to keep balance on one leg while performing a step.

AmpRuota is the maximum amplitude in degrees of opening of the legs during the rotation, its value can change from a minimum of 5 to a maximum of 40.

IncRuota is the maximum inclination of the robot during the rotation, its value can change from a minimum of 5 to a maximum of 20.

 

 

ROBOT BIPE

We see now to the second robot, is called BIPE.

The mechanical is made of PCB and assembly is made by soding together the various components to ensure the strength needed to support the weight of the components.

The control board based on Arduino + shield is positioned on the back of the robot while the battery pack, should be placed at the front. Let’s say that for our tests we used a battery composed of two cell 850mAh LiPo which, being small and light, are easily placed and not weigh down the structure. To properly position the sensor SRF05 you must use a small adapter with a strip made of male-female, as those used on the Arduino shield, angled 90 °.

Connecting servos with robot BIPE

Servo Arduino Pin Connector shield Function
Servo 0 2 S1 left hip
Servo 1 3 S2 left knee
Servo 2 4 S3 left foot
Servo 3 5 S4 right hip
Servo 4 6 S5 right knee
Servo 5 7 S6 right foot

 

For setting follow the same instructions for the robot Filippo, the sketch retains the same structure of the software used with Filippo, with the necessary modifications and add.

 

// BIPE ARDUINO
// by Segatello Mirco per ElettronicaIN 
// compilato con Arduino21

#include <Servo.h> 
#include <IRremote.h> 
#include <EEPROM.h>

#define RECV_PIN 10   // pin per sensore IR
#define PING_PIN 11   // pin per sensore RADAR
#define       P1 12   // pin per pulsante

#define STNB_CODE1 0x81D    // Stop Philips TV remote
#define STNB_CODE2 0x1D     // Codice alternativo
#define WALK_CODE1 0x81C    // Play Philips TV remote
#define WALK_CODE2 0x1C     // Codice alternativo
#define SPEEDUP_CODE1 0x820 // Prg+ Philips TV remote
#define SPEEDUP_CODE2 0x20  // Codice alternativo
#define SPEEDDW_CODE1 0x821 // Prg- Philips TV remote
#define SPEEDDW_CODE2 0x21  // Codice alternativo
#define LEFT_CODE1    0x2C  // Left Philips remote
#define LEFT_CODE2    0x82C  // Codice alternativo
#define RIGHT_CODE1    0x2B  // Right Philips remote
#define RIGHT_CODE2    0x82B  // Codice alternativo
#define VOLUP_CODE1   0x810 // Volume+
#define VOLUP_CODE2   0x10  // codice alternativo
#define VOLDW_CODE1   0x811 //Volume-
#define VOLDW_CODE2   0x11 //codice alternativo

#define PRG1_CODE1 0x801 // Program 1
#define PRG1_CODE2 0x1 // Program 1
#define PRG2_CODE1 0x802 // Program 2
#define PRG2_CODE2 0x2 // Program 2

#define MODE_OFF       0    // Servi OFF
#define MODE_STANDBY   1    // Servi armati in posizione di riposo
#define MODE_INWALK    2    // Assume la posizione di partenza
#define MODE_WALK      3    // Cammina in avanti
#define MODE_INSTANDBY 4    // Assume la posizione di standby
#define MODE_LEFT      5    // Si gira verso sinistra
#define MODE_RIGHT     6    // Si gira a destra
#define MODE_REVWALK   7    // Cammina all'indietro

IRrecv irrecv(RECV_PIN);
decode_results results;

int RobotMode = MODE_OFF;   
int TimeOneStep = 4000;     // Velocità di esecuzione
int AmpPasso = 10;          // Ampiezza del passo (da 5 a 20)
int AmpRuota = 12;          // Ampiezza durante la rotazione (da 5 a 20)
int IncPasso = 8;           // Inlinazione durante la camminata (da 5 a 10)

Servo servo0, servo1, servo2, servo3,
      servo4, servo5, servo6, servo7;  // oggetti servo
      // Servo 6 e 7 possono essere usati per le braccia!

int leg_ntr[8] = {90, 90, 90, 90, 90, 90, 90, 90}; //posizione neutrale dei servi
int leg_old[8] = {90, 90, 90, 90, 90, 90, 90, 90}; //posizione precedente dei servi
int leg[8];                 //posizione attuale dei servi
int i;

void setup() 
{ 
  Serial.begin(9600);       // Start seriale
  Serial.println("SIDERIN Aduino V1.0");
  irrecv.enableIRIn();      // Start ricevitore IR  
  irrecv.blink13(true);     // Lampeggio LED in ricezione IR attivo
  pinMode(P1, INPUT);       // Pulsante 
  digitalWrite(P1, HIGH);   // Abilita pull-up
  levelBat();               // Verifica stato batteria  
  Serial.println("Livello batteria OK.");  
  Serial.println("Recupero dati posizione neutro servi...");
  readNeutral();
  Serial.println("Inizializzo Servi...");  
  initServo();              // Inizializza servi
  Serial.println("Invia 'obs' per testare il sensore di ostacoli");
  Serial.println("Invia 'lev' per testare il livello della batteria"); 
  inStandby();              // Robot in attesa di comando  
} 

void loop() 
{ 
  if (irrecv.decode(&results)) IRcommand();
  if (RobotMode==MODE_WALK)   walk();
//  if (RobotMode==MODE_REVWALK) walkReverse();
  if (RobotMode==MODE_LEFT)   leftWalk();  
  if (RobotMode==MODE_RIGHT)   rightWalk();

  if (digitalRead(P1)==0) P1Press(); 

  if (RobotMode==MODE_STANDBY) 
  {
    if (Serial.available() > 2 )  ReceiveData();  
  }  
  else 
  {  
    levelBat();    
    int obstacle = readDistance();    
    if (obstacle < 20)  inStandby();  
  }  
} 

void readNeutral()
{
  // Recupera dalla EEPROM la posizione neutrale dei servi
  byte value;
  Serial.print("Neutro dei Servi: ");      
  for (byte adress=0; adress<6; adress++) 
  {
     value = EEPROM.read(adress);
     if ((80<value) && (value<100))
     {
          leg_ntr[adress] = value;
          Serial.print(value, DEC);
          Serial.print("  ");
     }     
     else     
     {
       leg_ntr[adress] = 90;
     }  
   }
   Serial.println();
}  

void ReceiveData() 
{
    // Arrivati dati dalla USB
    byte startbyte, data_hight, data_low, data;    
    Serial.print("Receive data USB     "); 
    startbyte = Serial.read();
    data_hight = Serial.read();    
    data_low= Serial.read();
    // richiesta livello batteria
    if ( (startbyte=='l') && (data_hight=='e') && (data_low=='v'))
    {
      levelBat();     
      Serial.flush();  // svuota il buffer in ricezione  
      exit;
    }
    // richiesta distanza ostacolo
    if ( (startbyte=='o') && (data_hight=='b') && (data_low=='s'))
    {
      int obstacle = readDistance();
      Serial.print("Ostacolo a ");
      Serial.print(obstacle, DEC);    
      Serial.println(" cm");
      if (obstacle<20)  inStandby();  
      Serial.flush();  // svuota il buffer in ricezione 
      exit;
    }    
    // impostazione neutro servo
    if ((data_hight >= '0') && (data_hight <= '9') && (data_low >= '0') && (data_low <= '9')) {      
      data = (data_hight-48)*10+(data_low-48);
      if ((80 <= data) && (data <= 100)) {
         if (startbyte=='a') {
           leg_ntr[0] = data;
           EEPROM.write(0, data);
           printValue('a', data);
         }  
         if (startbyte=='b') {
           leg_ntr[1] = data;
           EEPROM.write(1, data);
           printValue('b', data);           
         }
         if (startbyte=='c') {
           leg_ntr[2] = data;
           EEPROM.write(2, data);
           printValue('c', data);                  
         }  
         if (startbyte=='d') {
           leg_ntr[3] = data;
           EEPROM.write(3, data);
           printValue('d', data);                    
         }  
         if (startbyte=='e') {
           leg_ntr[4] = data;
           EEPROM.write(4, data);
           printValue('e', data);                   
         }
         if (startbyte=='f') {
           leg_ntr[5] = data;
           EEPROM.write(5, data);
           printValue('f', data);                   
         }
      inStandby();         // aggiorna posizione neutro dei servi
      }
    }
    Serial.flush();  // svuota il buffer in ricezione   
}  

void printValue(byte servo, byte dt)
{
  Serial.print ("Set Servo: ");
  Serial.print (servo);
  Serial.print (" to ");
  Serial.println(dt,DEC);        
}  

void IRcommand()
{
    // E' arrivato un comando via IR
    Serial.println(results.value, HEX);  // ECO su serial monitor per sapere il codice arrivato

    if (results.value == WALK_CODE1 || results.value == WALK_CODE2)   inWalk();     
    else if (results.value == LEFT_CODE1 || results.value == LEFT_CODE2)  inLeft();     
    else if (results.value == RIGHT_CODE1 || results.value == RIGHT_CODE2)  inRight();       
    else if (results.value == STNB_CODE1 || results.value == STNB_CODE2)  inStandby();   

    else if (results.value == PRG1_CODE1 || results.value == PRG1_CODE2) {
      if (RobotMode==MODE_STANDBY) kick(); }

    else if (results.value == PRG2_CODE1 || results.value == PRG2_CODE2)  {
       if (RobotMode==MODE_STANDBY)  bow(); }

    else if (results.value == SPEEDUP_CODE1 || results.value == SPEEDUP_CODE2) {
      if (TimeOneStep > 1000) TimeOneStep -= 200; }
    else if (results.value == SPEEDDW_CODE1 || results.value == SPEEDDW_CODE2) {
      if (TimeOneStep < 2000) TimeOneStep += 200; }
    Serial.print("TimeOneStep= ");      
    Serial.println(TimeOneStep);
    irrecv.resume(); // Resume decoding   
}  

void P1Press()
{
  // E' stato premuto il pulsante   
  while (digitalRead(P1)==0) delay(100);  
  if (RobotMode==MODE_WALK)  inStandby();            
  else if (RobotMode==MODE_STANDBY) inWalk(); 
}  

void levelBat()
{
  // controllo livello batteria  
  int VbatRAW = analogRead(A0);
  float Vbat = float(VbatRAW)/50;
  Serial.print("Vbat= ");
  Serial.println(Vbat, DEC);     
  if (Vbat<6.0)   {
    Serial.println("Livello batteria basso!");    
    inOff();    
  }  
}

void initServo()  
{
  // posizione iniziale dei servi
  servo0.attach(2);  // connette servo 
  delay(200);
  servo1.attach(3);  // connette servo 
  delay(200);  
  servo2.attach(4);  // connette servo 
  delay(200);
  servo3.attach(5);  // connette servo 
  delay(200);  
  servo4.attach(6);  // connette servo 
  delay(200);
  servo5.attach(7);  // connette servo 
  delay(200);  
  servo6.attach(8);  // connette servo 
  delay(200);
  servo7.attach(9);  // connette servo 
  delay(200);  
  Serial.println("Servi inizializzati.");  
}

void inOff()
{
  // Spegne tutti i servi
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5];   
  leg[6] = 90;
  leg[7] = 90;    
  setServo();  
  servo0.detach();  // sconnette servo 
  servo1.detach();  // sconnette servo 
  servo2.detach();  // sconnette servo 
  servo3.detach();  // sconnette servo 
  servo4.detach();  // sconnette servo 
  servo5.detach();  // sconnette servo 
  servo6.detach();  // sconnette servo 
  servo7.detach();  // sconnette servo   
  RobotMode = MODE_OFF;     
  // Da questo modalità si deve spegnere il robot e ricaricare le batterie
}  

void inStandby()
{
  // Posiziono tutti i servi in posizione neutrale
  leg[0] = leg_ntr[0];
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5];
  leg[6] = 90;
  leg[7] = 90;      
  setServo();  
  RobotMode = MODE_STANDBY;  
  Serial.println("Sono in Standby...");  
}  

void inWalk()
{
  // Si porta in posizione di passo partendo da fermo  
  leg[0] = leg_ntr[0];//inclinazione
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5]-IncPasso*2;  
  setServo();    
  leg[0] = leg_ntr[0]+AmpPasso;//passo DX da fermo
  leg[1] = leg_ntr[1]+AmpPasso;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]+AmpPasso;
  leg[4] = leg_ntr[4]+AmpPasso;
  leg[5] = leg_ntr[5]-IncPasso*2;      
  setServo();
  RobotMode = MODE_WALK;
  Serial.println("Walk Mode...");   
}

void setServo() 
{  
   // Posiziona i servi alle coordinate specificate da leg[]  
   for (i=0; i<18; i++) {
       servo0.write(leg_old[0] + i*(leg[0]-leg_old[0])/18);  
       servo1.write(leg_old[1] + i*(leg[1]-leg_old[1])/18);        
       servo2.write(leg_old[2] + i*(leg[2]-leg_old[2])/18);  
       servo3.write(leg_old[3] + i*(leg[3]-leg_old[3])/18);      
       servo4.write(leg_old[4] + i*(leg[4]-leg_old[4])/18);  
       servo5.write(leg_old[5] + i*(leg[5]-leg_old[5])/18);        
       servo6.write(leg_old[6] + i*(leg[6]-leg_old[6])/18);  
       servo7.write(leg_old[7] + i*(leg[7]-leg_old[7])/18);    
       delay(TimeOneStep/4/18);
    }   
    leg_old[0]=leg[0];
    leg_old[1]=leg[1]; 
    leg_old[2]=leg[2];
    leg_old[3]=leg[3];  
    leg_old[4]=leg[4];
    leg_old[5]=leg[5]; 
    leg_old[6]=leg[6];
    leg_old[7]=leg[7];       
}  

void      setServoWalk()
{
};   

void walk()
{
  // Coordinate per eseguire un passo
  leg[0] = leg_ntr[0]+AmpPasso;//inclinazione
  leg[1] = leg_ntr[1]+AmpPasso;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]+AmpPasso;
  leg[4] = leg_ntr[4]+AmpPasso;
  leg[5] = leg_ntr[5]+IncPasso;       
  setServo();  
  if (RobotMode!=MODE_WALK) return;  

  leg[0] = leg_ntr[0]-AmpPasso;//passo SX
  leg[1] = leg_ntr[1]-AmpPasso;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]-AmpPasso;
  leg[4] = leg_ntr[4]-AmpPasso;
  leg[5] = leg_ntr[5]+IncPasso;  
  setServo();
  if (RobotMode!=MODE_WALK) return;

  leg[0] = leg_ntr[0]-AmpPasso;//inclinazione
  leg[1] = leg_ntr[1]-AmpPasso;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]-AmpPasso;
  leg[4] = leg_ntr[4]-AmpPasso;
  leg[5] = leg_ntr[5]-IncPasso*2;  
  setServo();
  if (RobotMode!=MODE_WALK) return;

  leg[0] = leg_ntr[0]+AmpPasso;//passo DX
  leg[1] = leg_ntr[1]+AmpPasso;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]+AmpPasso;
  leg[4] = leg_ntr[4]+AmpPasso;
  leg[5] = leg_ntr[5]-IncPasso*2;      
  setServo();        
}

void inLeft()
{
  // Si posiziona pronto per girare a sinistra   
  leg[0] = leg_ntr[0];//inclinazione SX
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5]-IncPasso*2;    
  setServo();    

  leg[0] = leg_ntr[0];//piede DX avanti
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5]-IncPasso*2;       
  setServo(); 

  leg[0] = leg_ntr[0];//inclinazione DX
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5]+IncPasso;        
  setServo();

  leg[0] = leg_ntr[0]+AmpRuota;//piede SX indietro
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5]+IncPasso;      
  setServo();     

  leg[0] = leg_ntr[0]+AmpRuota;//piedi a terra
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5];      
  setServo();       

  RobotMode = MODE_LEFT;
  Serial.println("Left Mode...");   
}

void leftWalk()
{
      //passo 1      
  leg[0] = leg_ntr[0]-AmpRuota;//sforbiciata
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5];      
  setServo();       
      if (RobotMode!=MODE_LEFT) return;   

      //passo 2      
  leg[0] = leg_ntr[0]-AmpRuota;//inclinazione
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5]-IncPasso*2;      
  setServo();   
      if (RobotMode!=MODE_LEFT) return;

      //passo 3      
  leg[0] = leg_ntr[0]-AmpRuota;//sposta piede DX in avanti
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5]-IncPasso*2;      
  setServo();
      if (RobotMode!=MODE_LEFT) return; 

      //passo 4      
  leg[0] = leg_ntr[0]-AmpRuota;//inclinazione
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5]+IncPasso;      
  setServo();
      if (RobotMode!=MODE_LEFT) return;

      //passo 5      
  leg[0] = leg_ntr[0]+AmpRuota;//sposta SX indietro
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5]+IncPasso;      
  setServo();
      if (RobotMode!=MODE_LEFT) return;

      //passo 6
  leg[0] = leg_ntr[0]+AmpRuota;//piedi a terra
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5];      
  setServo();  
     if (RobotMode!=MODE_LEFT) return;
}

void inRight()
{
  // Si posiziona pronto per girare a sinistra   
  leg[0] = leg_ntr[0];//inclinazione SX
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5]+IncPasso;    
  setServo();    

  leg[0] = leg_ntr[0]-AmpRuota;//piede DX avanti
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5]+IncPasso;       
  setServo(); 

  leg[0] = leg_ntr[0]-AmpRuota;//inclinazione DX
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5]-IncPasso*2;        
  setServo();

  leg[0] = leg_ntr[0]-AmpRuota;//piede SX indietro
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5]-IncPasso*2;      
  setServo();     

  leg[0] = leg_ntr[0]-AmpRuota;//piedi a terra
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5];      
  setServo();       

  RobotMode = MODE_RIGHT;
  Serial.println("Right Mode...");   
}

void rightWalk()
{
      //passo 1      
  leg[0] = leg_ntr[0]+AmpRuota;//sforbiciata
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5];      
  setServo();       
      if (RobotMode!=MODE_RIGHT) return;   

      //passo 2      
  leg[0] = leg_ntr[0]+AmpRuota;//inclinazione
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]+AmpRuota;
  leg[4] = leg_ntr[4]+AmpRuota;
  leg[5] = leg_ntr[5]+IncPasso;      
  setServo();   
      if (RobotMode!=MODE_RIGHT) return;

      //passo 3      
  leg[0] = leg_ntr[0]+AmpRuota;//sposta piede DX in avanti
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2]+IncPasso*2;
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5]+IncPasso;      
  setServo();
      if (RobotMode!=MODE_RIGHT) return; 

      //passo 4      
  leg[0] = leg_ntr[0]+AmpRuota;//inclinazione
  leg[1] = leg_ntr[1]+AmpRuota;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5]-IncPasso*2;      
  setServo();
      if (RobotMode!=MODE_RIGHT) return;

      //passo 5      
  leg[0] = leg_ntr[0]-AmpRuota;//sposta SX indietro
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2]-IncPasso;
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5]-IncPasso*2;      
  setServo();
      if (RobotMode!=MODE_RIGHT) return;

      //passo 6
  leg[0] = leg_ntr[0]-AmpRuota;//piedi a terra
  leg[1] = leg_ntr[1]-AmpRuota;
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3]-AmpRuota;
  leg[4] = leg_ntr[4]-AmpRuota;
  leg[5] = leg_ntr[5];      
  setServo();         
      if (RobotMode!=MODE_RIGHT) return;  
} 

void bow()
{
  //inchino
  leg[0] = leg_ntr[0]-60;
  leg[1] = leg_ntr[1]-10;
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3]+60;
  leg[4] = leg_ntr[4]+10;
  leg[5] = leg_ntr[5];  
  setServo();    
  delay(1000);
  leg[0] = leg_ntr[0];//passo DX da fermo
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5];      
  setServo();    
}  

void kick()
{
   //calcio 
  leg[0] = leg_ntr[0];//inclinazione
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2]-12;//regolare questo valore per bilanciare
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5]-24;  
  setServo();    
  leg[0] = leg_ntr[0];//piede indietro
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2]-12;//regolare questo valore per bilanciare
  leg[3] = leg_ntr[3]-AmpPasso;
  leg[4] = leg_ntr[4]+AmpPasso;
  leg[5] = leg_ntr[5];  
  setServo();       
  //calcia 

       leg_old[3]=leg_ntr[3]+AmpPasso; 
       servo3.write(leg_old[3]);      
       leg_old[4]=leg_ntr[4]-AmpPasso;        
       servo4.write(leg_old[4]);  

  leg[0] = leg_ntr[0];//ritorna in posizione
  leg[1] = leg_ntr[1];
  leg[2] = leg_ntr[2];
  leg[3] = leg_ntr[3];
  leg[4] = leg_ntr[4];
  leg[5] = leg_ntr[5];      
  setServo();  

}  

long readDistance()
{
  // Procedura per leggere la presenza di ostacoli
  // Viene generato un PING di 2usec ed atteso l'ECO di risposta
  long duration, cm;
  pinMode(PING_PIN, OUTPUT);
  digitalWrite(PING_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(PING_PIN, HIGH);
  delayMicroseconds(5);
  digitalWrite(PING_PIN, LOW);

  // Lo stesso pin che genera il trigger è usato per la lettura
  // del segnale di ritorno
  pinMode(PING_PIN, INPUT);
  duration = pulseIn(PING_PIN, HIGH);

  // ritorna distanza ostacolo in cm
  return duration / 29 / 2;
}

 

For this robot is important to the calibration of the neutral of the servos that occurs as previously described.  Servo0 corresponds to the letter ‘a‘ – Servo5 corresponds to the letter ‘f‘. If the command is ok will receive confirmation of Serial Monitor, for example: “set servo: a to 90“.

 

 

 

 

This robot have additional functions such as the bow and football features that are not implemented on Filippo.

 

Code 4

#define PRG1_CODE1 0x801 // Program 1
#define PRG1_CODE2 0x1 // Program 1
#define PRG2_CODE1 0x802 // Program 2
#define PRG2_CODE2 0x2 // Program 2

 

To the button ’1 ‘corresponds to the function of football with which the robot can hit, for example a ball, to the button ’2′ corresponds to the bow that is always of great effect.

The parameters can be set by the program are similar to those of robot Filippo:

 

Code 5

int TimeOneStep = 4000;  
int AmpPasso = 10;         
int AmpRuota = 12;         
int IncPasso = 8;

 

SPIDER ROBOT

With this robot we wanted to replicate the appearance and movements of a spider with all the limitations derived from a simplified mechanics and a limited cost.  The choice has been the use of two servos for paw for a total of four legs, which, however, ensure a final result very attractive. The largest number of servos relative to the robot BIPE should not scare because, at the end, this robot is the most simple to make and having regard to the intrinsic stability, does not present serious problems even in the operation. For this robot we have not even provided the adjustment of the neutral servos because of some inaccuracies should not be to influence the operation.The only care is to fix the battery pack in the center so the robots present the center of gravity exactly in the center. During the movement three legs always remain in contact with the ground while one moves, rising, thereby ensuring a good stability.

The mechanical is made by PCB, the same material used for printed electronic and suggest paint it black to improve the aesthetic appearance. No soldering required, and each piece is simply screwed to the servos that make up the mechanics.

How practical advice suggest to program the Arduino board with this program and then electrically connecting the servos, doing so will all be positioned exactly in the middle.Then you connect the mechanical servos in their proper locations.

// SPIDER ARDUINO
// by Segatello Mirco for ElettronicaIN 
// Compilato con Arduino21

#include <Servo.h> 
#include <IRremote.h> 

#define RECV_PIN 10   // pin per sensore IR
#define PING_PIN 11   // pin per sensore RADAR
#define       P1 12   // pin per pulsante

#define STNB_CODE1 0x81D    // Stop Philips TV remote
#define STNB_CODE2 0x1D     // Codice alternativo
#define WALK_CODE1 0x81C    // Play Philips TV remote
#define WALK_CODE2 0x1C     // Codice alternativo
#define SPEEDUP_CODE1 0x820 // Prg+ Philips TV remote
#define SPEEDUP_CODE2 0x20  // Codice alternativo
#define SPEEDDW_CODE1 0x821 // Prg- Philips TV remote
#define SPEEDDW_CODE2 0x21  // Codice alternativo
#define LEFT_CODE1    0x2C  // Left Philips remote
#define LEFT_CODE2    0x82C  // Codice alternativo
#define RIGHT_CODE1    0x2B  // Left Philips remote
#define RIGHT_CODE2    0x82B  // Codice alternativo

#define MODE_OFF       0    // Servi OFF
#define MODE_STANDBY   1    // Servi armati in posizione di riposo
#define MODE_INWALK    2    // Assume la posizione di partenza
#define MODE_WALK      3    // Cammina in avanti
#define MODE_INSTANDBY 4    // Assume la posizione di standby
#define MODE_LEFT      5    // Si gira verso sinistra
#define MODE_RIGHT     6    // Si gira a destra
#define MODE_REVWALK   7    // Cammina all'indietro

IRrecv irrecv(RECV_PIN);
decode_results results;

int RobotMode = MODE_OFF;   
int TimeOneStep = 6000;     // Tempo in msec per eseguire un passo completo

Servo servo0, servo1, servo2, servo3,
      servo4, servo5, servo6, servo7;  // oggetti servo

int leg_old[8] = {90, 90, 90, 90, 90, 90, 90, 90}; //posizione precedente dei servi
int leg[8];                 //posizione attuale dei servi
int i;

void setup() 
{ 
  Serial.begin(9600);       // Start seriale
  Serial.println("BIPE Aduino V1.0");
  irrecv.enableIRIn();      // Start ricevitore IR  
  irrecv.blink13(true);     // Lampeggio LED in ricezione IR attivo
  pinMode(P1, INPUT);       // Pulsante 
  digitalWrite(P1, HIGH);   // Abilita pull-up
  levelBat();               // Verifica stato batteria  
  Serial.println("Livello batteria OK.");  
  Serial.println("Inizializzo Servi...");  
  initServo();              // Inizializza servi
  Serial.println("Servi inizializzati.");
  inStandby();              // Robot in attesa di comando
} 

void loop() 
{ 
  if (irrecv.decode(&results)) IRcommand();
  if (RobotMode==MODE_WALK)   walk();
  if (RobotMode==MODE_REVWALK) walkReverse();
  if (RobotMode==MODE_LEFT)   leftWalk();  
  if (RobotMode==MODE_RIGHT)   rightWalk();
  levelBat();  
  if (RobotMode==MODE_STANDBY) delay(100); 
  if (digitalRead(P1)==0) P1Press();  

  int obstacle = readDistance();
  Serial.print("Ostacolo: ");
  Serial.println(obstacle, DEC);    
  if (obstacle<20)  inStandby();    

  // Ricezione seriale per setup servi
  if (Serial.available()) SerialSet();  
} 

void SerialSet()
{
   // E' arrivato un comando dalla seriale
  byte c;
  byte srv;

  while(Serial.available())     // finchè ci sono dati 
  {
      c = Serial.read();    // legge i dati e li salva in una variabile
      if ( 97 <= c <= 102)   Serial.print(c);
 }  
}

void IRcommand()
{
    // E' arrivato un comando via IR
    Serial.println(results.value, HEX);  // ECO su serial monitor per sapere il codice arrivato

    if (results.value == WALK_CODE1 || results.value == WALK_CODE2)   inWalk();     
    else if (results.value == LEFT_CODE1 || results.value == LEFT_CODE2)  inLeft();     
    else if (results.value == RIGHT_CODE1 || results.value == RIGHT_CODE2)  inRight();       
    else if (results.value == STNB_CODE1 || results.value == STNB_CODE2)  inStandby();            
    else if (results.value == SPEEDUP_CODE1 || results.value == SPEEDUP_CODE2) {
      if (TimeOneStep > 1000) TimeOneStep -= 500; }
    else if (results.value == SPEEDDW_CODE1 || results.value == SPEEDDW_CODE2) {
      if (TimeOneStep < 6000) TimeOneStep += 500; }
    Serial.print("TimeOneStep= ");      
    Serial.println(TimeOneStep);
    irrecv.resume(); // Resume decoding   
}  

void P1Press()
{
  // E' stato premuto il pulsante   
  while (digitalRead(P1)==0) delay(100);  
  if (RobotMode==MODE_WALK)  inStandby();            
  else if (RobotMode==MODE_STANDBY) inWalk(); 
}  

void levelBat()
{
  // controlla livello batteria  
  int VbatRAW = analogRead(A0);
  float Vbat = float(VbatRAW)/50;
  Serial.print("Vbat= ");
  Serial.println(Vbat, DEC);     
  if (Vbat<6.0)   {
    Serial.println("Livello batteria basso!");    
    inOff();    
  }  
}

void initServo()  
{
  // posizione iniziale dei servi
  servo0.attach(2);  // connette servo 
  delay(300);
  servo1.attach(3);  // connette servo 
  delay(300);  
  servo2.attach(4);  // connette servo 
  delay(300);
  servo3.attach(5);  // connette servo 
  delay(300);  
  servo4.attach(6);  // connette servo 
  delay(300);
  servo5.attach(7);  // connette servo 
  delay(300);  
  servo6.attach(8);  // connette servo 
  delay(300);
  servo7.attach(9);  // connette servo 
  delay(300);     
}

void inOff()
{
  // Spegne tutti i servi
  leg[0] = 90;
  leg[1] = 90;
  leg[2] = 90;
  leg[3] = 90;
  leg[4] = 90;
  leg[5] = 90;
  leg[6] = 90;
  leg[7] = 90;      
  setServo();  
  servo0.detach();  // connette servo 
  servo1.detach();  // connette servo 
  servo2.detach();  // connette servo 
  servo3.detach();  // connette servo 
  servo4.detach();  // connette servo 
  servo5.detach();  // connette servo 
  servo6.detach();  // connette servo 
  servo7.detach();  // connette servo 
  RobotMode = MODE_OFF;     
  // Da questo modalità si deve spegnere il robot e ricaricare le batterie
}  

void inStandby()
{
  // Posiziono tutti i servi al centro
  leg[0] = 90;
  leg[1] = 90;
  leg[2] = 90;
  leg[3] = 90;
  leg[4] = 90;
  leg[5] = 90;
  leg[6] = 90;
  leg[7] = 90;      
  setServo();  
  RobotMode = MODE_STANDBY;  
  Serial.println("Sono in Standby...");  
}  

void inWalk()
{
  // Si alza pronto per partire   
  leg[0] = 99;
  leg[1] = 126;
  leg[2] = 117;
  leg[3] = 54;
  leg[4] = 99;
  leg[5] = 126;
  leg[6] = 117;
  leg[7] = 54;      
  setServo();  
  RobotMode = MODE_WALK;
  Serial.println("Walk Mode...");   
}

void setServo() 
{  
   // Posiziona i servi alle cordinate specificate da leg[]  
   for (i=0; i<18; i++) {
       servo0.write(leg_old[0] + i*(leg[0]-leg_old[0])/18);  
       servo1.write(leg_old[1] + i*(leg[1]-leg_old[1])/18);        
       servo2.write(leg_old[2] + i*(leg[2]-leg_old[2])/18);  
       servo3.write(leg_old[3] + i*(leg[3]-leg_old[3])/18);      
       servo4.write(leg_old[4] + i*(leg[4]-leg_old[4])/18);  
       servo5.write(leg_old[5] + i*(leg[5]-leg_old[5])/18);        
       servo6.write(leg_old[6] + i*(leg[6]-leg_old[6])/18);  
       servo7.write(leg_old[7] + i*(leg[7]-leg_old[7])/18);    
       delay(TimeOneStep/4/18);
    }   
    leg_old[0]=leg[0];
    leg_old[1]=leg[1]; 
    leg_old[2]=leg[2];
    leg_old[3]=leg[3];  
    leg_old[4]=leg[4];
    leg_old[5]=leg[5]; 
    leg_old[6]=leg[6];
    leg_old[7]=leg[7];       
}  

void setServoWalk() 
{     
   // Posiziona i servi durante la camminata 
   for (i=1; i<=18; i++) {
       servo0.write(leg_old[0] + i*(leg[0]-leg_old[0])/18);          
       servo2.write(leg_old[2] + i*(leg[2]-leg_old[2])/18);       
       servo4.write(leg_old[4] + i*(leg[4]-leg_old[4])/18);       
       servo6.write(leg_old[6] + i*(leg[6]-leg_old[6])/18);  

      // servi delle zampe
         if ( i <= 9 ) 
           servo1.write(leg_old[1] + i*(leg[1]-leg_old[1])/9);         
         else  
           servo1.write(leg_old[1] + (18-i)*(leg[1]-leg_old[1])/9);      

         if ( i <= 9 ) 
           servo3.write(leg_old[3] + i*(leg[3]-leg_old[3])/9);                   
         else    
           servo3.write(leg_old[3] + (18-i)*(leg[3]-leg_old[3])/9); 

         if ( i <= 9 ) 
           servo5.write(leg_old[5] + i*(leg[5]-leg_old[5])/9);         
         else  
           servo5.write(leg_old[5] + (18-i)*(leg[5]-leg_old[5])/9);    

         if ( i <= 9 ) 
           servo7.write(leg_old[7] + i*(leg[7]-leg_old[7])/9);         
         else  
           servo7.write(leg_old[7] + (18-i)*(leg[7]-leg_old[7])/9);       

       delay(TimeOneStep/4/18);
    }   
    leg_old[0]=leg[0];
    leg_old[1]=126;//leg[1]; 
    leg_old[2]=leg[2];
    leg_old[3]=54;//leg[3];  
    leg_old[4]=leg[4];
    leg_old[5]=126;//leg[5]; 
    leg_old[6]=leg[6];
    leg_old[7]=54; //leg[7];  
    if (digitalRead(P1)==0) P1Press();  
    if (irrecv.decode(&results)) IRcommand();    
}  

void walk()
{
      // Coordinate per eseguire un passo

      //passo 1      
      leg[0] = 117;
      leg[1] = 126;
      leg[2] = 63;
      leg[3] = 90;   //posizione zampa alzata
      leg[4] = 81;
      leg[5] = 126;
      leg[6] = 99;
      leg[7] = 54;  
      setServoWalk();      
      if (RobotMode!=MODE_WALK) return;

      //passo 2      
      leg[0] = 63;
      leg[1] = 90;   // posizione zampa alzata
      leg[2] = 81;
      leg[3] = 54;
      leg[4] = 63;
      leg[5] = 126;
      leg[6] = 81;
      leg[7] = 54;  
      setServoWalk();
      if (RobotMode!=MODE_WALK) return;

      //passo 3      
      leg[0] = 81;
      leg[1] = 126;
      leg[2] = 99;
      leg[3] = 54;
      leg[4] = 117;
      leg[5] = 90;    // posizione zampa alzata
      leg[6] = 63;
      leg[7] = 54;  
      setServoWalk();
      if (RobotMode!=MODE_WALK) return; 

      //passo 4      
      leg[0] = 99;
      leg[1] = 126;
      leg[2] = 117;
      leg[3] = 54;
      leg[4] = 99;
      leg[5] = 126;
      leg[6] = 117;
      leg[7] = 90;    // posizione zampa alzata
      setServoWalk();       
}

void walkReverse()
{
      //passo 1      
      leg[0] = 63;
      leg[1] = 126;
      leg[2] = 117;
      leg[3] = 90;  // si alza
      leg[4] = 99;
      leg[5] = 126;
      leg[6] = 81;
      leg[7] = 54;  
      setServoWalk();      
      if (RobotMode!=MODE_WALK) return;   

      //passo 2      
      leg[0] = 117;
      leg[1] = 126;
      leg[2] = 99;
      leg[3] = 54;
      leg[4] = 117;
      leg[5] = 90;  // si alza
      leg[6] = 99;
      leg[7] = 54;  
      setServoWalk();
      if (RobotMode!=MODE_WALK) return;

      //passo 3      
      leg[0] = 99;
      leg[1] = 126;
      leg[2] = 81;
      leg[3] = 54;
      leg[4] = 63;
      leg[5] = 126;
      leg[6] = 117;
      leg[7] = 90;  // si alza  
      setServoWalk();
      if (RobotMode!=MODE_WALK) return; 

      //passo 4      
      leg[0] = 81;
      leg[1] = 90; // si alza
      leg[2] = 63;
      leg[3] = 54;
      leg[4] = 81;
      leg[5] = 126;
      leg[6] = 63;
      leg[7] = 54;  
      setServoWalk();       
}

void inLeft()
{
  // Si alza pronto per girare a sinistra   
  leg[0] = 63;
  leg[1] = 126;
  leg[2] = 81;
  leg[3] = 54;
  leg[4] = 99;
  leg[5] = 126;
  leg[6] = 117;
  leg[7] = 54;      
  setServo();  
  RobotMode = MODE_LEFT;
  Serial.println("Left Mode...");   
}

void leftWalk()
{
      //passo 1      
      leg[0] = 81;
      leg[1] = 126;
      leg[2] = 99;
      leg[3] = 54;  
      leg[4] = 117;
      leg[5] = 126;
      leg[6] = 63;
      leg[7] = 90;//*  
      setServoWalk();      
      if (RobotMode!=MODE_LEFT) return;   

      //passo 2      
      leg[0] = 99;
      leg[1] = 126;
      leg[2] = 117;
      leg[3] = 54;
      leg[4] = 63;
      leg[5] = 90;//*
      leg[6] = 99;
      leg[7] = 54;  
      setServoWalk();
      if (RobotMode!=MODE_LEFT) return;

      //passo 3      
      leg[0] = 117;
      leg[1] = 126;
      leg[2] = 63;
      leg[3] = 90;//*
      leg[4] = 81;
      leg[5] = 126;
      leg[6] = 99;
      leg[7] = 54;   
      setServoWalk();
      if (RobotMode!=MODE_LEFT) return; 

      //passo 4      
      leg[0] = 63;
      leg[1] = 90;//*
      leg[2] = 81;
      leg[3] = 54;
      leg[4] = 99;
      leg[5] = 126;
      leg[6] = 117;
      leg[7] = 54;  
      setServoWalk();         
}

void inRight()
{
  // Si alza pronto per girare a destra   
  leg[0] = 99;
  leg[1] = 126;
  leg[2] = 117;
  leg[3] = 54;
  leg[4] = 63;
  leg[5] = 126;
  leg[6] = 81;
  leg[7] = 54;      
  setServo();  
  RobotMode = MODE_RIGHT;
  Serial.println("Right Mode...");   
}

void rightWalk()
{
      //passo 1      
      leg[0] = 81;
      leg[1] = 126;
      leg[2] = 99;
      leg[3] = 54;  
      leg[4] = 117;
      leg[5] = 90;//*
      leg[6] = 63;
      leg[7] = 54;  
      setServoWalk();      
      if (RobotMode!=MODE_RIGHT) return;   

      //passo 2      
      leg[0] = 63;
      leg[1] = 126;
      leg[2] = 81;
      leg[3] = 54;
      leg[4] = 99;
      leg[5] = 126;
      leg[6] = 117;
      leg[7] = 90;//*  
      setServoWalk();
      if (RobotMode!=MODE_RIGHT) return;

      //passo 3      
      leg[0] = 117;
      leg[1] = 90;//*
      leg[2] = 63;
      leg[3] = 54;
      leg[4] = 81;
      leg[5] = 126;
      leg[6] = 99;
      leg[7] = 54;   
      setServoWalk();
      if (RobotMode!=MODE_RIGHT) return; 

      //passo 4      
      leg[0] = 99;
      leg[1] = 126;
      leg[2] = 117;
      leg[3] = 90;//*
      leg[4] = 63;
      leg[5] = 126;
      leg[6] = 81;
      leg[7] = 54;  
      setServoWalk();           
} 

long readDistance()
{
  // Procedura per leggere la presenza di ostacoli
  // Viene generato un PING di 2usec ed atteso l'ECO di risposta
  long duration, cm;
  pinMode(PING_PIN, OUTPUT);
  digitalWrite(PING_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(PING_PIN, HIGH);
  delayMicroseconds(5);
  digitalWrite(PING_PIN, LOW);

  // Lo stesso pin che genera il trigger è usato per la lettura
  // del segnale di ritorno
  pinMode(PING_PIN, INPUT);
  duration = pulseIn(PING_PIN, HIGH);

  // ritorna distanza ostacolo in cm
  return duration / 29 / 2;
}

Make sure that the servos are aligned and that the legs are neither too open nor too closed, taking as reference the pictures posted here .

 

 

Connect the servos to the robot Spider

Servo Arduino Pin Connector shield Function
Servo 0 2 S1 Angle right foreleg
Servo 1 3 S2 Elevation of right foreleg
Servo 2 4 S3 Angle of the right hind leg
Servo 3 5 S4 Elevation of the right hind leg
Servo 4 6 S5 Angle left hind leg
Servo 5 7 S6 Elevation of the left hind paw
Servo 6 8 S7 Angle left foreleg
Servo 7 9 S8 Elevation of left foreleg

 

Turning on after 1 second (after the warm-up switching power supply) all the servos will be placed in the neutral point. It may happen that some servos vibrate slightly, this is due to the internal mechanism that has yet to find the center point, sometimes just a small blow to the servant to fix things.

For this robot we never anticipated that you can edit parameters, movements are many and complex and there are too many variables to set, we preferred to find a setup that could offer the best performance in every situation. For our prototype LiPo battery that powers it has been established under the structure, right through to the servos, ensuring, in addition to the centering of weight, a low center of gravity.

Let us see now the analysis of the firmware describing those functions that are common to all the robots such as the procedure that reads the distance from obstacles by means of the sensor SRF05:

 

Code 6

long readDistance()
{
  long duration, cm;
  pinMode(PING_PIN, OUTPUT);
  digitalWrite(PING_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(PING_PIN, HIGH);
  delayMicroseconds(5);
  digitalWrite(PING_PIN, LOW);
  pinMode(PING_PIN, INPUT);
  duration = pulseIn(PING_PIN, HIGH);
  // ritorna distanza ostacolo in cm
  return duration / 29 / 2;
}

The procedure foresees to send a pulse duration of 2usec to the sensor, which, proceeds generating a series of ultrasound to the outside. The same pin is subsequently used as input for reading, via the function PulseIn, the time taken by the sound to reach the obstacle, bounce and return to the sensor, the period during which the sensor maintains a high level of the line. The time taken by the ultrasound to go and return to the sensor is proportional to the distance of the object.

 

Here also the procedure for reading the voltage on the battery:

 

Code 7

void levelBat()
{
  int VbatRAW = analogRead(A0);
  float Vbat = float(VbatRAW)/50;
  Serial.print("Vbat= ");
  Serial.println(Vbat, DEC);    
  if (Vbat<6.0)   {
    Serial.println("Livello batteria basso!");   
    inOff();   
  } 
}

 

The procedure is simple, plan to read the analog channel A0 of Arduino and save the result into a variable VbatRAW. As explained above, by dividing this value by 50, is obtained by the voltage in volts of the battery. Since excessively discharge the battery can damage it, we expected an alarm to the level below which the robot is immediately stopped and all the servos are disabled.  The threshold value is defined in 6.0 V ideal for use with a battery pack consisting of two cell LiPo or six if you use NiMh or NiCd cells, eight cells used instead if you can increase this value up to 8.0 volts or, one volt per used cell.

 

Another common procedure is called to all the robots initServo () to initialize the servos:

 

Code 8

void initServo() 
{
  // posizione iniziale dei servi
  servo0.attach(2);  // connette servo
  delay(300);
........
  servo7.attach(9);  // connette servo
  delay(300);    
}

 

The function Servo.attach() associates each object provides the respective servo output, from this moment the servant reaches the PWM signal.

 

The procedure inOff () performs the opposite function by removing the pin from their association with the servos and leaving them with no control.

 

Code 9

void inOff()
{
  leg[0] = 90;
.....
  leg[7] = 90;     
  setServo(); 
  servo0.detach();  // connette servo
....
  servo7.detach();  // connette servo
  RobotMode = MODE_OFF;    
}

 

The function to put in sleep mode the robot is called Standby() and simply place all the servos in the central position. In the case of the robot Filippo and BIPE the servos are positioned in their respective neutral points whose values are contained in the vector named leg_ntr [].

 

Code 10

void inStandby()
{
  leg[0] = 90;
....
  leg[7] = 90;     
  setServo(); 
  RobotMode = MODE_STANDBY; 
  Serial.println("Sono in Standby..."); 
}

 

A very important procedure is to ensure that the servos have to place to desired coordinates:

 

Code 11

void setServo()
{ 
   for (i=0; i<18; i++) {
       servo0.write(leg_old[0] + i*(leg[0]-leg_old[0])/18); 
       servo1.write(leg_old[1] + i*(leg[1]-leg_old[1])/18);       
       servo2.write(leg_old[2] + i*(leg[2]-leg_old[2])/18); 
       servo3.write(leg_old[3] + i*(leg[3]-leg_old[3])/18);     
       servo4.write(leg_old[4] + i*(leg[4]-leg_old[4])/18); 
       servo5.write(leg_old[5] + i*(leg[5]-leg_old[5])/18);       
       servo6.write(leg_old[6] + i*(leg[6]-leg_old[6])/18); 
       servo7.write(leg_old[7] + i*(leg[7]-leg_old[7])/18);   
       delay(TimeOneStep/4/18);
    }  
    leg_old[0]=leg[0];
    leg_old[1]=leg[1];
    leg_old[2]=leg[2];
    leg_old[3]=leg[3]; 
    leg_old[4]=leg[4];
    leg_old[5]=leg[5];
    leg_old[6]=leg[6];
    leg_old[7]=leg[7];      
}

 

If we set directly the servo, it was a sudden movement and the robot would move in spurts. He prefers, instead, gradually controlling the servo to bring it to the desired position in a defined time. To do this you must define a vector leg[] that contains the coordinates to be achieved by each servo and a vector leg_old[] that contains the actual coordinates. The procedure controls the servos by sending them all coordinated by the intermediate value at the target value in a time defined by the variable TimeOneStep. This system allows us to obtain fluid movements.

Only the robot spider there is a procedure called setServoWalk() because it is necessary that some servos are moving at different speeds than the other. During the walk the three legs in contact with the floor moving slowly, the fourth foot must lift and move fast in the opposite direction to progress.

 

 

Download

 Gerber for Shield
   Gerber for Filippo
   Gerber for Bipe
   Gerber for Spider


 

-->-->-->-->-->-->
-->-->

How to make an Arduino shield with Eagle CAD – Tutorial

-->-->-->-->

There are many CAD developed to assist the electronic designers during drawing of PCBs and schematics; often they are integrated in complete suite to project, simulate and realize a whole electronic system. Besides the many commercial versions, there are also free CADs available. Today we’d like to analyze one of the most diffused and known software: Eaglecad (eagle does not mean the powerful bird but it is the acronym of Easily Applicable Graphical Layout Editor) made by Cadsoft, actually at version 6.2.0. We have chosen this one because, as you know as an Arduino’s fan, the official pcbs and schematic files of the boards are developed and available free of charge to everybody in Eaglecad format; you can find also a lot of libraries and circuits made by famous DIY website (Sparkfun for first) available for free. Eaglecad is a professional software that have gained a lot of popularity due to the Arduino’s success. One of the most important difference between Eaglecad and its competitors is the availability of a version for every of the most common desktop OS: Windows, Linux, Mac. We have to specify that Eaglecad is not Free software but is a commercial one, which can be used in the free version (eaglecad light) only for evaluation purposes and by student but you can’t use the light version in any case when you earn or save money by using it. For further details about licenses and distributors have a look to the official Eaglecad website where you can find all the information you need. Remember that the light version has some limitations; anyway you can design circuit with a discrete complexity, as the one you can see at http://elmicro.com/en/kit12.html. The limitations are:

 - pcb dimensions not bigger than 100×80 mm;

 - no more than 2 layers;

 - only 1 sheet for schematic.

Now let’s have a look at the software itself starting from the GUI, which is made by three main units:

Control Panel

Schematic (you can see an Arduino’s UNO R3 board schematic screenshot)

Board (the pcb editor) which can be seen “in action” which shows the pcb of the Arduino’s R3 board

 

For people used to the other similar cads, the interface is very closed to them and you’ll learn to use it easily; anyway to use the most powerful functions you need some practice.

The first thing you see at the CAD start up is the Control Panel, from which you can easily get access (for example) to the libraries, projects and examples; this is the software section where you can configure the main options like user’s folders, delay for the autosave option and the most important graphical parameters, all by getting access to the “OPTIONS” menu. The available documentation is pretty complete: you can access to the help function from the “help” menu available in both “Schematic” and “Pcb”. If you need further details you have to read the complete manual and the tutorial which are both available getting access to “Start” (on Windows), Programs-> Eagle Layout Editor 6.2.0.

Let’s try to have practice with an example: we want to draw an Arduino’s shield made by 4 leds e da 4 switches, connected to 8 digital pins; it’s obvious due to the kind of circuit we are approaching to make, that this shield is only for training purposes. This pcb can be used to show the digital logic level of one or some pins, levels that could be changed by the four switches or to have a led alarm in case of an analog becomes higher or lower than some level.

For first we have to draw the schematic so we select “FILE”, “NEW”, “SCHEMATIC” in this order: the Schematic window will open up. It is mainly made by two groups of icons: one on the top with the main commands like file management and zoom and another one on the left with the “drawing” icons.

 

We can add the components by selecting the “AND” gate icon on the left hand side of the screen; when the cursor will be on it the word “Add” will pop up. Once selected, a list of libraries will be shown.

We can add other libraries like the Sparkfun one for example or we can also modify the ones which are provided by Eaglecad. Now select “Resistor”, “R-EU”: on the screen will appear a sub library where we can choose the kind of resistor we need (SMD,trough-hole) and its package.

For our example we’d like to use trough hole components so we’ll choose “R-EU_02_07/10″ which is a 1/4W resistor horizontally mounted. Once a component has been chosen, on the right hand side of the window, Eaglecad shows the component symbol used in the schematic and beside the pcb pads of such component and the space required on the PCB. There is another window under the two we have seen before where there are details and notes that have been inserted during creation of the selected component.

We need 4 of such components so we click on “OK”, move on the schematic drawing area and put the element where we want by clicking again. Eaglecad automatically names resistors in a progressive way.

When we have finished with these components, we have to select “ESC” on the keyboard: again the “ADD” window will open itself; now we select “LED5MM” in the “LED” sub-library which is contained into the “Led” library and we’ll draw four leds as done before.

In the same way we can select the 4 switches “10-xx” available in the library “switch-omron”; these actions lead us to the situation shown here:

For the moment we can mainly focus our attention about the correct type of the connectors so we add, as explained before, two made by 6 contacts for the power supply section and the analog connections and other two made by 8 pins for digitals; the chosen connectors are the ones in the “con-molex” library, identified by “22-23-2061″ e “22-23-2081″. Push two times ESC to exit and so far we are in the conditions show:

Now select the 4 resistors one at time, right-click and select “Value” in order to assign the desired value to each of them. Do the same with the 4 connectors, in order to change their value e.g. into A1, A2, D1, D2. A warning window with two choices will pop up: we’ll chose “Yes” and in the next window we’ll insert the required value. We’ll do the same for the next three strips.

Now below every resistors there is the resistance value and also the four connectors have been renamed as required. It is also possible to rename every singol contact of every connector. Let’s do that, in order to avoid mistakes: select “name” in the left hand column and then put the mouse cursor on every contact to replace their name, e.g. “D1″, “D2″, “A1″, “A2″.

In this way it is easy to understand for every contact which is the related connector strip. Now insert the ground symbol and connect the LED cathodes to them (Eaglecad have available many kind of ground symbols: they are in the libraries “supply1″ and “supply2″). We’ll choose “GND” available in the “supply1″ library. Looking at the digital strips we can notice that they are in the “wrong” side of the schematic. To have a more easily access to the contact connections and to have a clear and readable schematic, we can use the”mirror” command to mirror the selected parts. Before apply this command, select the symbols of both connectors with the command “group” in order to reduce the number of required actions.

Select “Mirror” and then put the mouse pointer on the working area and select by left clicking first and then by right clicking “Mirror: Group”. Now it’ s time to draw connections. We can proceed in two ways: by selecting the commands “Draw” and “Wire” in sequence or by clicking with the left mouse switch on the related icon. To connect components put the cursor on the end of the symbol you want to connect, click with the left mouse switch and move the pointer on the terminal of the other components you have to connect to and click again.

To go to the next connection push ESC on the keyboard, put the mouse pointer where you want to draw the next wire and then left click again.

So far so good. We have focused our attention on LEDs, forgetting the switches. Never mind, we can insert, modify, delete, change the inserted parts in the schematic every time we need it; now we insert the missing components adding the required connections.

As you can see it’s easy to rotate and to move any part by using the related function in the “edit” menu or by selecting the desired icon in the left hand side column.

Once all the connections are done, select “Tool”, “Erc” to solve errors, if any, which will be shown in the “Erc errors” window where Eaglecad lists some issues: leds and switches have no value and the pins of the strips are not connected.

We don’t care about the missing values because they are not important in our schematic and we know that the unconnected pins are not used in our circuit. To confirm that, select “Approve” for all the requests and then with “Tools” and “”Errors” command we make sure that there are no further issues. Finally it’s time to draw the printed circuit board: left click on the “Board” icon which is the fifth starting from the left on the tool bar which is on the top of the working window.

The system will ask us if we want to create the related file so we confirm “Yes” and then we’ll have on the screen the same picture as the one shown in figure:

Using the command “Move” which can be selected by the icon with the four arrows in the left hand column, move the components where required. It’s better to start with the connectors due to they give the dimensions to the shield. Remember that the eight and the 6 pins connectors don’t have the same “step” on the board; in case of doubt check another shield, or you can refer to the pcb of the Uno which can be easily found on the Arduino’s website. The ones who have the R3 know that the strips have been redrawn to follow the increased needs of such system so the old connectors 8+8 and 6+6 have been replaced with 10+8 for digital pins and 8+6 for analog. In our example we have chosen to use the old connectors because they are compatible with all the Arduino version between 2009 and Uno and then because our shield was born for teaching reasons so it’s better to have it compatible also with the old pcb versions which are still used by many people. To insert the four connectors we can use the grid which help us; to change its resolution get access to “View”, “Grid” or “Properties” which is available by the “i” icon; in the last case we have also information about the absolute position in the working space.

Since the versions 6 of Eagleacad it is available another function which support us during drawing: “dimension” available through “Draw->Dimension”.

Wiring routing can be done automatically (autorouting function) or manually. In this short introduction we’ll use the hand routing in order to practice with Eaglecad. By selecting the “Route” icon it is possible to draw connections; the dimension, shape and width are visible on the top icon bar where is also possible to select the pcb side. The freeware version make possible to draw pcbs with only two sides, so we’ll find only “Top” and “Bottom”. In the same way you move components it is possible to define the printed circuit board dimensions; the white lines are the cutting boarder where the CNC will cut the pcb. Finally here a possible two sides pcb of our Arduino’s shield.

Special thanks to author Vincenzo Mendola.

-->-->-->-->-->-->
-->-->

Low cost Ethernet shield with ENC28J60

Economical alternative to original Arduino ethernet shields, allows data rates up to 10 Mbps and is achieved with a traditional assembly components.

One of the most interesting shield that you can mount on the Arduino platform is certainly the ethernet shield, because enable numerous networking applications such as remote control of systems and users, web access and publication of data, and more yet, the simplicity of finding and integrating open-source libraries on Arduino IDE does the rest. The usefulness of LAN connectivity has meant that the market would respond by offering different ethernet shield, first of all the original Arduino Ethernet Shield, which was accompanied by the good shield by Seeed Studio, both of these circuits are based on the chipset WIZnet W5100, allow multiple socket connections and can work at 100 Mbps

This ethernet shield is low-cost thanks to components used: all traditional mounting (THT). This feature makes the circuit accessible to those who haven’t the equipment to assemble SMD components. The data-rate is limited to 10 Mbps.

 

Wiring diagram

The shield is based on a Microchip ENC28J60 chip that interfaces with Arduino and data conversion according to the ethernet protocol. It integrates the MAC controller, an 8 KB Transmit / Receive Packet Dual Port Buffer and a circular FIFO managed at the hardware level, allows the programming of data retransmission in case of collision.
The MAC controller supports both Unicast, Multicast and Broadcast packets, has a programmable 64-byte pattern within a margin allowed to the user and programmable wake-up on multiple packet formats (Magic Packet, Unicast, Multicast, Broadcast, specific packet match or any packet).

 

In the circuit we see that over all’ENC28J60 there are a standard RJ45 jack with integrated LEDs, filters and line transformers, and a voltage level shifter for the SPI interface to communicate with the Arduino.

MISO is the output data of the slave device and the input of Arduino, while MOSI is the opposite; SCK is the clock that marks the two-way communication on the SPI bus and RESET the reset line, which is also connected to a button that allows you to reset the Ethernet interface, if necessary, manually. The digital D10 and D2 lines of Arduino are used, respectively, for the control of CS (Chip Select, active logic zero) and the reading of INT. U3B is used to adapt the logic levels 0/3, 3 V to those of Arduino 0/5 V.

The ENC28J60 operates with a clock of 25 MHz, defined by the quartz Q1 connected between the pins 23 and 24; the capacitor connected to pin VCAP filters the output voltage (2.5 V) of the internal controller and should preferably be of the type low ESR (low series resistance parasite). The resistor connected to RBIAS is used to bias the LAN transceiver that is part of the pin TPIN + / – and TPOUT + / -.

We conclude the analysis of the circuit diagram of the shield with the power that is drawn by Arduino 5V and Vin through the strip: the first provides the 5 volts continuous stabilized points of the circuit that require them (basically the 74HC125 and the resistance of pull Line-up reset and Chip Select) and the second give power to the integrated regulator U2, which creates the 3.3 volts needed to power the microcontroller and circuits contained in the RJ45 jack.


The library for ENC28J60

 

The original library from which we derived can be downloaded from the site https://github.com/jcw/ethercard ; from our site you can download the library itself but with a higher number of application examples.

Here you will find a sketch example to build a Web Server, in particular, in the current web page you will see the hours: minutes: seconds elapsed from the ignition of Arduino.

 


// This is a demo of the RBBB running as webserver 
// with the Ether Card
// 2010-05-28 
// http://opensource.org/licenses/mit-license.php

#include

// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// ethernet interface ip address
static byte myip[] = { 192,168,0,188 };
// gateway ip address
static byte gwip[] = { 192,168,0,1 };

byte Ethernet::buffer[500];
BufferFiller bfill;

void setup () {
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
    Serial.println( "Failed to access Ethernet controller");
  ether.staticSetup(myip);
}

static word homePage() {
  long t = millis() / 1000;
  word h = t / 3600;
  byte m = (t / 60) % 60;
  byte s = t % 60;
  bfill = ether.tcpOffset();
  bfill.emit_p(PSTR(
    "HTTP/1.0 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Pragma: no-cache\r\n"
    "\r\n"
    "<meta http-equiv='refresh' content='1'/>"
    "<title>RBBB server</title>" 
    "<h1>$D$D:$D$D:$D$D</h1>"),
      h/10, h%10, m/10, m%10, s/10, s%10);
  return bfill.position();
}

void loop () {
  word len = ether.packetReceive();
  word pos = ether.packetLoop(len);

  if (pos)  // check if valid tcp data is received
    ether.httpServerReply(homePage()); // send web page data
}

 


Library Ethernet shild with ENC28J60 

Store

Arduino Full Memory: upgrade to the last ATMEL Toolchain version

This short report is aimed to the most “advanced” users of Arduino boards, especially to the users of the “Mega” flavors of the family, but also users of standard versions of the board, like Arduino UNO and Arduino Duemilanove, can take advantage of the following notes.

The story starts with the TiDiGino, one of the recent projects based on the ATmega2560, a very well performing mcu with 256kByte of flash memory on board, that is also the core of of the Arduino Mega 2560 board.

The TiDiGino project software has been developed under a contest.

Some out of the participants have been developed high level solutions that took advantage of almost all of the many hardware features of the TiDiGino board.

During development tests they had to notice crashes and malfunctioning that appeared mysterious and very tricky to debug and fix.

After a series of further deep tests and investigation on the support site of ATMEL we have discovered that the main source of our problems was the compiler included in the versions 0022/0023 of the IDE as like as in the current version 1.0.

The compiler program, named “avr-gcc-4.3.2.exe” is not able to compile correctly sketches that require data areas larger than 64kWord, i.e. 128kByte of flash memory.

In simple words the reason is related in the wrong translation of jump instructions beyond 64k.

The compiler we are talking on is the one (version 4.3.2) included in WinAVR package dated from 2008, when the ATMEL microcontroller had on board less than 64kB of memory.

The WinAVR project has been updated on January 2010 with the version “WinAVR-20100110” containing a new version of the compiler, named “avr-gcc-4.3.3.exe”; we tried out this new version too, without success.

The major negative outcome of this issue is that it affects also the Arduino Mega boards both 1280 and 2560 versions, with the effect of limiting the use of data areas larger than 64kWord in sketches. In order to get access to data beyond that limit it is necessary to use the functions of the PROGMEM library, that allow the use of 24bit pointers.

The issue affects only the dimension of data areas, one program that occupies 60kB of data end 60kB of program would run without problem also in the current situation.

After many investigations and tries we find out the solution to this issue, that is to integrate the last version of the ATMEL Toolchain into the Arduino IDE package.

The ATMEL Toolchain is a set of software programs and libraries (tools) that transforms a source code into an executable by a sort of “virtual assembly line”; the output processed by one tool is the input for the following tool in the chain, an so on.

Of course the most important tool in the Toolchain is the compiler, whose last version is currently the “avr-gcc-4.5.1.exe”.

 

This version is an important enhancement in respect of the one included in the Arduino IDE and offers many advantages:

  1. - supports all the 8bit ATMEL microcontrollers families;
  2. - overcame the 128kB limit and compiles correctly sketches up to 256kB;
  3. - includes best and newest libraries;
  4. - outputs a most compact and efficient compiled object code.


As a completion of this preliminary notes we would focus on the avrdude.exe and avrdude.conf files.

Avrdude.exe is a service program included in the IDE and it is located in the “MyPath\arduino-0022\hardware\tools\avr\bin” folder. The Avrdude.exe version in the Arduino IDE has been modified, respect the AVR original version, in order to support the Arduino bootloaders.

Avrdude.conf is the configuration file that contains the configuration data and settings for each ATMEL microcontroller managed by the IDE, the most advanced users could have been modified this file with the additions of new models of microcontrollers.

Avrdude.conf is located in the “MyPath\arduino-0022\hardware\tools\avr\etc”.

The reason we have mentioned these two files is that they are not involved in the operation of upgrading the Arduino IDE with the compiler in the Toolchain, and have to be carefully saved in a safe place before beginning the upgrading, especially in the step where we will proceed to delete all the contents in the “MyPath\arduino-0022\hardware\tools\avr” folder.

At this point it is possible to describe all the actions needed to execute the upgrading of the IDE.

Our suggestion is to follow the instructions described below, step by step in the provided order and without modification.

The process has been tested many times in order to guarantee the achievement of the result.

Upgrading Arduino IDE process

The process described below is applicable to the Arduino IDE versions 0022, 0023, 1.0, 1.0.1-rc1; the last one listed is the candidate release of IDE 1.0, that is a sort of beta release, still under test; we have processed it too with good results.

Below are the steps to follow:

  1. Copy the whole original IDE folder in a new folder as a backup, in order to maintain the original installation and save the possibility to downgrade the process in case of problem.

  2. Rename the new folder  i.e. arduino-0022-tcnew:


The original folder of the IDE and its copy


  1. In the new folder delete the sub-directory “avr” in “MyPath\arduino-0022-tcnew\hardware\tools”:

The “avr” directory that has to be deleted

  1. Download the last version of the ATMEL Toolchain for Windows, from the link http://www.atmel.com/tools/ATMELAVRTOOLCHAIN3_2_3FORWINDOWS.aspx; to get access to the download section you must fill an on-line registration form; you will receive an e-mail containing the link to the actual download address:

Download section inside the ATMEL site

  1. Install on your PC in the usual way the downloaded file “avr-toolchain-installer-3.2.3.579-win32.win32.x86.exe”. Take a note of the installation path, in order to easily retrieve the folder in a subsequent moment. If you have a copy of the AVR Studio already installed on your PC, the installation wizard will prompt you with the existing path, in order to get your application upgraded;
  2. Copy from the new installation the directory “AVR Toolchain” and paste it into the folder “MyPath\arduino-0022-tcnew\hardware\tools”; at the end rename the “AVR Toolchain” directory as “avr”. In this way you will get again the original path: “MyPath\arduino-0022-tcnew\hardware\tools\avr”;
  3. Enter the new folder “avr” and delete the sub-directory “avr32”:

The sub-directory “avr32” to be deleted

  1. Copy the file avrdude.exe from the original directory “MyPath\arduino-0022\hardware\tools\avr\bin” and paste it into the folder “MyPath\arduino-0022-tcnew\hardware\tools\avr\bin”. Say “YES” at the warning prompt to overwrite the file;
  2. Copy the whole original directory tree “MyPath\arduino-0022\hardware\tools\avr\etc” and paste it in the folder “MyPath\arduino-0022-tcnew\hardware\tools\avr\;
  3. Delete the sub-directory “include” in ” MyPath\arduino-0022-tcnew\hardware\tools\avr\avr“. Pay attention at the double “avr” directory; there is actually an “avr” subdirectory inside an other “avr” sub-directory as shown in this figure. In place of the deleted sub-directory paste the directory that you can download from our site.

The “include” sub-directory that has to be deleted and substituted with the one downloaded from our site

  1. Now enter the directory “MyPath\arduino-0022-tcnew\examples\”, delete the sub-directory ArduinoISP and the sketch contained in it and add the folder “ArduinoISP101”, that is the new version of that sketch, included in the IDE 1.0.1-rc1. You can download this folder too from here. At the beginning of the process we suggested to you to make a copy of the whole folder of the Arduino IDE; subsequently we drove you in the process of upgrading the copy of the IDE itself. That in order to hold one original version of the IDE that is anyhow useful in case you would get in trouble with the new version. Anyway the original version will always be good to compile applications having a data area smaller than 64kB. Please note that the sketch “ArduinoISP101” has the extension .pde that is correct for the IDE versions 0022 e 0023; in case you are using the version 1.0 you must rename the sketch extension in “.ino” (the new standard adopted by IDE 1.0);

One more warning about the last step: the sketch, that is of interest for all the users running Arduino as an ISP Programmer, works correctly at a BAUD rate of 19200 with the IDE version 0022, 0023; at 9600 BAUD with the version 1.0.1-rc1, and doesn’t work at all with the version 1.0.

According to IDE version that you are using could be needed to change the line Serial.begin(19200);” in “Serial.begin(9600);”.

For the users of version 1.0 of the IDE we have posted in the download section a further version of ArduinoISP, named “ArduinoISP101LM” that is a version of the 1.0.1 patched by two experienced programmers whose names are in the credits list of the sketch.

Be aware that this last version is not an official version and will work with the IDE 1.0 too, at a BAUDRATE of 19200.

In IDE 1.0.1-rc1 environment won’t be mandatory to set the BAUDRATE at 9600 BAUD because the sketch automatically detects the IDE version and sets the port speed accordingly.

As previously described the sketch folder should be placed in the “MyPath\arduino-0022-tcnew\examples\” folder.

Although the sketch is not an official release we can assure that it works quite better than the 101 original, especially in the case you should program MCUs with large memories.

For a better explanation give a glance at the contents of the Table:

Comparison table of the two version of ArduinoISP

As a final note we would warn all the users of the ATtiny family of microcontrollers with the IDE versions 1.0 or 1.0.1 that in same conditions our upgrade could fault the compiling task.

The solution, quite simple, is to add the line “#include <math.h>” as the first instruction in the wiring.h file of the tiny “core”

This solve the problem of the correct priority in the loading of the library chain because math.h has to be loaded as the first library of the chain and not as a dependence of other libraries.

It is time to test this upgrade; if you don’t have at hand one sketch bigger enough to overcame the memory limits described in this article, ever in the download section of our site you could download the sketch “test_80k” that will provide to you the opportunity to proof that the Arduino Mega is now able to run correctly sketches with data areas bigger than 64kB.

The story ends with the test of the software on our TiDiGino project than now run happily.

We will keep you up to date with further news about our tests and investigations on the topic.

Download

Include folder

ArduinoISP101

ArduinoISP101LM

Test 80K

[Thanks to Prof. Michele Menniti & Ing. Marco d’Ambrosio]

Arduino ISP (In System Programming) and stand-alone circuits

We use an Arduino to program other ATmega without bootloader . This technique allows you to use all flash memory for code and make boards using new ATmega, cheaper than those with bootloader.

The qualities that have made the success of Arduino are undoubtedly the open-source software, many libraries, a good hardware and a virtually infinite Reference that explains each possible use of the platform.

But if we use Arduino for a specific use, we can integrate it into a specific circuit and program the micro in a way that performs a single firmware. We may so remove the bootloader and leave to the firmware the entire program memory.

The ATmega328 has 32 Kbytes of flash, that when the chip is mounted on Arduino are not all available, as a portion is reserved to the bootloader, the purpose of which is to communicate with the IDE Arduino to load programs (sketch) to be performed. The same bootloader, on each power on or reset of Arduino, verifies the presence of a sketch in flash memory and executes it. The bootloader occupies a space of 512 bytes, in the case of Arduino UNO.

Well, in a stand-alone application the bootloader no longer needed.

The configuration of the micro ATmega328P needs, in addition to the power (+5 VDC to pins 7 and 20, GND to pins 8 and 22), a 16-MHz crystal between pins 9 and 10, two 22 pF ceramic capacitors from between these pins and GND, a 10 k Ω resistor between pin 1 and +5 VDC for pull-up the reset line.

 

Programming ATMEGA in stand-alone

Anyone knows that it is necessary program Arduino uploading a sketch via USB, using the software called IDE and the operation is quite simple.

We can see a screenshot of the IDE with an Arduino sketch loaded and UNO during the receipt of the sketch (notice the yellow LED on).

The technique will test allows the use of a board Arduino as ISP Programmer.

We start with the list of required materials:

•               Arduino UNO / Duemilanove (will be used as a programmer);

•               ATmega328P chip (chip to be programmed);

•               Breadboard and jumper;

•               a crystal of 16 MHz, two ceramic capacitors from 22 pF, a resistance of 10 K Ω 1/4 W, a resistance of 560 Ω 1/4 W LED 3 or 5 mm;

•               seven male-male jumper wires.

A resistance of 120 Ω 1/4 of watts, and an electrolytic capacitor or tantalum from 10 uF 10 ÷ 16 volts.


Now we prepare our target circuit and first of all insert the chip on the Breadboard, these are the connections to make:

•               through the jumper to be Breadboard connect pins 7 and 20 of the chip to the positive supply line (+5 volts);

•               in the same way we connect the pins 8 and 22 of the chip to the ground line supply (GND);

•               connect pin 1 of the chip to the +5 V line through the resistor of 10 k Ω;

•               insert the crystal to the pins 9 and 10 of the chip;

•               insert the two 22 pF ceramic capacitors; both must have a leg connected to GND, while the other will serve to connect a capacitor to pin 9 and the other to pin 10 of the chip;

•               insert one end of resistor 560 Ω at the pin 19 and the other end into an empty spot on the breadboard, and to this end we connect the anode LED(the longer pin) , whose other end (cathode) goes to GND;

 

At this point we can connect to the Arduino Breadboard using jumper cables under the following matches:

•               Arduino pin 10 goes to pin 1 of the chip;

•               Arduino pin 11 goes to pin 17 of the chip;

•               pin 12 of Arduino is connected to pin 18 of the chip;

•               pin 13 to Arduino pin 19 goes on the chip;

•               the +5 V pins of Arduino goes to the positive supply line of the breadboard;

•               any of the three GND pin of Arduino goes to the ground line of the breadboard.

 

Now look the software to reveal the “trick” that sends a sketch, using the IDE, to the chip on the Breadboard, bypassing Arduino that will play the role of Programmer ISP.

What we need to do is create a virtual board, starting from the original (corresponding to the model we are using Arduino) and making some simple but essential changes. We must first locate the file that is boards.txt containing all information relating to the various boards that the IDE shows us when we execute the command Tools->Board. Typically this file is located in the folder of the IDE software, the path X: \ mypath \ arduino-xxx \ hardware \ arduino, where X is the letter that indicates the logical drive and myPath the folder or location containing the program (xxx indicates the version of the program).

Now open the file with Notepad and see a long series of lines arranged in groups separated by a line consisting of a repetition of the symbol ”#”,each group representing a different board. The lines are identified by the initial code, the same for all, but different for the board, the name that will appear in the submenu Tools->Board is inserted in the first row in the group.

The code is represented by the word “uno” which is at the beginning of each line.

The line containing the word “name” (usually the first) is followed by “=” and then the name that the board will have in the IDE.

Other information that concern us are:

uno.upload.maximum_size = 32256: Sets the maximum capacity of flash memory that we can use in practice from 32 Kbytes of Flash which has the total ATmega328P we must subtract the space occupied by the bootloader, for the Arduino UNO is 512 byte;

uno.bootloader.low_fuses = 0xffuno.bootloader.high_fuses = 0xdeuno.bootloader.extended_fuses = 0×05; these three lines are the “fuse”, are used to set the behavior of the chip and are expressed with hexadecimal values;

uno.build.f_cpu = 16000000L: This line must correspond to the clock frequency for which the chip has been set, by means of the fused, expressed in Hz, 1 Hz 6,000,000 correspond to 16 MHz, precisely the frequency of the quartz or, more precisely, the present external oscillator to Arduino UNO; this value is used as a reference for timing controls of the software, such as delay () and millis ().

 

And now we create our own virtual board, writing these lines of code:

 

atmsa16.name=ATmega in Stand Alone (w/ Arduino as ISP)
atmsa16.upload.protocol=stk500
atmsa16.upload.maximum_size=32768
atmsa16.upload.speed=115200
atmsa16.upload.using=arduino:arduinoisp
atmsa16.bootloader.low_fuses=0xff
atmsa16.bootloader.high_fuses=0xdf
atmsa16.bootloader.extended_fuses=0x05
#### atmsa16.bootloader.extended_fuses=0x07
atmsa16.bootloader.path=optiboot
atmsa16.bootloader.file=optiboot_atmega328.hex
atmsa16.bootloader.unlock_bits=0x3F
atmsa16.bootloader.lock_bits=0x0F
atmsa16.build.mcu=atmega328p
atmsa16.build.f_cpu=16000000L
atmsa16.build.core=arduino

 

Following the approach of the file will separate this group of lines to those of other boards, inserting a line of ”#”.The end result should be:

We note that are varied: the code (atmsa16 instead of uno), the maximum_size (brought to its maximum capabilities of Flash, since we do not reserve space for the bootloader), then there a new line (atmsa16.upload.using = arduino: arduinoisp) that allows us to understand the IDE that will program the chip in stand-alone and not on the Arduino. Another new line is preceded by some “# # # #” that disables it, the reason is easily explained: the extended_fuses is set to 0×05, and in some special cases, during the transfer of the sketch could be an error bound the setting of this value.As we shall see later, simply change the following two lines of code:

 <em># # # # Atmsa16.bootloader.extended_fuses = 0x05</em>
<em>atmsa16.bootloader.extended_fuses = 0x0</em>7

thus activating the value 0×07 instead of 0×05, it will work out. Of course, this change should not be made before, but only if you get the error.

 

Program the micro

At this point we are ready for the final step: send our sketches to the chip mounted on the breadboard and then will test the operation separating it from Arduino.


To read the new board in the file, the IDE must be restarted, so if this program was open, when editing the file boards.txt must close it and restart it. To verify that our modification is successful, it is sufficient now run the command Tools->Board and check if there is now our “stand-alone” board, otherwise we should close the IDE and check the file boards.txt, because certainly we made ​​a mistake.

The technique used to send the sketch to the chip in stand-alone mode is very simple: First select the Arduino board that we are using as a programmer (eg Arduino Duemilanove or UNO) , just as we do for normal use of Arduino. Then select the Arduino serial port (the COM for Windows users) and recall from the IDE the sketch ArduinoISP, execute this command by clicking the Upload button on the IDE. After several seconds of the three flashing LEDs and Arduino to the breadboard of course (at the moment is physically connected to pin 13 of Arduino that, as we know, check out one of the three LEDs on the board) on the IDE will come the message “done uploading “.

Arduino is ready to play the role of Programmer ISP, select, now, our board IDE “ATmega Stand Alone (w / Arduino as ISP)“, without changing the COM.

We load the sketch “blink” and execute it again by clicking the Upload button on the IDE: LEDs and Arduino breadboard flash again, this time for a much shorter period, after which the IDE will show the message again “Done uploading”.

So our ATmega328P chip was programmed without having to physically fit on Arduino and now lives its own life. It is then ready to be mounted in the circuit which it is intended.

Of course, the chip can be reprogrammed at will with any kind of sketch.

 

Troubleshooting

At this point we have to solve three types of problem that may occur when we send the sketch to the chip stand-alone. The problems of’extended_fuses and of autoreset may occur on either Arduino Duemilanove or Arduino UNO, without that you can establish a certain rule.We must also emphasize that the remedies that will illustrate to 100% solve the problems, but must be applied only if the problem occurs.

We start from the situation that may occur if we use a blank chip, the Atmel set the fuse to make the chip work at 1 MHz with the internal oscillator. If we send a sketch directly, happens that the chip in stand-alone ignores the external crystal and times will be staggered: for example, the LED blink with the sketch will last about 16 seconds instead of 1 second. Simply, we set the fuse, the operation can be done easily by loading the bootloader on the chip before sending the sketch.

Before explaining this simple maneuver quickly clarify two points: the bootloader is sent once a chip virgin and will only serve to set the fuse, then it will become useless and the sketch overwrite it, if we had to first load the sketch, noticing the error, and then load the bootloader, no problem: the chip is set and we just have to resubmit the sketch. The simple steps that are going to describe will return very useful for cases where we wanted to prepare a blank chip to work directly on Arduino; is a good idea to have in the house a spare chip with bootloader of our board, so if you were unfortunately damaged the original, a simple substitution solves this problem immediately.

Here are the steps to follow:

•               prepare and connect the Breadboard Arduino as discussed previously;

•               We open the IDE and select the model we are using Arduino and port to which it is connected;

•               upload the sketch ArduinoISP to Arduino;

•               now execute the command Tools->Burn Bootloader w / Arduino as ISP;

•               After about a minute we loaded into the stand-alone chip the bootloader of Arduino boards (you may have noticed that in the IDE we’ve set our Arduino board).

 

As mentioned, the chip can be quickly mounted to receive the Arduino sketch, or leave it on the breadboard and repeat/execute the operation of sending the sketch stand-alone, this time the Blink will work perfectly.

Of course, other errors may occur, do not worry, keep reading this section and of course everything will be resolved.

So let the problem of ’extended_fuses: the rows of our virtual board we expected a double value for this cast, because it can happen (even though it is quite rare) that some boards do not succeed in this program merged with the value 0×05. During the upload of the sketch on the chip with stand-alone mode, the IDE will display an error message (written in red on a black background) that will indicate the need to use the value 0×07, if it appears that in practice warning means that we must close the IDE, open the file boards.txt and activate the relevant line, simultaneously disabling the other (with 0×05), as explained above. At this point we can repeat the test. We clarify that if the error occurs on a given board will always occur on this board, so the variation of the files should be done only once and permanently.

And now we see the problem, more frequent, about autoreset. When the serial chip (FT232RL on Duemilanove or ATmega8U2 of UNO) receives a signal from the USB port, sends the reset pulse to ATmega328, who then prepares itself to receive Data. This operation corresponds to the one you make every time you press the button “RESET” on the Arduino.

If the data do not arrive or if the reset was made manually, the sketches in flash memory chip ATmega328 is executed. When Arduino is used as ISP Programmer can happen that, if the autoreset is sent too early, the upload operation fails. In this case the IDE returns the following error: ”avrdude:stk500_getsync (): not in sync: resp = 0×15“.

The problem is solved by blocking the Autoreset. The 120 ohm resistance must be connected between the RESET pin of Arduino and +5 V, while the 10µF capacitor is connected with the positive pole to the RESET of Arduino and negative to GND.

With a jumper cable connect on Breadboard the RESET signal of Arduino.

The methods described should be used only if absolutely necessary.

Important note: the need to connect these components only when needed, is dictated by the fact that to load a sketch on the Arduino should autoreset, otherwise the upload will fail and we will get the error avrdude: stk500_getsync (): not in sync: resp = 0×00 – avrdude: stk500_disable (): protocol error, expect = 0×14, resp = 0×51, so if you see this error, know that you just have to “liberate” the pin “RESET” Arduino from the link with the Anti- autoreset.

[Thanks to Michele Menniti]

The MAKERS Revolution

“A Thanks to Chris AndersonMassimo BanziDale Dougherty and the MAKERS of the new Industrial Revolution.

On March 9 in the Acquario Romano we heard testimonies of people, reality and Italian companies that have never stopped believing in innovation.
We like the stories of those who invest in their future without fear and looking to new technologies.
Just as we love the old craftsmen who know how to reinvent traditions. We know that it takes courage to get involved.
World Wide Rome has shown us that there are opportunities to do business.

No time to lose.

 We want this event would mark the beginning of something new.
We would like the genius of provocation Makers became a model of development.

Let’s get to work.

” [World Wide Rome]

We were there and we show you the key notes of Chris Anderson, and Dale Dougherty.

See the video covered by copyright.

 

More Photos

Open Electronics 10 Mar 19:23
arduino  featured  maker  mods  news  

Arduino RFID shield

This shield could be used as a stand-alone transponder key, or with Google’s servers to create a cloud-computing application.

 

It’s time to present you an application with RFID. We want to show you how to use the popular Arduino to produce a device capable of recognizing passive transponder (TAG). But this is not the usual RFID key, because the system can activate a relay if a recognised TAG is read, but also we took the opportunity to make an application that use cloud-computing. The basic version, which is a simple key relay consists of an Arduino (Duemilanove or UNO) and the RFID shield based on a ID-12 of Innovations: placing a transponder already learned, the relay is activated.
The extended version of our project uses an Arduino, the RFID Shield and the Ethernet Shield with which we can access the Internet and stored, using the Google Docs service, the transponder data.

The RFID shield
But before you see the applications in detail, we spend some words on the shield for Arduino that we need to capture data of passive TAG. It is a very simple circuit based on the form ID-12 , which contains a complete recognizer of passive transponders, in addition to a relay controlled by Arduino and a few other passive components. The buzzer, which allows you to set an audible alert, could be controlled by ID-12 or by Arduino.

The relay is powered by Vin Arduino (and the corresponding contact of the shield) and GND. The base of the transistor that controls RL1 is driven by the pin 9 of the Arduino. The lines 6 and 8 control the lighting of the LEDs.
In our case, the pin 7 of ID-12 is connected to ground, so the chip will only recognize ASCII coded tag and return its output in ASCII characters.

The component has a TTL level serial interface, accessible from it’s pins 9 and 8, then there is an output (pin 10) that pulses rapidly (at a frequency of 3 kHz) every time the module detects the code of a tag encoded and used to drive a buzzer or a light emitting diode.
All data are read from Arduino using the library NewsoftSerial that allows to emulate a serial port; in our case, the emulation is carried on lines 7.

How it works

Once you put power to the system, when the module ID-12 reads a tag, the pin 10 pulse at 3 kHz and the Arduino read s data; then microcontroller compares the code with those who has in memory.
If the transponder is one of those already learned the micro actives the relay and the green led. This relay will be used to control an electric lock, a gate, etc..
In bistable mode, the relay changes state each time the ID-12 reads a valid tag.
Clearly, the circuit can work well if in his memory there is at least a RFID tag.

To learn the code for a tag and then write it to EEPROM, you must press and hold button P1 for 3 seconds (max. 5), once that is done you have to pass a card and wait for the confirmation sound (given by buzzer) and light (provided by the green LED).
At any time you can remove a tag code from memory: must press the P1 button for 5 seconds or longer, until the red LED lights on. At this point you release the button and pass the tag to be deleted, if the LED turns off and on again, the card has been deleted.
To erase the entire EEPROM you must restart the Arduino, and during the reboot, hold down the button P1 for about one second; when the red LED lights up. Done this, Arduino is ready to read new tags.

R1: 330 ohm
R2: 330 ohm
R3: 4,7 kohm
R4: 10 kohm

LD1: Led 3 mm green
LD2: Led 3 mm red

BZ1: Buzzer

T1: BC547

RFID1: ID-12

RL1: Relé 12V

P1: Microswitch 90°

D1: 1N4007

Varie:
- Screw 3 poli
- Jumper (2 pz.)
- Strip male 3 via (2 pz.)
- Strip M/F 6 via (2 pz.)
- Strip M/F 8 via (2 pz.)


/* RFID shield key

 created 2011
 by Andrea Fainozzi

 This example code is in the public domain.

http://www.open-electronics.org

http://www.futurashop.it

http://blog.elettronicain.it/

 */

#include <EEPROM.h>
#include <NewSoftSerial.h>

#define PULSANTE   5               //pin relativo al pulsante da premere per entrare in modalità scrittura/cancellazione

#define DATA_PIN       7           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (7 | 
#define RELE_PIN       9           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (9 | 10)
#define BUZZ_PIN       3           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (3 | 11)
#define GREEN_LED_PIN  8           //pin relativo al led verde
#define RED_LED_PIN    6           //pin relativo al led rosso

//scegliere cosa fare quando viene letta una scheda

#define RELE     0                 //scegliere '1' per fare in modo che alla lettura di una scheda il relè venga attivato '0' per non fare nulla
#define BUZZER   1                 //scegliere '1' per fare in modo che alla lettura di una scheda il buzzer emetta un suono '0' per non fare nulla
#define LED      1                 //scegliere '1' per fare in modo che alla lettura di una scheda corretta venga acceso il led verde e per una scheda incorretta il led rosso '0' per non fare nulla

#define DURATA_RELE 1000          //scegliere il tempo per il quale deve rimanere acceso il relè (se viene inserito '0' il relè funzionerà in modo bistabile)

boolean check;                    //variabile con la quale eseguo tutti i controlli all'interno dello sketch
int on_off=0;                     //variabile che utilizzo per controllare lo stato del led in modalità bistabile

NewSoftSerial mySerial(DATA_PIN,1);    //inizializzo il pin sul quale leggere i dati trasmessi dall'ID-12
void setup() {

  if(DURATA_RELE>60000)                                                    //controllo che il tempo impostato per la durata di attivazione del relè sia inferiore a 1 minuto
    while(1){                                                              //in caso contrario stampo su seriale un messaggio di errore in un ciclo infinito
        delay(2000);
        Serial.print("Tempo relè non valido, troppo alto");
    }

  pinMode(PULSANTE,INPUT);                                                 //imposto il pin del pulsante in modalità input per verificare quando il pulsante viene premuto
  digitalWrite(PULSANTE,HIGH);                                             //e lo setto alto, in modo tale da attivare la resistenza di pull-up

  if(RELE)                                                                 //controllo se è stato scelto di attivare o meno il relè, nel primo caso, imposto il pin assegnatogli come output
    pinMode(RELE_PIN,OUTPUT);
  if(BUZZER)                                                               //controllo se è stato scelto di attivare o meno il buzzer, nel primo caso, imposto il pin assegnatogli come output
    pinMode(BUZZ_PIN,OUTPUT);
  if(LED){                                                                 //controllo se è stato scelto di attivare o meno i led, nel primo caso, imposto i pin assegnatogli come output
    pinMode(GREEN_LED_PIN,OUTPUT);
    pinMode(RED_LED_PIN,OUTPUT);
  }
  Serial.begin(9600);                                                      //Inizializzo la porta seriale sulla frequenza di 9600 baud
  mySerial.begin(9600);                                                    //inizializzo la seriale sulla quale leggo i dati delle schede a 9600 baud

  if(digitalRead(PULSANTE)==LOW) azzera();                                 //controllo che il il pulsante sia premuto in fase di accensione del dispositivo, in caso affermativo azzero tutta la memoria EEPROM
}

void loop () {

  byte val;                                                          //variabile che utilizzo per leggere i valori dalla tessera appena passata
  byte code[6];                                                      //vettore nel quale salvo il codice letto completo
  byte checksum;                                                     //variabile sulla quale calcolo e salvo il checksum
  byte bytesread;                                                    //variabile che viene utilizzata per per contare quanti byte sono stati letti
  byte tempbyte;                                                     //variabile che mi serve per memorizzare temporaneamente mezzo byte letto

  unsigned long int tempo=0;                                         //variabile che utilizzo per salvare il tempo attuale, per contare i millisecondi passati
  boolean scrivere=false;                                            //variabile che utilizzo per controllare se la tessera appena letta è da salvare o da controllare
  boolean controllo=false;                                           //variabile che utilizzo per controllare se la tessera appena letta è da cancellare oppure no

  if(digitalRead(PULSANTE)==LOW){                                    //controllo se il pulsante è premuto
     tempo=millis();                                                 //se lo è salvo gli attuali millisecondi passati dall'avvio del dispositivo
     while((digitalRead(PULSANTE)==LOW)&&(tempo+3000>millis()));     //quindi mando in esecuzione un ciclo che non fa nulla
     if(millis()>tempo+2999){                                        //controllo dopo la fine del ciclo se esso è stato in esecuzione per 3 secondi, confrontando il tempo iniziale + 3000 con il tempo attuale
       if(LED)
         digitalWrite(GREEN_LED_PIN,HIGH);                           //se così è, accendo il led verde
         Serial.println("Modalità registrazione");                   //e stampo sulla seriale che sono entrato in modalità registrazione
       if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //e faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
       }
         scrivere=true;                                              //e pongo a vero la variabile scrivere
     }
     if(digitalRead(PULSANTE)==LOW){                                 //se dopo ciò il pulsante è ancora premuto
       while((digitalRead(PULSANTE)==LOW)&&(tempo+5000>millis()));   //mando in esecuzione un altro ciclo nullo
       if(millis()>tempo+4999){                                      //se esso è stato in esecuzione per 2 secondi significa che sono entrato in modalita eliminazione
         Serial.println("Modalità eliminazione");                    //quindi lo scrivo sulla seriale
        if(LED){
         digitalWrite(RED_LED_PIN,HIGH);                             //accendo il led rosso
         digitalWrite(GREEN_LED_PIN,LOW);                            //spengo quello verde, precedentemente acceso
        }
        if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
        }
         while(digitalRead(PULSANTE)==LOW);                          //mando in esecuzione un ciclo finchè il pulsante non viene rilasciato
         controllo=true;                                             //e pongo a vero la variabile controllo
       }
     }
  }

//-------------------------------------------------------------------------------------inizio do-while------------------------------------------------------------------------------------------

  do{                                                                //inizio un ciclo che finirà solo quando verrà premuto nuovamente il pulsante

   val = 0;
   checksum = 0;                                                     //azzero le variabili precedentemente dichiarate
   bytesread = 0;
   tempbyte = 0;

  if(mySerial.available() > 0) {                                     //controllo se sulla mia seriale è presente qualche dato
    if((val = mySerial.read()) == 2) {                               //se così è leggo da essa il valore
      bytesread = 0;                                                 //e se è uguale a 2 (carattere di controllo) pongo a 0 la variabile bytesread
      while (bytesread < 12) {                                       //mando in esecuzione un ciclo per 12 volte, in modo da poter leggere tutti i 12 caratteri della tessera (5 byte del codice + 1 del cehcksum
      if( mySerial.available() > 0) {                                //controllo se i dati sono disponibili ad essere letti
          val = mySerial.read();                                     //quindi assegno a 'val' il valore dell'i-esimo carattere
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {     //se leggo un carattere 'header' o un carattere di stop
            break;                                                             // fermo la lettura
          }

          if ((val >= '0') && (val <= '9')) {
            val -= '0';
          }                                                                    //traduco in esadecimale il carattere appena letto
          else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          //ogni 2 caratteri letti, aggiungo il byte così creato al vettore 'code'

          if (bytesread & 1 == 1) {                                            //se ho letto un solo carattere fin'ora
            code[bytesread >> 1] = (val | (tempbyte << 4));                        //assegno alla seconda parte del byte in posizione bytesread-esima il valore esadecimale del carattere letto

            if (bytesread >> 1 != 5) {                                             //se ho letto l'ultimo byte della scheda calcolo il checksum
              checksum ^= code[bytesread >> 1];                                    //facendo la XOR sull'ultimo byte letto
            };
          } else {
            tempbyte = val;                                                    //altrimenti assegno il valore letto alla variabile tempbyte
          };

          bytesread++;                                                        //mi preparo a leggere il prossimo byte
        }
      }

     if (bytesread == 12) {                                                   //se ho letto tutti i 6 byte
        (code[5]==checksum) ? check = true : check = false ;                  //controllo che il checksum sia corretto
        if(check){                                                            //se lo è passo a controllare se devo salvare o cancellare
            check=false;                                                      //rimetto a false la variabile check per successivi utilizzi
            if(scrivere&&!controllo){                                         //controllo se devo scrivere
                  for(int i=0;i<1021;i+=5){                                   //in caso affermativo eseguo un ciclo che controlla tutta la EEPROM
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            check=true;                                        //se trovo il codice della tessera letta già salvato nella EEPROM metto a true la variabile 'check'
                            break;                                             //ed esco dal ciclo
                        }
                  }
                  if(check){                                                   //quindi controllo il valore della variabile check, se è vero, significa che la tessera è già stata registrata
                        Serial.print("Tessera già registrata!");               //quindi lo comunico su seriale
                        stampa_code(code);
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                        delay(50);
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        delay(50);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                      if(LED)
                        digitalWrite(RED_LED_PIN,LOW);
                  }

                  else{                                                        //se la tessera non è stata trovata
                      check=false;                                             //rimetto a false la variabile check per successivi utilizzi
                      for(int i=0;i<1021;i+=5){                                //quindi eseguo un ciclo che controlla tutta la EEPROM in cerca di 5 byte successivi liberi
                        if((EEPROM.read(i)==0xff)&&(EEPROM.read(i+1)==0xff)&&(EEPROM.read(i+2)==0xff)&&(EEPROM.read(i+3)==0xff)&&(EEPROM.read(i+4)==0xff)){
                          for(int j=i;j<i+5;j++)                               //una volta trovati, partendo dal primo, fino al quinto, ci salvo il valore della tessera
                              EEPROM.write(j,code[j-i]);                             //eseguendo un ciclo 5 volte
                          check=true;                                                //pongo a true la variabile check
                          break;                                               //ed esco dal ciclo
                        }
                      }
                      if(check){                                               //se la variabile check è vera, significa che ho salvato con successo, quindi
                          Serial.print("Tessera Salvata");                     //lo stampo su seriale
                          stampa_code(code);
                        if(BUZZER){
                          analogWrite(BUZZ_PIN,50);
                          delay(100);
                          digitalWrite(BUZZ_PIN,LOW);
                        }
                        if(LED){
                          for(int i=0;i<5;i++){
                           digitalWrite(GREEN_LED_PIN,HIGH);                   //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           delay(50);
                           digitalWrite(GREEN_LED_PIN,LOW);
                           delay(50);
                          }
                          digitalWrite(GREEN_LED_PIN,HIGH);
                        }
                      }
                      else{                                                    //se la variabile check non è vera, significa che ho controllato tutta la memoria senza trovare 5 byte sequenziali liberi
                           Serial.println("Memoria piena");                    //quindi spamo su seriale che la memoria è piena
                           for(int i=0;i<5;i++){
                           if(LED)
                             digitalWrite(RED_LED_PIN,HIGH);
                           if(BUZZER)
                             analogWrite(BUZZ_PIN,50);
                           delay(50);                                          //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           if(LED)
                             digitalWrite(RED_LED_PIN,LOW);
                           if(BUZZER)
                             digitalWrite(BUZZ_PIN,LOW);
                           delay(50);
                          }
                    }
                }
            }
            else if(scrivere&&controllo){                                      //se non bisogna salvare, controllo se bisogna eliminare una tessera
                  int posizione=-1;                                            //quindi inizializzo a -1 la variabile posizione, che mi servirà per salvare la posizione nella EEPROM della tessera
                  for(int i=0;i<1021;i+=5){                                    //ed eseguo un ciclo che controlla tutta la EEPROM per cercare il codice corrispondente
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            posizione=i;                                       //se viene trovato salvo la posizione del primo byte nella variabile posizione
                        break;                                                 //ed esco dal ciclo
                        }
                  }
                  if(posizione!=-1){                                           //quindi controllo che la variabile posizione sia diversa da -1 così da sapere se è stato trovato o meno il codice
                      for(int j=posizione;j<posizione+5;j++)                   //eseguo quindi un ciclo partendo dalla posizione 'posizione' nella EEPROM
                              EEPROM.write(j,0xff);                            //sovrascrivendo i 5 byte corrispondenti alla tessera, con il byte di default '0xff'
                      Serial.print("Scheda cancellata");                       //una volta fatto ciò, stampo su seriale l'avvenuta cancellazione
                      stampa_code(code);
                      if(LED){
                        digitalWrite(GREEN_LED_PIN,HIGH);
                        digitalWrite(RED_LED_PIN,HIGH);
                      }
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                      delay(250);
                      if(LED)
                        digitalWrite(GREEN_LED_PIN,LOW);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                  }
                  else{                                                        //se la variabile posizione vale -1 significa che non ha trovato in memoria la tessera letta
                      Serial.print("Impossibile cancellare la scheda, non è salvata");  //quindi lo comunico su seriale
                      stampa_code(code);
                      for(int x=0;x<10;x++){
                        if(LED)
                          digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER)
                          analogWrite(BUZZ_PIN,50);
                        delay(25);                                             //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        if(LED)
                          digitalWrite(RED_LED_PIN,LOW);
                        if(BUZZER)
                          digitalWrite(BUZZ_PIN,LOW);
                        delay(25);
                      }
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                    }

            }

            check=true;                                                        //rimetto a vero il valore della variabile check siccome il checksum è corretto
            }
            else{                                                              //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
                 if(LED)
                    digitalWrite(RED_LED_PIN,HIGH);
            }

     }
    }
  }
  }
  while((digitalRead(PULSANTE)==HIGH)&&(controllo||scrivere));

//-------------------------------------------------------------------------------------------fine do-while---------------------------------------------------------------------------------------

  if(LED){
    digitalWrite(GREEN_LED_PIN,LOW);                                          //spengo gli eventuali led accesi per conoscere la modalità nella quale ero all'interno del ciclo
    digitalWrite(RED_LED_PIN,LOW);
  }

  if (bytesread == 12) {                                                      //controllo di avere letto tutti i 6 byte della tessera
     if(check){                                                               //controllo che il checksum sia corretto
           if(!scrivere){                                                     //e controllo anche che non ci sia da salvare/scrivere una tessera
                  check=false;                                                //rimetto a false la variabile check per successivi utilizzi
                  for(int i=0;i<1021;i+=5)                                    //eseguo un ciclo che controlla tutta la EEPROM alla ricerca della tessera letta
                        if(EEPROM.read(i)==code[0]&&EEPROM.read(i+1)==code[1]&&EEPROM.read(i+2)==code[2]&&EEPROM.read(i+3)==code[3]&&EEPROM.read(i+4)==code[4]){
                            check=true;                                       //se viene trovata metto a true la variabile check
                            break;                                            //ed esco dal ciclo
                        }

                     if(check){                                               //quindi controllo il valore della variabile check
                       Serial.print("Tessera valida");                        //se è vero, significa che la tessera è stata trovata e quindi è valida, e lo stampo su seriale
                       stampa_code(code);
                       if(LED)
                            digitalWrite(GREEN_LED_PIN,HIGH);
                       if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(200);
                            digitalWrite(BUZZ_PIN,LOW);                       //quindi in base alla selezione dell'utente
                       }                                                      //mando un segnale luminoso e/o sonoro
                       if(RELE){                                              //in più accendo il relè
                            if(DURATA_RELE){                                  //secondo la modalità impostata dall'utente
                               digitalWrite(RELE_PIN,HIGH);
                               tempo=millis();
                               while(tempo+DURATA_RELE>millis());
                               digitalWrite(RELE_PIN,LOW);
                            }
                            else{
                               if(on_off){
                                  digitalWrite(RELE_PIN,LOW);
                                  on_off--;
                               }
                               else{
                                  digitalWrite(RELE_PIN,HIGH);
                                  on_off++;
                               }
                            }
                       }
                    }
                      else{                                                    //se al contrario il valore è falso
                        Serial.print("Tessera non valida!");                   //significa che ho controllato tutta la memoria senza trovare la tessera, quindi lo comunico su seriale
                        stampa_code(code);
                        if(LED)
                            digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);                        //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                            delay(50);
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);
                        }
                     }
                    }
                    if(LED){
                      delay(500);
                      digitalWrite(GREEN_LED_PIN,LOW);                         //spegno gli eventuali led rimasti accesi
                      digitalWrite(RED_LED_PIN,LOW);
                    }
     }
     else{                                                                     //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
     }
    }
  bytesread=0;                                                                 //azzero la variabile bytesread per una prossima lettura
}

//--------------------------------------------------------------------------FUNZIONE PER AZZERARE LA MEMORIA EEPROM------------------------------------------------------------------------------

void azzera(){
  if(LED){
    digitalWrite(GREEN_LED_PIN,HIGH);
    digitalWrite(RED_LED_PIN,HIGH);
  }
  for(int i=0;i<1023;i++)
      EEPROM.write(i,0xff);
  Serial.println("Memoria Azzerata!");
  if(BUZZER)
    analogWrite(BUZZ_PIN,50);
  for(int i=0;i<5;i++)
    if(LED){
      digitalWrite(GREEN_LED_PIN,HIGH);
      delay(100);
      digitalWrite(GREEN_LED_PIN,LOW);
      digitalWrite(RED_LED_PIN,HIGH);
      delay(100);
      digitalWrite(RED_LED_PIN,LOW);
    }
  if(BUZZER)
    digitalWrite(BUZZ_PIN,LOW);
}

//--------------------------------------------------------------FUNZIONE PER STAMPARE IL CODICE DELLA TESSERA LETTA SU SERIALE-------------------------------------------------------------------

void stampa_code(byte * code){
        Serial.print(": <");
        for (int i=0; i<5; i++) {
          if (code[i] < 16) Serial.print("0");
          Serial.print(code[i], HEX);
          if(i!=4)
            Serial.print(" ");
        }
        Serial.println(">");
}

 

 

Send data to Google

Our system may be facing a network and on the web to secure the cooperation of the Google Docs service. It only works if we add an Ethernet Shield.
Our online application proposes to use a Google Spreadsheet document (spreadsheet on Google Docs, anyway …) in which Arduino transcribe the codes read from valid cards. The only condition for accessing the service has to be registered, or have a Google account (eg Gmail), if you have not, open it: it is free and gives you the opportunity to have a mail box and many other free services offered by Google.
In practice, our system does not directly access to the spreadsheet, but sends the data using a form (form). We write a post to explain how to connect Arduino to Google Docs. All the results of a module is imported in the corresponding sheet, from which can be viewed by authorized users, or by anyone in possession of the link, if we remove the protection.


/* RFID shield Google

 created 2011
 by Andrea Fainozzi

 This example code is in the public domain.

http://www.open-electronics.org

http://www.futurashop.it

http://blog.elettronicain.it/

 */

#include <EEPROM.h>
#include <NewSoftSerial.h>
#include <Ethernet.h>
#include <SPI.h>
#include <Client.h>

char formkey[] = "dDh11222222233333333344444444MQ"; //Chiave identificatrice del documento di google (SOSTITUIRE CON LA PROPRIA CHIAVE PRESA DIRETTAMENTE DALL'URL DI GOOGLE SPREADSHEET)
byte mac[] = { 0x90,0xA2,0xDA,0x00,0x55,0xA3};         //Mac addres della scheda ethernet dell'arduino (SOSTITUIRE CON IL MAC ADDRESS RIPORTATO SULLA SHIELD ETHERNET)
byte ip[] = { 192,168,0,99};                           //IP da assegnare alla scheda ethernet dell'arduino (SOSTITUIRE CON UNO SUPPORTATO DALLA PROPRIA RETE)
byte subnet[] = { 255,255,255,0};                      //Maschera di sottorete riferita alla propria connessione (SOSTITUIRE CON LA PROPRIA SUBNET MASK)
byte gateway[] = { 192,168,0,254};                     //Gateway del proprio modem/router (SOSTITUIRE CON IL PROPRIO GATEWAY PREDEFINITO)
byte server[] = { 209,85,229,101 };                    //IP del server di google spreadsheet

Client client(server, 80);                             //connettiamo il nostro arduino, come client al server di google spreadsheet

char buffer [33];                                      //vettore nel quale salvo temporaneamente vari caratteri che mi serviranno per leggere totalmente le tessere
char codice[13];                                       //stringa nella quale andremo a salvare il codice letto dalla tessera

#define PULSANTE   5               //pin relativo al pulsante da premere per entrare in modalità scrittura/cancellazione

#define DATA_PIN       7           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (7 | 
#define RELE_PIN       9           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (9 | 10)
#define BUZZ_PIN       3           //scegliere il pin che si vuole utilizzare in base alla scelta fatta con il jumper sulla scheda (3 | 11)
#define GREEN_LED_PIN  8           //pin relativo al led verde
#define RED_LED_PIN    6           //pin relativo al led rosso

//scegliere cosa fare quando viene letta una scheda

#define RELE     1                 //scegliere '1' per fare in modo che alla lettura di una scheda il relè venga attivato '0' per non fare nulla
#define BUZZER   1                 //scegliere '1' per fare in modo che alla lettura di una scheda il buzzer emetta un suono '0' per non fare nulla
#define LED      1                 //scegliere '1' per fare in modo che alla lettura di una scheda corretta venga acceso il led verde e per una scheda incorretta il led rosso '0' per non fare nulla
#define EEPROM_ON_OFF 1            //scegliere '1'(consigliato) per fare in modo che alla lettura di una tessera, il programma controlli che essa sia registrata per essere valida, '0' per fare in modo che una qualsiasi tessera con checksum valido sia considerata valida

#define DURATA_RELE 1000          //scegliere il tempo per il quale deve rimanere acceso il relè (se viene inserito '0' il relè funzionerà in modo bistabile)

boolean check;                    //variabile con la quale eseguo tutti i controlli all'interno dello sketch
int on_off=0;                     //variabile che utilizzo per controllare lo stato del led in modalità bistabile

NewSoftSerial mySerial(DATA_PIN,1);    //inizializzo il pin sul quale leggere i dati trasmessi dall'ID-12
void setup() {

  Serial.begin(9600);
  Ethernet.begin(mac, ip , gateway , subnet);

  if(DURATA_RELE>60000)                                                    //controllo che il tempo impostato per la durata di attivazione del relè sia inferiore a 1 minuto
    while(1){                                                              //in caso contrario stampo su seriale un messaggio di errore in un ciclo infinito
        delay(2000);
        Serial.print("Tempo relè non valido, troppo alto");
    }

  pinMode(PULSANTE,INPUT);                                                 //imposto il pin del pulsante in modalità input per verificare quando il pulsante viene premuto
  digitalWrite(PULSANTE,HIGH);                                             //e lo setto alto, in modo tale da attivare la resistenza di pull-up

  if(RELE)                                                                 //controllo se è stato scelto di attivare o meno il relè, nel primo caso, imposto il pin assegnatogli come output
    pinMode(RELE_PIN,OUTPUT);
  if(BUZZER)                                                               //controllo se è stato scelto di attivare o meno il buzzer, nel primo caso, imposto il pin assegnatogli come output
    pinMode(BUZZ_PIN,OUTPUT);
  if(LED){                                                                 //controllo se è stato scelto di attivare o meno i led, nel primo caso, imposto i pin assegnatogli come output
    pinMode(GREEN_LED_PIN,OUTPUT);
    pinMode(RED_LED_PIN,OUTPUT);
  }
  Serial.begin(9600);                                                      //Inizializzo la porta seriale sulla frequenza di 9600 baud
  mySerial.begin(9600);                                                    //inizializzo la seriale sulla quale leggo i dati delle schede a 9600 baud

  if(digitalRead(PULSANTE)==LOW) azzera();                                 //controllo che il il pulsante sia premuto in fase di accensione del dispositivo, in caso affermativo azzero tutta la memoria EEPROM
}

void loop () {

  byte val;                                                          //variabile che utilizzo per leggere i valori dalla tessera appena passata
  byte code[6];                                                      //vettore nel quale salvo il codice letto completo
  byte checksum;                                                     //variabile sulla quale calcolo e salvo il checksum
  byte bytesread;                                                    //variabile che viene utilizzata per per contare quanti byte sono stati letti
  byte tempbyte;                                                     //variabile che mi serve per memorizzare temporaneamente mezzo byte letto

  unsigned long int tempo=0;                                         //variabile che utilizzo per salvare il tempo attuale, per contare i millisecondi passati
  boolean scrivere=false;                                            //variabile che utilizzo per controllare se la tessera appena letta è da salvare o da controllare
  boolean controllo=false;                                           //variabile che utilizzo per controllare se la tessera appena letta è da cancellare oppure no
 if(EEPROM_ON_OFF){
  if(digitalRead(PULSANTE)==LOW){                                    //controllo se il pulsante è premuto
     tempo=millis();                                                 //se lo è salvo gli attuali millisecondi passati dall'avvio del dispositivo
     while((digitalRead(PULSANTE)==LOW)&&(tempo+3000>millis()));     //quindi mando in esecuzione un ciclo che non fa nulla
     if(millis()>tempo+2999){                                        //controllo dopo la fine del ciclo se esso è stato in esecuzione per 3 secondi, confrontando il tempo iniziale + 3000 con il tempo attuale
       if(LED)
         digitalWrite(GREEN_LED_PIN,HIGH);                           //se così è, accendo il led verde
         Serial.println("Modalità registrazione");                   //e stampo sulla seriale che sono entrato in modalità registrazione
       if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //e faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
       }
         scrivere=true;                                              //e pongo a vero la variabile scrivere
     }
     if(digitalRead(PULSANTE)==LOW){                                 //se dopo ciò il pulsante è ancora premuto
       while((digitalRead(PULSANTE)==LOW)&&(tempo+5000>millis()));   //mando in esecuzione un altro ciclo nullo
       if(millis()>tempo+4999){                                      //se esso è stato in esecuzione per 2 secondi significa che sono entrato in modalita eliminazione
         Serial.println("Modalità eliminazione");                    //quindi lo scrivo sulla seriale
        if(LED){
         digitalWrite(RED_LED_PIN,HIGH);                             //accendo il led rosso
         digitalWrite(GREEN_LED_PIN,LOW);                            //spengo quello verde, precedentemente acceso
        }
        if(BUZZER){
         analogWrite(BUZZ_PIN,50);
         delay(50);                                                  //faccio fare un suono di avviso al buzzer
         digitalWrite(BUZZ_PIN,LOW);
        }
         while(digitalRead(PULSANTE)==LOW);                          //mando in esecuzione un ciclo finchè il pulsante non viene rilasciato
         controllo=true;                                             //e pongo a vero la variabile controllo
       }
     }
  }
 }

//-------------------------------------------------------------------------------------inizio do-while------------------------------------------------------------------------------------------

  do{                                                                //inizio un ciclo che finirà solo quando verrà premuto nuovamente il pulsante

   val = 0;
   checksum = 0;                                                     //azzero le variabili precedentemente dichiarate
   bytesread = 0;
   tempbyte = 0;

  if(mySerial.available() > 0) {                                     //controllo se sulla mia seriale è presente qualche dato
    if((val = mySerial.read()) == 2) {                               //se così è leggo da essa il valore
      bytesread = 0;                                                 //e se è uguale a 2 (carattere di controllo) pongo a 0 la variabile bytesread
      while (bytesread < 12) {                                       //mando in esecuzione un ciclo per 12 volte, in modo da poter leggere tutti i 12 caratteri della tessera (5 byte del codice + 1 del cehcksum
      if( mySerial.available() > 0) {                                //controllo se i dati sono disponibili ad essere letti
          val = mySerial.read();                                     //quindi assegno a 'val' il valore dell'i-esimo carattere
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {     //se leggo un carattere 'header' o un carattere di stop
            break;                                                             // fermo la lettura
          }

          if ((val >= '0') && (val <= '9')) {
            val -= '0';
          }                                                                    //traduco in esadecimale il carattere appena letto
          else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          //ogni 2 caratteri letti, aggiungo il byte così creato al vettore 'code'

          if (bytesread & 1 == 1) {                                            //se ho letto un solo carattere fin'ora
            code[bytesread >> 1] = (val | (tempbyte << 4));                        //assegno alla seconda parte del byte in posizione bytesread-esima il valore esadecimale del carattere letto

            if (bytesread >> 1 != 5) {                                             //se ho letto l'ultimo byte della scheda calcolo il checksum
              checksum ^= code[bytesread >> 1];                                    //facendo la XOR sull'ultimo byte letto
            };
          } else {
            tempbyte = val;                                                    //altrimenti assegno il valore letto alla variabile tempbyte
          };

          bytesread++;                                                        //mi preparo a leggere il prossimo byte
        }
      }

     if (bytesread == 12) {                                                   //se ho letto tutti i 6 byte
        (code[5]==checksum) ? check = true : check = false ;                  //controllo che il checksum sia corretto
      if(EEPROM_ON_OFF){                                                      //se è stato scelto di untilizzare la EEPROM
        if(check){                                                            //e il checksum è corretto, passo a controllare se devo salvare o cancellare
            check=false;                                                      //rimetto a false la variabile check per successivi utilizzi
            if(scrivere&&!controllo){                                         //controllo se devo scrivere
                  for(int i=0;i<1021;i+=5){                                   //in caso affermativo eseguo un ciclo che controlla tutta la EEPROM
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            check=true;                                        //se trovo il codice della tessera letta già salvato nella EEPROM metto a true la variabile 'check'
                            break;                                             //ed esco dal ciclo
                        }
                  }
                  if(check){                                                   //quindi controllo il valore della variabile check, se è vero, significa che la tessera è già stata registrata
                        Serial.print("Tessera già registrata!");               //quindi lo comunico su seriale
                        stampa_code(code);
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                        delay(50);
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        delay(50);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                      if(LED)
                        digitalWrite(RED_LED_PIN,LOW);
                  }

                  else{                                                        //se la tessera non è stata trovata
                      check=false;                                             //rimetto a false la variabile check per successivi utilizzi
                      for(int i=0;i<1021;i+=5){                                //quindi eseguo un ciclo che controlla tutta la EEPROM in cerca di 5 byte successivi liberi
                        if((EEPROM.read(i)==0xff)&&(EEPROM.read(i+1)==0xff)&&(EEPROM.read(i+2)==0xff)&&(EEPROM.read(i+3)==0xff)&&(EEPROM.read(i+4)==0xff)){
                          for(int j=i;j<i+5;j++)                               //una volta trovati, partendo dal primo, fino al quinto, ci salvo il valore della tessera
                              EEPROM.write(j,code[j-i]);                             //eseguendo un ciclo 5 volte
                          check=true;                                                //pongo a true la variabile check
                          break;                                               //ed esco dal ciclo
                        }
                      }
                      if(check){                                               //se la variabile check è vera, significa che ho salvato con successo, quindi
                          Serial.print("Tessera Salvata");                     //lo stampo su seriale
                          stampa_code(code);
                        if(BUZZER){
                          analogWrite(BUZZ_PIN,50);
                          delay(100);
                          digitalWrite(BUZZ_PIN,LOW);
                        }
                        if(LED){
                          for(int i=0;i<5;i++){
                           digitalWrite(GREEN_LED_PIN,HIGH);                   //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           delay(50);
                           digitalWrite(GREEN_LED_PIN,LOW);
                           delay(50);
                          }
                          digitalWrite(GREEN_LED_PIN,HIGH);
                        }
                      }
                      else{                                                    //se la variabile check non è vera, significa che ho controllato tutta la memoria senza trovare 5 byte sequenziali liberi
                           Serial.println("Memoria piena");                    //quindi spamo su seriale che la memoria è piena
                           for(int i=0;i<5;i++){
                           if(LED)
                             digitalWrite(RED_LED_PIN,HIGH);
                           if(BUZZER)
                             analogWrite(BUZZ_PIN,50);
                           delay(50);                                          //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                           if(LED)
                             digitalWrite(RED_LED_PIN,LOW);
                           if(BUZZER)
                             digitalWrite(BUZZ_PIN,LOW);
                           delay(50);
                          }
                    }
                }
            }
            else if(scrivere&&controllo){                                      //se non bisogna salvare, controllo se bisogna eliminare una tessera
                  int posizione=-1;                                            //quindi inizializzo a -1 la variabile posizione, che mi servirà per salvare la posizione nella EEPROM della tessera
                  for(int i=0;i<1021;i+=5){                                    //ed eseguo un ciclo che controlla tutta la EEPROM per cercare il codice corrispondente
                        if((EEPROM.read(i)==code[0])&&(EEPROM.read(i+1)==code[1])&&(EEPROM.read(i+2)==code[2])&&(EEPROM.read(i+3)==code[3])&&(EEPROM.read(i+4)==code[4])){
                            posizione=i;                                       //se viene trovato salvo la posizione del primo byte nella variabile posizione
                        break;                                                 //ed esco dal ciclo
                        }
                  }
                  if(posizione!=-1){                                           //quindi controllo che la variabile posizione sia diversa da -1 così da sapere se è stato trovato o meno il codice
                      for(int j=posizione;j<posizione+5;j++)                   //eseguo quindi un ciclo partendo dalla posizione 'posizione' nella EEPROM
                              EEPROM.write(j,0xff);                            //sovrascrivendo i 5 byte corrispondenti alla tessera, con il byte di default '0xff'
                      Serial.print("Scheda cancellata");                       //una volta fatto ciò, stampo su seriale l'avvenuta cancellazione
                      stampa_code(code);
                      if(LED){
                        digitalWrite(GREEN_LED_PIN,HIGH);
                        digitalWrite(RED_LED_PIN,HIGH);
                      }
                      if(BUZZER)
                        analogWrite(BUZZ_PIN,50);                              //e mando un segnale luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                      delay(250);
                      if(LED)
                        digitalWrite(GREEN_LED_PIN,LOW);
                      if(BUZZER)
                        digitalWrite(BUZZ_PIN,LOW);
                  }
                  else{                                                        //se la variabile posizione vale -1 significa che non ha trovato in memoria la tessera letta
                      Serial.print("Impossibile cancellare la scheda, non è salvata");  //quindi lo comunico su seriale
                      stampa_code(code);
                      for(int x=0;x<10;x++){
                        if(LED)
                          digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER)
                          analogWrite(BUZZ_PIN,50);
                        delay(25);                                             //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                        if(LED)
                          digitalWrite(RED_LED_PIN,LOW);
                        if(BUZZER)
                          digitalWrite(BUZZ_PIN,LOW);
                        delay(25);
                      }
                      if(LED)
                        digitalWrite(RED_LED_PIN,HIGH);
                    }

            }

            check=true;                                                        //rimetto a vero il valore della variabile check siccome il checksum è corretto
            }

            else{                                                              //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
                 if(LED)
                    digitalWrite(RED_LED_PIN,HIGH);
            }

     }
     }
    }
  }
  }
  while((digitalRead(PULSANTE)==HIGH)&&(controllo||scrivere));

//-------------------------------------------------------------------------------------------fine do-while---------------------------------------------------------------------------------------

  if(LED){
    digitalWrite(GREEN_LED_PIN,LOW);                                          //spengo gli eventuali led accesi per conoscere la modalità nella quale ero all'interno del ciclo
    digitalWrite(RED_LED_PIN,LOW);
  }

  if (bytesread == 12) {                                                      //controllo di avere letto tutti i 6 byte della tessera
     if(check&&EEPROM_ON_OFF){                                                //controllo che il checksum sia corretto e che è stato scelto di utilizzare la EEPROM
           if(!scrivere){                                                     //e controllo anche che non ci sia da salvare/scrivere una tessera
                  check=false;                                                //rimetto a false la variabile check per successivi utilizzi
                  for(int i=0;i<1021;i+=5)                                    //eseguo un ciclo che controlla tutta la EEPROM alla ricerca della tessera letta
                        if(EEPROM.read(i)==code[0]&&EEPROM.read(i+1)==code[1]&&EEPROM.read(i+2)==code[2]&&EEPROM.read(i+3)==code[3]&&EEPROM.read(i+4)==code[4]){
                            check=true;                                       //se viene trovata metto a true la variabile check
                            break;                                            //ed esco dal ciclo
                        }

                     if(check){                                               //quindi controllo il valore della variabile check
                       Serial.print("Tessera valida");                        //se è vero, significa che la tessera è stata trovata e quindi è valida, e lo stampo su seriale
                       stampa_code(code);
                       stampa_codice(code,codice);
                       if(LED)
                            digitalWrite(GREEN_LED_PIN,HIGH);
                       if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(200);
                            digitalWrite(BUZZ_PIN,LOW);                       //quindi in base alla selezione dell'utente
                       }                                                      //mando un segnale luminoso e/o sonoro
                       if(RELE){                                              //in più accendo il relè
                            if(DURATA_RELE){                                  //secondo la modalità impostata dall'utente
                               digitalWrite(RELE_PIN,HIGH);
                               tempo=millis();
                               while(tempo+DURATA_RELE>millis());
                               digitalWrite(RELE_PIN,LOW);
                            }
                            else{
                               if(on_off){
                                  digitalWrite(RELE_PIN,LOW);
                                  on_off--;
                               }
                               else{
                                  digitalWrite(RELE_PIN,HIGH);
                                  on_off++;
                               }
                            }
                       }
                      google_send("entry.0.single",codice);
                    }
                      else{                                                    //se al contrario il valore è falso
                        Serial.print("Tessera non valida!");                   //significa che ho controllato tutta la memoria senza trovare la tessera, quindi lo comunico su seriale
                        stampa_code(code);
                        if(LED)
                            digitalWrite(RED_LED_PIN,HIGH);
                        if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);                        //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                            delay(50);
                            analogWrite(BUZZ_PIN,50);
                            delay(50);
                            digitalWrite(BUZZ_PIN,LOW);
                        }
                     }
                    }
                    if(LED){
                      delay(500);
                      digitalWrite(GREEN_LED_PIN,LOW);                         //spegno gli eventuali led rimasti accesi
                      digitalWrite(RED_LED_PIN,LOW);
                    }
     }   

     else if(check&&!EEPROM_ON_OFF){
                             Serial.print("Tessera valida");                        //se è vero, significa che la tessera è stata trovata e quindi è valida, e lo stampo su seriale
                       stampa_code(code);
                       stampa_codice(code,codice);
                       if(LED)
                            digitalWrite(GREEN_LED_PIN,HIGH);
                       if(BUZZER){
                            analogWrite(BUZZ_PIN,50);
                            delay(200);
                            digitalWrite(BUZZ_PIN,LOW);                       //quindi in base alla selezione dell'utente
                       }                                                      //mando un segnale luminoso e/o sonoro
                       if(RELE){                                              //in più accendo il relè
                            if(DURATA_RELE){                                  //secondo la modalità impostata dall'utente
                               digitalWrite(RELE_PIN,HIGH);
                               tempo=millis();
                               while(tempo+DURATA_RELE>millis());
                               digitalWrite(RELE_PIN,LOW);
                            }
                            else{
                               if(on_off){
                                  digitalWrite(RELE_PIN,LOW);
                                  on_off--;
                               }
                               else{
                                  digitalWrite(RELE_PIN,HIGH);
                                  on_off++;
                               }
                            }
                       }
                      google_send("entry.0.single",codice);
     }

     else if(!check){                                                                     //se il checksum fosse incorretto
                 Serial.print("Checksum incorretto");                          //lo comunico su seriale
                 for(int i=0;i<3;i++){
                    if(LED)
                      digitalWrite(RED_LED_PIN,HIGH);
                    if(BUZZER)
                      analogWrite(BUZZ_PIN,50);
                    delay(30);                                                 //e mando un segnale di errore luminoso e/o sonoro in sempre in base al fatto che l'utente abbia specificato led e buzzer
                    if(LED)
                      digitalWrite(RED_LED_PIN,LOW);
                    if(BUZZER)
                      digitalWrite(BUZZ_PIN,LOW);
                 }
     }
    }
  bytesread=0;                                                                 //azzero la variabile bytesread per una prossima lettura
}

//--------------------------------------------------------------------------FUNZIONE PER AZZERARE LA MEMORIA EEPROM------------------------------------------------------------------------------

void azzera(){
  if(LED){
    digitalWrite(GREEN_LED_PIN,HIGH);
    digitalWrite(RED_LED_PIN,HIGH);
  }
  for(int i=0;i<1023;i++)
      EEPROM.write(i,0xff);
  Serial.println("Memoria Azzerata!");
  if(BUZZER)
    analogWrite(BUZZ_PIN,50);
  for(int i=0;i<5;i++)
    if(LED){
      digitalWrite(GREEN_LED_PIN,HIGH);
      delay(100);
      digitalWrite(GREEN_LED_PIN,LOW);
      digitalWrite(RED_LED_PIN,HIGH);
      delay(100);
      digitalWrite(RED_LED_PIN,LOW);
    }
  if(BUZZER)
    digitalWrite(BUZZ_PIN,LOW);
}

//--------------------------------------------------------------FUNZIONE PER STAMPARE IL CODICE DELLA TESSERA LETTA SU SERIALE-------------------------------------------------------------------

void stampa_code(byte * code){
        Serial.print(": <");
        for (int i=0; i<5; i++) {
          if (code[i] < 16) Serial.print("0");
          Serial.print(code[i], HEX);
          if(i!=4)
            Serial.print(" ");
        }
        Serial.println(">");
}

//------------------------------------------------------------FUNZIONE PER INVIARE A GOOGLE SPREADSHEET IL VALORE DELLA TESSERA LETTA------------------------------------------------------------

void google_send(char *entry,char *val){

  char *submit = "&submit=Submit";
  if (client.connect()) {
    client.print("POST /formResponse?formkey=");
    client.print(formkey);
    client.println("&ifq HTTP/1.1");
    client.println("Host: spreadsheets.google.com");
    client.println("Content-Type: application/x-www-form-urlencoded");
    client.print("Content-Length: ");
    client.println(strlen(entry)+1+strlen(val)+strlen(submit),DEC);
    client.println();
    client.print(entry);
    client.print("=");
    client.print(val);
    client.print(submit);
    client.println();
  }
  delay(1000);
  client.stop();
}

//-----------------------------------------------------------FUNZIONE PER CONVERTIRE DA BYTE A CARATTERE IL VALORE DELLA TESSERA LETTA-----------------------------------------------------------

void stampa_codice(byte * code,char * codice){
   char tmp[3];
   codice[0]='\0';
   for(int i=0;i<5;i++){
   sprintf(tmp, "%02X", code[i]);
   strncat(codice,tmp,2);
   }
}

 

 

[Thanks to Andrea Fainozzi]

ARDUINO WIFI RGB LAMP [IKEA DUDERÖ MODDING]

 

We create an application based on Arduino, that allows you to control brightness and color of a RGB strip LED via local network or Internet through a WiFi or Ethernet shield

How it works

The system that we propose is based on the Arduino UNO, on which are mounted two shield: the Ethernet or WIFI Shield, which provides the connection to LAN, and the RGB shield which mounts three power drivers to control the LED strip.
In Arduino must be loaded different sketch depending of the type of connection you choose (Ethernet or WiFi). The sketch allows you to manage communication via LAN and create a web interface (which will come to those who try to access via a local network) and run the commands received.
Arduino is like a web server, an HTML page is showed through a browser, by introducing into the address bar the IP address corresponding to the ethernet/WIFI shield.

This means that the lamp can be turned on and controlled by any device on the network or remotely via the Internet. The web page shows the current setting of R, G, B of the lamp and allows you to edit them.

 

The shield RGB

Arduino controls the LED channels by a shield very simple, containing three MOSFET enhancement-mode n-channel type P36NF06; each MOSFET is driven on the gate, through a resistor, with the logic signal that Arduino sends. To be precise, pin 3 controls T3 (red), pin 5 controls T2 (green) and pin 6 controls T1 (blue), each line has a status LED, polarized by a limiting resistor (LEDs indicate how it is behaving this channel). Note that Arduino controls the individual transistors by PWM signals, which duty cycle determines the presence and intensity of a certain color; more precisely, the width of the pulses can changes from a minimum to a maximum to decide how much light should be the group of LEDs of the respective color.

The drain of each MOSFET controls the load which must be connected with the anode to the positive line of the common power supply (+); for each channel there is a connector with a positive contact (goes on line common) and a negative (corresponding to the respective drain MOSFET).
We have provided the possibility to power the LEDs in two ways: with the power drawn by Arduino contact Vin (in which case you should close the jumper on Vin) or with a voltage supplied to the terminal PWR (PWR jumper closed on), you can opt for the first solution if you think your lamps absorbs less than 1.5 amps, but if you need more power you have give power apart from the shield, with a suitable power supply.
Note that by closing the jumper on Vin, the Arduino must be supplied at 12 V with a power supply capable of delivering all the current required.

 

R1: 1 kohm
R2: 390 ohm
R3: 180 ohm
R4: 330 ohm
R5: 330 ohm
R6: 330 ohm

T1: STP36NE06
T2: STP36NE06
T3: STP36NE06

LD1: Led 5 mm blue
LD2: Led 5 mm green
LD3: Led 5 mm red

D1: 6A600

- Screw a 2

R1: 1 kohm
R2: 390 ohm
R3: 180 ohm
R4: 330 ohm
R5: 330 ohm
R6: 330 ohm

T1: STP36NE06
T2: STP36NE06
T3: STP36NE06

LD1: Led 5 mm blu (510LB7C)
LD2: Led 5 mm verde
LD3: Led 5 mm rosso

D1: 6A600

Varie:
- Screw 2 via(4 pz.)
- Strip M/F 6 via (2 pz.)
- Strip M/F 8 via (2 pz.)

The sketch

/* IKEA Dudero mods WIFI Version

 created 2011
 by Boris Landoni

 This example code is in the public domain.

http://www.open-electronics.org

http://www.futurashop.it

http://blog.elettronicain.it/

 */

// Inclusione Libreria per Server Web WiFi
#include <WiServer.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>

int red = 3;    // RED LED connected to PWM pin 3
int green = 5;    // GREEN LED connected to PWM pin 5
int blue = 6;    // BLUE LED connected to PWM pin 6
int r=50; int g=100; int b=150;
int rup; int gup; int bup;
int fader=0;
int inc=10;
String inString = String(50);
char buffer[160]; // make sure this is large enough for the largest string it must hold

// Definizione Parametri Rete Wireless
#define WIRELESS_MODE_INFRA	1  // Infrastrutturata (basata su Access Point)
#define WIRELESS_MODE_ADHOC	2  // Ad-hoc (senza Access Point)

unsigned char local_ip[] = {192, 168, 0, 89};      // Indirizzo IP
unsigned char gateway_ip[] = {192, 168, 0, 254};	    // Indirizzo gateway IP
unsigned char subnet_mask[] = {255, 255, 255, 0};   // Subnet Mask
const prog_char ssid[] PROGMEM = {"AP_FES"};	    // SSID access point

// Selezione tipo di cifratura rete Wireless
unsigned char security_type = 3;  // 0 -> nessuna cifratura
                                  // 1 -> cifratura WEP
                                  // 2 -> cifratura WPA
                                  // 3 -> cifratura WPA2

// Password cifratura per WPA/WPA2 (max. 64 cratteri)
const prog_char security_passphrase[] PROGMEM = {"12345678"};

// Password cifratura per WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

// Selezione tipo di rete Wireless infrastrutturata
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

// Variabili per lunghezza SSID e password di cifratura
unsigned char ssid_len;
unsigned char security_passphrase_len;

prog_char string_0[] PROGMEM  = "<html><head><title>Boris's Project</title></head><script language=\"javascript\"> var alphaStr = \"0123456789ABCDEF\";";
prog_char string_1[] PROGMEM  = "var alphaArr = [\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"A\",\"B\",\"C\",\"D\",\"E\",\"F\"]; var RGB = [";
prog_char string_2[] PROGMEM  = "];function pulsRED(){document.bgColor='#FF0000';RGB = [255,0,0]}function pulsGRE(){document.bgColor='#00FF00';RGB = [0,255,0]}";
prog_char string_3[] PROGMEM  = "function pulsBLU(){document.bgColor='#0000FF';RGB = [0,0,255]}function pulsYEL(){document.bgColor='#FFFF00';RGB = [255,255,0]}";
prog_char string_4[] PROGMEM  = "function pulsPIN(){document.bgColor='#FF00FF';RGB = [255,0,255]}function pulsCEL(){document.bgColor='#00FFFF';RGB = [0,255,255]}";
prog_char string_5[] PROGMEM  = "function pulsWHI(){document.bgColor='#FFFFFF';RGB = [255,255,255]}";
prog_char string_6[] PROGMEM  = " ";
prog_char string_7[] PROGMEM  = "function HEX_from_RGB(){document.bgColor = '#' + DEC_to_HEX(RGB[0]) + DEC_to_HEX(RGB[1]) + DEC_to_HEX(RGB[2]);}";
prog_char string_8[] PROGMEM  = "function adjRED(incr){	RGB[0] += incr;	if (RGB[0] > 255) RGB[0] = 255;	if (RGB[0] < 0) RGB[0] = 0;}";
prog_char string_9[] PROGMEM  = "function adjGRN(incr)	{RGB[1] += incr;if (RGB[1] > 255) RGB[1] = 255;	if (RGB[1] < 0) RGB[1] = 0;}";
prog_char string_10[] PROGMEM  = "function adjBLU(incr)	{RGB[2] += incr;if (RGB[2] > 255) RGB[2] = 255;	if (RGB[2] < 0) RGB[2] = 0;}";
prog_char string_11[] PROGMEM = "function setRED(r) { RGB[0] = r; } function setGRN(g) { RGB[1] = g; } function setBLU(b) { RGB[2] = b; }";
prog_char string_12[] PROGMEM = "function newRGB() { HEX_from_RGB(); } </script> <script language=\"javascript\"> var i_a; ";
prog_char string_13[] PROGMEM = "function DEC_to_HEX(dec) {var n_ = Math.floor(dec / 16); var _n = dec - n_ * 16; return alphaArr[n_] + alphaArr[_n];	}";
prog_char string_14[] PROGMEM = "function HEX_to_DEC(hex){var n_ = alphaStr.indexOf(hex.substring(0,1)); var _n = alphaStr.indexOf(hex.substring(1,2)); return n_ * 16 + _n;	}";
prog_char string_15[] PROGMEM = "function updateFields(){var d = document.colForm;d.r.value = RGB[0];	d.g.value = RGB[1];	d.b.value = RGB[2];	}";
prog_char string_16[] PROGMEM = "function setRGB(){var d = document.colForm; var R = d.r.value;	var G = d.g.value;	var B = d.b.value;";
prog_char string_17[] PROGMEM = "setRED(parseInt(R));	setGRN(parseInt(G));	setBLU(parseInt(B));	newRGB(); updateFields();} </script>";
prog_char string_18[] PROGMEM = "</head><body><center><form method=GET, name=\"colForm\"><h1>The INTERNET RGB LAMP</h1> <table> <tr> <td valign=\"top\"> <input type=\"text\" name=\"r\"> ";
prog_char string_19[] PROGMEM = "<input type=\"text\" name=\"g\"> <input type=\"text\" name=\"b\"> <input type=\"button\" value=\"Calculate\" onclick=\"setRGB();\">";
prog_char string_20[] PROGMEM = " </td></tr> <tr><td><CENTER><input type=\"button\" class=\"tweak\" value=\"Red+\" onclick=\"adjRED(i_a);newRGB();updateFields();\">";
prog_char string_21[] PROGMEM = "<input type=\"button\" class=\"tweak\" value=\"Green+\" onclick=\"adjGRN(i_a);newRGB();updateFields();\"><input type=\"button\" class=\"tweak\" value=\"Blue+\"";
prog_char string_22[] PROGMEM = "onclick=\"adjBLU(i_a);newRGB();updateFields();\"> <select name=\"inc\" onchange=\"i_a = parseInt(document.colForm.inc.options";
prog_char string_23[] PROGMEM = "[document.colForm.inc.selectedIndex].value);\"> <option value=\"1\"";//selected
prog_char string_24[] PROGMEM = ">inc/speed = 1x <option value=\"5\"";
prog_char string_25[] PROGMEM = ">inc/speed = 5x <option value=\"10\"";
prog_char string_26[] PROGMEM = ">inc/speed = 10x <option value=\"25\"";
prog_char string_27[] PROGMEM = ">inc/speed = 25x <option value=\"50\"";
prog_char string_28[] PROGMEM = ">inc/speed = 50x <option value=\"100\"";
prog_char string_29[] PROGMEM = ">inc/speed = 100x <option value=\"150\"";
prog_char string_30[] PROGMEM = ">inc/speed = 150x <option value=\"200\"";
prog_char string_31[] PROGMEM = ">inc/speed = 200x <option value=\"250\"";
prog_char string_32[] PROGMEM = ">inc/speed = 250x</select><input type=";
prog_char string_33[] PROGMEM = "\"button\" class=\"tweak\" value=\"Red-\" onclick=\"adjRED(0-i_a);newRGB();updateFields();\"><input type=\"button\" class=\"tweak\" value=\"Green-\"";
prog_char string_34[] PROGMEM = "onclick=\"adjGRN(0-i_a);newRGB();updateFields();\"><input type=\"button\" class=\"tweak\" value=\"Blue-\" onclick=\"adjBLU(0-i_a);newRGB();updateFields();\">";
prog_char string_35[] PROGMEM = "</CENTER></td> <tr><td><CENTER>Fader<input type=\"radio\" name=\"fad\" value=\"1\"";
prog_char string_36[] PROGMEM = "/> On<input type=\"radio\" name=\"fad\" value=\"0\" ";
prog_char string_37[] PROGMEM = "/> Off</CENTER></td></tr> </tr></td> </tr> <input type=\"submit\" style=\" width:80;height:44px;background-color:FF0000;\" onclick=\"pulsRED();updateFields();\";>";
prog_char string_38[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:00FF00;\" onclick=\"pulsGRE();updateFields();\";>";
prog_char string_39[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:0000FF;\" onclick=\"pulsBLU();updateFields();\";>";
prog_char string_40[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:FFFF00;\" onclick=\"pulsYEL();updateFields();\";>";
prog_char string_41[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:FF00FF;\" onclick=\"pulsPIN();updateFields();\";>";
prog_char string_42[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:00FFFF;\" onclick=\"pulsCEL();updateFields();\";>";
prog_char string_43[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:FFFFFF;\" onclick=\"pulsWHI();updateFields();\";>";
prog_char string_44[] PROGMEM = "<tr><td><CENTER><input type=\"submit\" value=\"Set colors\"></CENTER></td></tr>   ";
prog_char string_45[] PROGMEM = "</table> </form> <script language=\"javascript\">newRGB(); updateFields(); ";
prog_char string_46[] PROGMEM = "i_a = parseInt(document.colForm.inc.options[document.colForm.inc.selectedIndex].value);</script>";
prog_char string_47[] PROGMEM = "<font size= 2>Powered by Open-Electronics.org - Boris Landoni</font>"; //please don't remove  ";
prog_char string_48[] PROGMEM  = "<br></center></body></html>";
prog_char string_49[] PROGMEM  = "";
prog_char string_50[] PROGMEM  = "";
prog_char string_51[] PROGMEM  = "";

PROGMEM const char *string_table[] = // change "string_table" name to suit
{
string_0,
string_1,
string_2,
string_3,
string_4,
string_5,
string_6,
string_7,
string_8,
string_9,
string_10,
string_11,
string_12,
string_13,
string_14,
string_15,
string_16,
string_17,
string_18,
string_19,
string_20,
string_21,
string_22,
string_23,
string_24,
string_25,
string_26,
string_27,
string_28,
string_29,
string_30,
string_31,
string_32,
string_33,
string_34,
string_35,
string_36,
string_37,
string_38,
string_39,
string_40,
string_41,
string_42,
string_43,
string_44,
string_45,
string_46,
string_47,
string_48,
string_49,
string_50,
string_51
};

void setup()
{
  // start the Ethernet connection and the server:
// Inizializzo WiServer (Gestione_Richieste_Web per creare/trasmettere pagine HTML)
      WiServer.init (Gestione_Richieste_Web);
      // Inizializzo porta seriale
      Serial.begin (9600);
      WiServer.enableVerboseMode (false);

      Serial.println("Serial READY");
      Serial.println("WiFi READY");
      Serial.println("Server READY");

      r = EEPROM.read(1);
      g = EEPROM.read(2);
      b = EEPROM.read(3);
      inc = EEPROM.read(4);
      fader = EEPROM.read(5);
} 

void loop()  { 

    // Avvio WiServer
  WiServer.server_task();

  delay(10);

  if (fader==1){
    funcfader();
  }

}

// Gestione diverse richieste provenienti dal WEB
// INPUT:   URL pagina web richiesta
// OUTPUT:  Flag URL riconosciuto/non riconosciutoo
boolean Gestione_Richieste_Web (char* URL) {
  Serial.print("Richiesta Web - URL->");
  Serial.println(URL); 

  // Se URL richiesto corrisponde a "/" (pagina index)
  if (strcmp (URL, "/") == 0) {
    // Secondo gli I/O creo e invio le pagine Web
    Serial.println("pagina index");
    printWebPage();

    // Ritorno URL è stato riconosciuto
    return true;
  }    // Chiusura if URL richieso corrisponde a "/" (pagina index)

  // Se URL richieso corrisponde a "?OPERATION=ACCENDI_ROSSO
  if (strncmp (URL, "/?r=*",4) == 0) {

    Serial.println("pagina operazione"); 

                char colorArr[5];
                String temp="";
                inString=URL;
                Serial.print("inString: ");
                Serial.println(inString);

                int Pos_r = inString.indexOf("r");
                int Pos_g = inString.indexOf("g");
                int Pos_b = inString.indexOf("b");
                int Pos_i = inString.indexOf("inc");
                int Pos_f = inString.indexOf("fad");
                int End = inString.indexOf("HTTP");
                Serial.print("Pos_r: ");
                Serial.println(Pos_r);
                Serial.print("Pos_g: ");
                Serial.println(Pos_g);
                Serial.print("Pos_b: ");
                Serial.println(Pos_b);
                Serial.print("Pos_i: ");
                Serial.println(Pos_i);
                Serial.print("Pos_f: ");
                Serial.println(Pos_f);
                Serial.print("End: ");
                Serial.println(End);
                if(Pos_r>=0){
                   temp=inString.substring((Pos_r+2), (Pos_g-1));
                   temp.toCharArray(colorArr, 5);
                   r=(atoi(colorArr));
                   Serial.print("red: ");
                   Serial.println(r);
                   EEPROM.write(1, r);
                }
                if(Pos_g>=0){
                   temp=inString.substring((Pos_g+2), (Pos_b-1));
                   temp.toCharArray(colorArr, 5);
                   g=(atoi(colorArr));
                   Serial.print("green: ");
                   Serial.println(g);
                   EEPROM.write(2, g);
                }         

                if(Pos_b>=0){
                   temp=inString.substring((Pos_b+2), (Pos_i-1));
                   temp.toCharArray(colorArr, 5);
                   b=(atoi(colorArr));
                   Serial.print("blue: ");
                   Serial.println(b);
                   EEPROM.write(3, b);
                }      

                if(Pos_i>=0){
                   temp=inString.substring((Pos_i+4), (Pos_f-1));
                   temp.toCharArray(colorArr, 5);
                   inc=(atoi(colorArr));
                   Serial.print("inc: ");
                   Serial.println(inc);
                   EEPROM.write(4, inc);
                } 

                if(Pos_f>=0){
                   temp=inString.substring((Pos_f+4), (End-1));
                   temp.toCharArray(colorArr, 5);
                   fader=(atoi(colorArr));
                   Serial.print("fader: ");
                   Serial.println(fader);
                   EEPROM.write(5, fader);
                }     

               if ((Pos_r>=0)&&(Pos_g>=0)&&(Pos_b>=0)) {
                 rgb(r,g,b);
               }

    // Secondo gli I/O creo e invio le pagine Web
    printWebPage();

    // Ritorno URL è stato riconosciuto
    return true;
  }    // Chiusura if URL richieso corrisponde a "?OPERATION=ACCENDI_ROSSO"

  // Ritorno URL non riconosciuto
  return false;
}

 void printWebPage2()
{
      int tmp=0;
      Serial.println("printWebPage");
      // send a standard http response header

//      WiServer.print("HTTP/1.1 200 OK");
//      WiServer.print("Content-Type: text/html");
//      WiServer.print();

      //strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0]))); // Necessary casts and dereferencing, just copy.
      //WiServer.print( buffer );
      //Serial.println( buffer );
      for (int i = 0; i < 51; i++)
      {
          //strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
          //WiServer.print( buffer );
          WiServer.print_P((char*)pgm_read_word(&(string_table[i])));
          //Serial.println( buffer );
          //delay(500);
      }

}          

void printWebPage()
{
      int tmp=0;
      Serial.println("printWebPage");
      // send a standard http response header
      //WiServer.print_P("HTTP/1.1 200 OK");
      //WiServer.print_P("Content-Type: text/html");

      //strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0]))); // Necessary casts and dereferencing, just copy.
      WiServer.print_P((char*)pgm_read_word(&(string_table[0])));
      //Serial.println( buffer );
      for (int i = 1; i < 51; i++)
      {
          /*if (i==9)
          {
              strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i])));  //butto tutto nell'array buffer
              for (tmp=0 ; tmp < sizeof(buffer); tmp++)
              {
                if (buffer[tmp]=='#')
                {
                  //Serial.println( "trovato ##### " ); 

                }

              }
          }
          else
          {
            strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
          }*/
          //strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
          WiServer.print_P((char*)pgm_read_word(&(string_table[i])));
          //Serial.println( buffer );
          if (i==1)
          {
            char tmpstr[4];
            WiServer.print( itoa(r,tmpstr,10) );
            //Serial.println( itoa(r,tmpstr,10) );
            WiServer.print( "," );
            //Serial.println("," );
            WiServer.print( itoa(g,tmpstr,10) );
            //Serial.println( itoa(g,tmpstr,10) );
            WiServer.print( "," );
            //Serial.println( "," );
            WiServer.print( itoa(b,tmpstr,10) );
            //Serial.println( itoa(b,tmpstr,10) );
          }

          if (i==23){if (inc==1){WiServer.print("selected");}}
          if (i==24){if (inc==5){WiServer.print("selected");}}
          if (i==25){if (inc==10){WiServer.print("selected");}}
          if (i==26){if (inc==25){WiServer.print("selected");}}
          if (i==27){if (inc==50){WiServer.print("selected");}}
          if (i==28){if (inc==100){WiServer.print("selected");}}
          if (i==29){if (inc==150){WiServer.print("selected");}}
          if (i==30){if (inc==200){WiServer.print("selected");}}
          if (i==31){if (inc==250){WiServer.print("selected");}}

          if (i==35)
          {
            if (fader==1){
              WiServer.print("checked");
            }
          }
          if (i==36)
          {
            if (fader==0){
              WiServer.print("checked");
            }
          }
      }
     Serial.println("FINE printWebPage"); 

}

void funcfader(){
    Serial.println("fader");
    if (rup==1){r+=1;}
    else{r-=1;}
    if (r>=255){rup=0;}
    if (r<=0){rup=1;}

    if (gup==1){g+=1;}
    else{g-=1;}
    if (g>=255){gup=0;}
    if (g<=0){gup=1;}

    if (bup==1){b+=1;}
    else{b-=1;}
    if (b>=255){bup=0;}
    if (b<=0){bup=1;}

    delay(inc*2);
    rgb(r, g, b);
}

void rgb(int r, int g, int b)
{

  Serial.print("RGB: ");
  Serial.print(r);
  Serial.print(" ");
  Serial.print(g);
  Serial.print(" ");
  Serial.print(b);
  if (r>255) r=255;
  if (g>255) g=255;
  if (b>255) b=255;
  if (r<0) r=0;
  if (g<0) g=0;
  if (b<0) b=0;

  analogWrite(red, r);
  analogWrite(green, g);
  analogWrite(blue, b);
}

 

/* IKEA Dudero mods Ethernet Version

 created 2011
 by Boris Landoni

 This example code is in the public domain.

http://www.open-electronics.org

http://www.futurashop.it

http://blog.elettronicain.it/

 */

#include <SPI.h>
#include <Ethernet.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>

int red = 3;    // RED LED connected to PWM pin 3
int green = 5;    // GREEN LED connected to PWM pin 5
int blue = 6;    // BLUE LED connected to PWM pin 6
int r=50; int g=100; int b=150;
int rup; int gup; int bup;
int fader=0;
int inc=10;
String inString = String(50);
char buffer[160]; // make sure this is large enough for the largest string it must hold

byte mac[] = {  0x90, 0xA2, 0xDA, 0x00, 0x1D, 0x89 };
byte ip[] = { 192,168,0,88 };
byte gateway[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };

/*

*/

prog_char string_0[] PROGMEM  = "<html><head><title>Boris's Project</title></head><script language=\"javascript\"> var alphaStr = \"0123456789ABCDEF\";";
prog_char string_1[] PROGMEM  = "var alphaArr = [\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"A\",\"B\",\"C\",\"D\",\"E\",\"F\"]; var RGB = [";
prog_char string_2[] PROGMEM  = "];function pulsRED(){document.bgColor='#FF0000';RGB = [255,0,0]}function pulsGRE(){document.bgColor='#00FF00';RGB = [0,255,0]}";
prog_char string_3[] PROGMEM  = "function pulsBLU(){document.bgColor='#0000FF';RGB = [0,0,255]}function pulsYEL(){document.bgColor='#FFFF00';RGB = [255,255,0]}";
prog_char string_4[] PROGMEM  = "function pulsPIN(){document.bgColor='#FF00FF';RGB = [255,0,255]}function pulsCEL(){document.bgColor='#00FFFF';RGB = [0,255,255]}";
prog_char string_5[] PROGMEM  = "function pulsWHI(){document.bgColor='#FFFFFF';RGB = [255,255,255]}";
prog_char string_6[] PROGMEM  = "";
prog_char string_7[] PROGMEM  = "function HEX_from_RGB(){document.bgColor = '#' + DEC_to_HEX(RGB[0]) + DEC_to_HEX(RGB[1]) + DEC_to_HEX(RGB[2]);}";
prog_char string_8[] PROGMEM  = "function adjRED(incr){	RGB[0] += incr;	if (RGB[0] > 255) RGB[0] = 255;	if (RGB[0] < 0) RGB[0] = 0;}";
prog_char string_9[] PROGMEM  = "function adjGRN(incr)	{RGB[1] += incr;if (RGB[1] > 255) RGB[1] = 255;	if (RGB[1] < 0) RGB[1] = 0;}";
prog_char string_10[] PROGMEM  = "function adjBLU(incr)	{RGB[2] += incr;if (RGB[2] > 255) RGB[2] = 255;	if (RGB[2] < 0) RGB[2] = 0;}";
prog_char string_11[] PROGMEM = "function setRED(r) { RGB[0] = r; } function setGRN(g) { RGB[1] = g; } function setBLU(b) { RGB[2] = b; }";
prog_char string_12[] PROGMEM = "function newRGB() { HEX_from_RGB(); } </script> <script language=\"javascript\"> var i_a; ";
prog_char string_13[] PROGMEM = "function DEC_to_HEX(dec) {var n_ = Math.floor(dec / 16); var _n = dec - n_ * 16; return alphaArr[n_] + alphaArr[_n];	}";
prog_char string_14[] PROGMEM = "function HEX_to_DEC(hex){var n_ = alphaStr.indexOf(hex.substring(0,1)); var _n = alphaStr.indexOf(hex.substring(1,2)); return n_ * 16 + _n;	}";
prog_char string_15[] PROGMEM = "function updateFields(){var d = document.colForm;d.r.value = RGB[0];	d.g.value = RGB[1];	d.b.value = RGB[2];	}";
prog_char string_16[] PROGMEM = "function setRGB(){var d = document.colForm; var R = d.r.value;	var G = d.g.value;	var B = d.b.value;";
prog_char string_17[] PROGMEM = "setRED(parseInt(R));	setGRN(parseInt(G));	setBLU(parseInt(B));	newRGB(); updateFields();} </script>";
prog_char string_18[] PROGMEM = "</head><body><center><form method=GET, name=\"colForm\"><h1>The INTERNET RGB LAMP</h1> <table> <tr> <td valign=\"top\"> <input type=\"text\" name=\"r\"> ";
prog_char string_19[] PROGMEM = "<input type=\"text\" name=\"g\"> <input type=\"text\" name=\"b\"> <input type=\"button\" value=\"Calculate\" onclick=\"setRGB();\">";
prog_char string_20[] PROGMEM = " </td></tr> <tr><td><CENTER><input type=\"button\" class=\"tweak\" value=\"Red+\" onclick=\"adjRED(i_a);newRGB();updateFields();\">";
prog_char string_21[] PROGMEM = "<input type=\"button\" class=\"tweak\" value=\"Green+\" onclick=\"adjGRN(i_a);newRGB();updateFields();\"><input type=\"button\" class=\"tweak\" value=\"Blue+\"";
prog_char string_22[] PROGMEM = "onclick=\"adjBLU(i_a);newRGB();updateFields();\"> <select name=\"inc\" onchange=\"i_a = parseInt(document.colForm.inc.options";
prog_char string_23[] PROGMEM = "[document.colForm.inc.selectedIndex].value);\"> <option value=\"1\"";//selected
prog_char string_24[] PROGMEM = ">inc/speed = 1x <option value=\"5\"";
prog_char string_25[] PROGMEM = ">inc/speed = 5x <option value=\"10\"";
prog_char string_26[] PROGMEM = ">inc/speed = 10x <option value=\"25\"";
prog_char string_27[] PROGMEM = ">inc/speed = 25x <option value=\"50\"";
prog_char string_28[] PROGMEM = ">inc/speed = 50x <option value=\"100\"";
prog_char string_29[] PROGMEM = ">inc/speed = 100x <option value=\"150\"";
prog_char string_30[] PROGMEM = ">inc/speed = 150x <option value=\"200\"";
prog_char string_31[] PROGMEM = ">inc/speed = 200x <option value=\"250\"";
prog_char string_32[] PROGMEM = ">inc/speed = 250x</select><input type=";
prog_char string_33[] PROGMEM = "\"button\" class=\"tweak\" value=\"Red-\" onclick=\"adjRED(0-i_a);newRGB();updateFields();\"><input type=\"button\" class=\"tweak\" value=\"Green-\"";
prog_char string_34[] PROGMEM = "onclick=\"adjGRN(0-i_a);newRGB();updateFields();\"><input type=\"button\" class=\"tweak\" value=\"Blue-\" onclick=\"adjBLU(0-i_a);newRGB();updateFields();\">";
prog_char string_35[] PROGMEM = "</CENTER></td> <tr><td><CENTER>Fader<input type=\"radio\" name=\"fad\" value=\"1\"";
prog_char string_36[] PROGMEM = "/> On<input type=\"radio\" name=\"fad\" value=\"0\" ";
prog_char string_37[] PROGMEM = "/> Off</CENTER></td></tr> </tr></td> </tr> <input type=\"submit\" style=\" width:80;height:44px;background-color:FF0000;\" onclick=\"pulsRED();updateFields();\";>";
prog_char string_38[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:00FF00;\" onclick=\"pulsGRE();updateFields();\";>";
prog_char string_39[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:0000FF;\" onclick=\"pulsBLU();updateFields();\";>";
prog_char string_40[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:FFFF00;\" onclick=\"pulsYEL();updateFields();\";>";
prog_char string_41[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:FF00FF;\" onclick=\"pulsPIN();updateFields();\";>";
prog_char string_42[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:00FFFF;\" onclick=\"pulsCEL();updateFields();\";>";
prog_char string_43[] PROGMEM = "<input type=\"submit\" style=\" width:80;height:44px;background-color:FFFFFF;\" onclick=\"pulsWHI();updateFields();\";>";
prog_char string_44[] PROGMEM = "<tr><td><CENTER><input type=\"submit\" value=\"Set colors\"></CENTER></td></tr>   ";
prog_char string_45[] PROGMEM = "</table> </form> <script language=\"javascript\">newRGB(); updateFields(); ";
prog_char string_46[] PROGMEM = "i_a = parseInt(document.colForm.inc.options[document.colForm.inc.selectedIndex].value);</script>";
prog_char string_47[] PROGMEM = "<font size= 2>Powered by Open-Electronics.org - Boris Landoni</font>"; //please don't remove  ";
prog_char string_48[] PROGMEM  = "<br></center></body></html>";
prog_char string_49[] PROGMEM  = "";
prog_char string_50[] PROGMEM  = "";
prog_char string_51[] PROGMEM  = "";

PROGMEM const char *string_table[] = // change "string_table" name to suit
{
string_0,
string_1,
string_2,
string_3,
string_4,
string_5,
string_6,
string_7,
string_8,
string_9,
string_10,
string_11,
string_12,
string_13,
string_14,
string_15,
string_16,
string_17,
string_18,
string_19,
string_20,
string_21,
string_22,
string_23,
string_24,
string_25,
string_26,
string_27,
string_28,
string_29,
string_30,
string_31,
string_32,
string_33,
string_34,
string_35,
string_36,
string_37,
string_38,
string_39,
string_40,
string_41,
string_42,
string_43,
string_44,
string_45,
string_46,
string_47,
string_48,
string_49,
string_50,
string_51
};

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
Server server(80);

void setup()
{
  // start the Ethernet connection and the server:
      Serial.begin(9600);
      Ethernet.begin(mac, ip,gateway,subnet);
      server.begin();
      Serial.println("Serial READY");
      Serial.println("Ethernet READY");
      Serial.println("Server READY");
      r = EEPROM.read(1);
      g = EEPROM.read(2);
      b = EEPROM.read(3);
      inc = EEPROM.read(4);
      fader = EEPROM.read(5);
} 

void loop()  {
//  // fade in from min to max in increments of 5 points:
//  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) {
//    // sets the value (range from 0 to 255):
//    //analogWrite(red, fadeValue);
//    // wait for 30 milliseconds to see the dimming effect
//    rgb(fadeValue,fadeValue,fadeValue);
//    delay(30);
//  }
//
//  // fade out from max to min in increments of 5 points:
//  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) {
//    // sets the value (range from 0 to 255):
//    //analogWrite(red, fadeValue);
//    // wait for 30 milliseconds to see the dimming effect
//    rgb(fadeValue,fadeValue,fadeValue);
//    delay(30);
//  } 

  if (fader==1){
    funcfader();
  }

      Client client = server.available();

      if (client) {
        Serial.println("client");
        // an http request ends with a blank line
        boolean current_line_is_blank = true;
        while (client.connected()) {

          if (client.available()) {

            char c = client.read();
            if (inString.length() < 50) {
            inString.concat(c);

            } 

            if (c == '\n' && current_line_is_blank) {
                char colorArr[5];
                String temp="";
                Serial.print("inString: ");
                Serial.println(inString);

                int Pos_r = inString.indexOf("r");
                int Pos_g = inString.indexOf("g");
                int Pos_b = inString.indexOf("b");
                int Pos_i = inString.indexOf("inc");
                int Pos_f = inString.indexOf("fad");
                int End = inString.indexOf("HTTP");
                Serial.print("Pos_r: ");
                Serial.println(Pos_r);
                Serial.print("Pos_g: ");
                Serial.println(Pos_g);
                Serial.print("Pos_b: ");
                Serial.println(Pos_b);
                Serial.print("Pos_i: ");
                Serial.println(Pos_i);
                Serial.print("Pos_f: ");
                Serial.println(Pos_f);
                Serial.print("End: ");
                Serial.println(End);

                if(Pos_r>=0){
                   temp=inString.substring((Pos_r+2), (Pos_g-1));
                   temp.toCharArray(colorArr, 5);
                   r=(atoi(colorArr));
                   Serial.print("red: ");
                   Serial.println(r);
                   EEPROM.write(1, r);
                }
                if(Pos_g>=0){
                   temp=inString.substring((Pos_g+2), (Pos_b-1));
                   temp.toCharArray(colorArr, 5);
                   g=(atoi(colorArr));
                   Serial.print("green: ");
                   Serial.println(g);
                   EEPROM.write(2, g);
                }         

                if(Pos_b>=0){
                   temp=inString.substring((Pos_b+2), (Pos_i-1));
                   temp.toCharArray(colorArr, 5);
                   b=(atoi(colorArr));
                   Serial.print("blue: ");
                   Serial.println(b);
                   EEPROM.write(3, b);
                }      

                if(Pos_i>=0){
                   temp=inString.substring((Pos_i+4), (Pos_f-1));
                   temp.toCharArray(colorArr, 5);
                   inc=(atoi(colorArr));
                   Serial.print("inc: ");
                   Serial.println(inc);
                   EEPROM.write(4, inc);
                } 

                if(Pos_f>=0){
                   temp=inString.substring((Pos_f+4), (End-1));
                   temp.toCharArray(colorArr, 5);
                   fader=(atoi(colorArr));
                   Serial.print("fader: ");
                   Serial.println(fader);
                   EEPROM.write(5, fader);
                }     

               if ((Pos_r>=0)&&(Pos_g>=0)&&(Pos_b>=0)) {
                 rgb(r,g,b);
               }
            printWebPage( &client);
            break;
            }
            if (c == '\n') {
            // we're starting a new line
            current_line_is_blank = true;
            } else if (c != '\r') {
            // we've gotten a character on the current line
            current_line_is_blank = false;
            }
          }
        }
        // give the web browser time to receive the data
        delay(1);

        inString = "";
        client.stop();
      }

}

void printWebPage(Client *client)
{
      int tmp=0;
      Serial.println("printWebPage");
      // send a standard http response header
      client->println("HTTP/1.1 200 OK");
      client->println("Content-Type: text/html");
      client->println();

      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0]))); // Necessary casts and dereferencing, just copy.
      client->println( buffer );
      //Serial.println( buffer );
      for (int i = 1; i < 51; i++)
      {
          /*if (i==9)
          {
              strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i])));  //butto tutto nell'array buffer
              for (tmp=0 ; tmp < sizeof(buffer); tmp++)
              {
                if (buffer[tmp]=='#')
                {
                  //Serial.println( "trovato ##### " ); 

                }

              }
          }
          else
          {
            strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
          }*/
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
          client->println( buffer );
          if (i==1)
          {
            client->print( r );client->print( "," );client->print( g );client->print( "," );client->print( b );
          }

          if (i==23){if (inc==1){client->print("selected");}}
          if (i==24){if (inc==5){client->print("selected");}}
          if (i==25){if (inc==10){client->print("selected");}}
          if (i==26){if (inc==25){client->print("selected");}}
          if (i==27){if (inc==50){client->print("selected");}}
          if (i==28){if (inc==100){client->print("selected");}}
          if (i==29){if (inc==150){client->print("selected");}}
          if (i==30){if (inc==200){client->print("selected");}}
          if (i==31){if (inc==250){client->print("selected");}}

          if (i==35)
          {
            if (fader==1){
              client->print("checked");
            }
          }
          if (i==36)
          {
            if (fader==0){
              client->print("checked");
            }
          }
//          switch(i){
//
//              case 1:
//                  //itoa (tempC, buffer, 10); client->print( buffer ); Serial.print( buffer ); client->print( "," ); Serial.print( "," ); itoa ((int(tempC * 100) % 100), buffer, 10); client->print( buffer ); Serial.print( buffer ); break;
//              case 2:
//                  //if(digitalRead(rele)) st4=41;
//                  //else st4=42;
//                  //strcpy_P(buffer, (char*)pgm_read_word(&(string_table[st4]))); client->println( buffer ); Serial.println( buffer ); break;
//              case 3:
//                  //strcpy_P(buffer, (char*)pgm_read_word(&(string_table[st6]))); client->println( buffer ); Serial.println( buffer ); break;
//              case 4:
//              case 5:
//              case 6:
//          }
          delay(30);
      }

}

void funcfader(){
    Serial.println("fader");
    if (rup==1){r+=1;}
    else{r-=1;}
    if (r>=255){rup=0;}
    if (r<=0){rup=1;}

    if (gup==1){g+=1;}
    else{g-=1;}
    if (g>=255){gup=0;}
    if (g<=0){gup=1;}

    if (bup==1){b+=1;}
    else{b-=1;}
    if (b>=255){bup=0;}
    if (b<=0){bup=1;}

    delay(inc*2);
    rgb(r, g, b);
}

void rgb(int r, int g, int b)
{

  Serial.print("RGB: ");
  Serial.print(r);
  Serial.print(" ");
  Serial.print(g);
  Serial.print(" ");
  Serial.print(b);
  if (r>255) r=255;
  if (g>255) g=255;
  if (b>255) b=255;
  if (r<0) r=0;
  if (g<0) g=0;
  if (b<0) b=0;

  analogWrite(red, r);
  analogWrite(green, g);
  analogWrite(blue, b);
}

 

 

 

The web page

We conclude seeing the commands and reports available on the web page, there are buttons to issue commands, the option radio to select mode and some boxes where you write parameters. We start from the top, where we find the seven buttons, each relating to a color: each of them set in the lamp the combination of the LEDs R, G and B to obtain the corresponding color; receiving the command Arduino sets its color. Below these buttons are three boxes, with the Calculate button to the right: from left to right, they represent the colors red, green and blue. In each box, you can write, with a number between 0 and 255, the intensity that we have employed the same light, for example, typing 255 in the middle box we illuminate at full intensity green light.
The value in each cell can be varied with the buttons below Red+ Green+ and Blue+ (which increases the light intensity, respectively, red, green and blue) or by Red- Green- and Blue- buttons that reduce the intensity. Clicking on the Calculate button, see what color will obtain, whereas with Set colors send a request for setting the color intensity corresponding to the combination of the three boxes.
The last section of the web page is that of the fader: it is the effect of color change continues, activated by clicking in the option box next to On the same name (Fader) to disable this function you must click Off. By activating the fader, we will see the light of the lamp shades change cyclically from the currently set color, you can also choose between multiple execution speed of the cycle, the drop down menu which is accessed by clicking the middle box inc/speed was above a Fader section.

To build the project

Open Electronics 20 Feb 14:15

Software and firmware for TiDiGino (GSM remote controller with Arduino)

A lot of people who bought the TiDiGino ask me how to test it.
The Gsm Remote Control is provided with bootloader, so you have to insert the prefered sketch that you can find in code.google.
Daniele Denaro wrote a good sketch for TiDiGino, and I’m reporting his tutorial.
Ask me (and him) all do you need.
Author Daniele Denaro

Be careful, because you have to manipulate the environment of development (IDE) 1.0 to insert the new hardware.
In particular replace the file “boards.txt” (see below).
In this new version of the file has been added to the section on hardware TiDiGino.
You should also add the folder “tidigino” that “boards.txt” references (see below).
The changes will be visible to restart the IDE.

Changes from previous version 1.0:

- It was introduced double message mode for alarms. Meaning now is also detected the return to the base level (end alarm) with the possibility to be notified by a second message.

- It is advisable to perform a reset procedure to be safe pressing both the switch P1 and P2 on the first start after installation.

- Fixed some errors in the Java program.

NB. If you have an unmodified hardware TiDiGino, should arrange removal 100-ohm resistor R20 (near the USB connector). Because otherwise…
TiDiGino remains constantly in reset and will not start unless it is also connected to the USB.
(As distinct from the opening of the JP2 jumper that only affects the transparency serial link to the functioning of the operating TiDiGino)

The download includes:
- Installation of this file
- A Italian handbook pdf: TiDiGinoMan.pdf
- A quick Italian reference guide to the controls and the installation and startup: TiDiGinoShort.pdf

- A folder “FirmwareTiDiGino” containing the firmware for TiDiGino;
“TiDiGinoMainV12.ino”: main sketch;
5 modules in the folder “modules”:
“Commands.c”: Commands and their management
“Phone.c” Management Procedures GSM
“Pins.c” Definitions of corresponding pins of the Arduino and global variables
“StateVariables.c” Variables to store the state of the controller and procedures for EEPROM
“Utility.c”: Various procedures used by other modules

- An executable jar file “TiDiGinoW32.jar” and “TiDiGinoW64.jar”
(Containing the Java application interface for Windows32 or Windows64)
(Just extract the files in a directory and appropriate “to click” above)

- A “Library” folder containing (for convenience) Arduino libraries used.
To be installed in the directory “libraries” of the Arduino software (if not already present)

- File “boards.txt” that replaces the same name in the “hardware\arduino”. This file has been added TiDiGino the platform that you will find it listed along with the other (after restarted the IDE). This file is pointing to the directory “Tidigino” of “variants”

- The folder “tdigino” that contains the file “pins_arduino.h” which realizes the map particular hardware of TiDiGino. This folder should be added to other in the templates folder (the folder “hardware\arduino\variants” of the environment Arduino 1.0)

N.B.
To load the sketch of TiDiGino must first edit the path of inclusion forms.
In fact we used the absolute path to solve the problems with the Arduino compiler.
The inclusion of modules is obviously “TiDiGinoMain.ino”.
The easiest thing is to create a folder in the workspace Arduino “TiDiGinoMain”, copy the file “TiDiGinoMain” and the Forms folder, then edit the file, changing paths, and finally activate the upload.
Attention! At the first start after the upload, press P1 and P2 to reset and load the default values ​​to EEPROM.

N.B.
The application interface is in Java (and so you must have Java installed) but it is only for WINDOWS environment because of the library bill for the management of the serial port.
(If the jar was not associated with java you can run it from the console window command “java-jar TiDiGinoWxx.jar”, or creating a link using “javaw-jar TidiGinoWxx.jar”)
Keep in mind that every time you open the serial port you have a firmware restart unless you open jumper JP2 (near the USB connector) that prevents the software reset of Arduino.

N.B.
The software is “open source” and therefore disclaims any liability arising from its use.