Difference between revisions of "Arduino and the mechanical relay"
(Started explaining the code) |
m |
||
(7 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | So you bought an arduino and then you got one of those cheap relay boards and you decided to try to do blinky flashy with them. First, it is not a great idea but assuming you want to try it, here you go! | ||
+ | |||
+ | == Second, here's the program code -- comments follow later! == | ||
+ | |||
<nowiki> | <nowiki> | ||
− | // *** diychristmas.org free software so long as this line remains in sketch! | + | // *** diychristmas.org free software so long as this line remains in sketch! |
− | // Vixen | + | // Basically Vixen "generic" serial mechanical relay sketch |
+ | // - Setup a generic serial controller to use this sketch | ||
// - Uses digitalWrite as this outputs LOW or HIGH no pwm values | // - Uses digitalWrite as this outputs LOW or HIGH no pwm values | ||
// - This is what is needed for a mechanical relay | // - This is what is needed for a mechanical relay | ||
Line 11: | Line 16: | ||
// Vixen information | // Vixen information | ||
− | + | // speed for the com port for talking with player | |
− | |||
− | // speed for the com port for talking with | ||
const long SERIAL_COM_SPEED = 115200L; | const long SERIAL_COM_SPEED = 115200L; | ||
// Generic Serial controller config - must be present, must match controller setup | // Generic Serial controller config - must be present, must match controller setup | ||
− | const int | + | const int CONTROLLER_HEADER[3] = {33, 34, 35}; // This is character !"# (hard to replicate in sequencer) |
+ | |||
// Relays | // Relays | ||
// - most mechanical relays turn on when pin is low, off on high | // - most mechanical relays turn on when pin is low, off on high | ||
Line 23: | Line 27: | ||
// these are program variables we need to use in multiple places | // these are program variables we need to use in multiple places | ||
− | const int SIZE_OF_HEADER = sizeof( | + | const int SIZE_OF_HEADER = sizeof(CONTROLLER_HEADER) / sizeof(int); // no need to change |
+ | const int CHANNEL_COUNT = sizeof(channels) / sizeof(int); // no need to change | ||
int buffer[CHANNEL_COUNT]; // no need to change going to hold relay output values | int buffer[CHANNEL_COUNT]; // no need to change going to hold relay output values | ||
Line 29: | Line 34: | ||
{ | { | ||
Serial.begin(SERIAL_COM_SPEED); | Serial.begin(SERIAL_COM_SPEED); | ||
− | |||
// set the channel pins to output mode | // set the channel pins to output mode | ||
Line 42: | Line 46: | ||
void loop() | void loop() | ||
{ | { | ||
− | + | waitForControllerHeader(CONTROLLER_HEADER); | |
− | + | readSequenceData(); | |
outputToLights(); | outputToLights(); | ||
} | } | ||
Line 70: | Line 74: | ||
} | } | ||
− | void | + | void readSequenceData() |
{ | { | ||
char buffer2[CHANNEL_COUNT]; | char buffer2[CHANNEL_COUNT]; | ||
Line 84: | Line 88: | ||
} | } | ||
− | void | + | void waitForControllerHeader(int header[]) |
{ | { | ||
for (int i = 0; i < SIZE_OF_HEADER; i++) { | for (int i = 0; i < SIZE_OF_HEADER; i++) { | ||
// wait for serial available | // wait for serial available | ||
while (!Serial.available()) {} | while (!Serial.available()) {} | ||
− | // Check the byte until it matches the | + | // Check the byte until it matches the CONTROLLER_HEADER byte |
int inByte = Serial.read(); | int inByte = Serial.read(); | ||
− | if (inByte != | + | if (inByte != CONTROLLER_HEADER[i]) { |
i = -1; // wrong data set to "zero" | i = -1; // wrong data set to "zero" | ||
} | } | ||
Line 116: | Line 120: | ||
turnLightsOff(); | turnLightsOff(); | ||
} | } | ||
+ | |||
</nowiki> | </nowiki> | ||
Let's talk about the code... | Let's talk about the code... | ||
− | At the top of the sketch, you will find the definitions of how you are going to use the Arduino with Vixen | + | At the top of the sketch, you will find the definitions of how you are going to use the Arduino with Vixen or any other serial output. These things are self explanatory but for the "I've never seen an Arduino or Vixen setup" people, here is another try to explain them. |
== Things you might have to change == | == Things you might have to change == | ||
Line 125: | Line 130: | ||
int channels[] = {2, 3, 4, 5, 6, 7, 8, 10}; | int channels[] = {2, 3, 4, 5, 6, 7, 8, 10}; | ||
− | This line assigns pins from the arduino to specific "channels" | + | This line assigns pins from the arduino to specific "channels". The order of definition is the order the pins will be turned on or off. In your software, you would assign channel one to Shrub1, channel two to Shrub2, etc. This is done in the element to controller mapping in Vixen. You will need to map these through the Arduino pins to the specific relay on your relay board and out to the lights. |
It might look like this: | It might look like this: | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 176: | Line 181: | ||
− | const | + | const long SERIAL_COM_SPEED = 115200L; |
− | + | This sets the communication speed back to the player. This will have to match the controller setup in your player. 115,200 baud is equivalent to 115,200 bps which translates to: | |
− | const int | + | 115,200 / 8 bits of data plus 2 bits of overhead = 11,520 bytes per second |
+ | 11,520 bytes / 20 fps (50 ms) = 576 bytes per frame | ||
+ | |||
+ | This is way more than enough for this setup but this becomes more important when we start doing pixels. So, we might as well use the faster speed. | ||
+ | |||
+ | const int CONTROLLER_HEADER[3] = {33, 34, 35}; | ||
+ | This is how we find the beginning of a packet. This is also set in the controller setup in the player. The player will send these bytes before sending the data bytes. We define them in integer so consult an ASCII chart to find the appropriate values. Using three values and using values that are one digit apart will make it hard to accidentally send these values. The reason we do this is because the communication stream could be interrupted and this will re-sync the stream. This also means that if something is wrong with your lights, you can fix it, turn the power back on and it will find which lights to turn on in order. | ||
+ | |||
const int ON = LOW; | const int ON = LOW; | ||
const int OFF = HIGH; | const int OFF = HIGH; | ||
+ | Most mechanical relays turn on when we send off (LOW or x'00'). If your relays are off when they should be on (and on when they should be off), then you will need to flip the LOW and HIGH. | ||
+ | |||
+ | Everything else in this sketch should just work with generic serial controller. As of June, 2018, this limits you to Vixen 2 or Vixen 3. If you need a Renard sketch, see [[Arduino and the mechanical relay using Renard]]. |
Latest revision as of 19:51, 3 August 2018
So you bought an arduino and then you got one of those cheap relay boards and you decided to try to do blinky flashy with them. First, it is not a great idea but assuming you want to try it, here you go!
Second, here's the program code -- comments follow later!
// *** diychristmas.org free software so long as this line remains in sketch! // Basically Vixen "generic" serial mechanical relay sketch // - Setup a generic serial controller to use this sketch // - Uses digitalWrite as this outputs LOW or HIGH no pwm values // - This is what is needed for a mechanical relay // Hookup the relay in order of channel definition // Define as many as you need // put channels (pins) in an array so we can use looping structures to control int channels[] = {2, 3, 4, 5, 6, 7, 8, 10}; // Vixen information // speed for the com port for talking with player const long SERIAL_COM_SPEED = 115200L; // Generic Serial controller config - must be present, must match controller setup const int CONTROLLER_HEADER[3] = {33, 34, 35}; // This is character !"# (hard to replicate in sequencer) // Relays // - most mechanical relays turn on when pin is low, off on high const int ON = LOW; const int OFF = HIGH; // these are program variables we need to use in multiple places const int SIZE_OF_HEADER = sizeof(CONTROLLER_HEADER) / sizeof(int); // no need to change const int CHANNEL_COUNT = sizeof(channels) / sizeof(int); // no need to change int buffer[CHANNEL_COUNT]; // no need to change going to hold relay output values void setup() { Serial.begin(SERIAL_COM_SPEED); // set the channel pins to output mode for (int channelIndex = 0; channelIndex < CHANNEL_COUNT; channelIndex++) { pinMode(channels[channelIndex], OUTPUT); } turnLightsOff(); powerOnSelfTest(); // watch your lights to make sure they are all going on in order } void loop() { waitForControllerHeader(CONTROLLER_HEADER); readSequenceData(); outputToLights(); } void turnLightsOff() { //turn them all off for (int channelIndex = 0; channelIndex < CHANNEL_COUNT; channelIndex++) { digitalWrite(channels[channelIndex], OFF); } } void outputToLights() { for (int channelIndex = 0; channelIndex < CHANNEL_COUNT; channelIndex++) { // we should only be seeing 255 and 0 but in case someone tried a fade // 48 is used for debug purposes. You can use the serial monitor to test // send this string !"#01010101 to turn on every other relay as 0 == dec(48) 1 == dec(49) if (buffer[channelIndex] > 48) { digitalWrite(channels[channelIndex], ON); } else { digitalWrite(channels[channelIndex], OFF); } } } void readSequenceData() { char buffer2[CHANNEL_COUNT]; int index = 0; while (Serial.available() < CHANNEL_COUNT) {} // We have enough data! for (int i = 0; i < CHANNEL_COUNT; i++) { int inByte = Serial.read(); buffer[i] = inByte; Serial.write(inByte); } } void waitForControllerHeader(int header[]) { for (int i = 0; i < SIZE_OF_HEADER; i++) { // wait for serial available while (!Serial.available()) {} // Check the byte until it matches the CONTROLLER_HEADER byte int inByte = Serial.read(); if (inByte != CONTROLLER_HEADER[i]) { i = -1; // wrong data set to "zero" } } // found the header! } // powerOnSelfTest - does a couple of checks to make sure everything turns on and off // - watch your lights, they should go on in order void powerOnSelfTest() { // This routines turns on and off each relay in order for (int channelIndex = 0; channelIndex < CHANNEL_COUNT; channelIndex++) { digitalWrite(channels[channelIndex], ON); // turn on one channel at a time delay(2000); digitalWrite(channels[channelIndex], OFF); } // This routines turns on each relay in order leaving them all on for .5 seconds for (int channelIndex = 0; channelIndex < CHANNEL_COUNT; channelIndex++) { digitalWrite(channels[channelIndex], ON); // all on test delay(500); // wait .5 seconds } delay(2000); // slight pause to check all on turnLightsOff(); }
Let's talk about the code... At the top of the sketch, you will find the definitions of how you are going to use the Arduino with Vixen or any other serial output. These things are self explanatory but for the "I've never seen an Arduino or Vixen setup" people, here is another try to explain them.
Things you might have to change
int channels[] = {2, 3, 4, 5, 6, 7, 8, 10};
This line assigns pins from the arduino to specific "channels". The order of definition is the order the pins will be turned on or off. In your software, you would assign channel one to Shrub1, channel two to Shrub2, etc. This is done in the element to controller mapping in Vixen. You will need to map these through the Arduino pins to the specific relay on your relay board and out to the lights. It might look like this:
Description | Channel | Pin | Relay |
---|---|---|---|
Shrub1Left | 1 | 2 | In1 |
Shrub2 | 2 | 3 | In2 |
Shrub3 | 3 | 4 | In3 |
Shrub4Right | 4 | 5 | In4 |
Post1Left | 5 | 6 | In5 |
Post2 | 6 | 7 | In6 |
Post3 | 7 | 8 | In7 |
Post4Right | 8 | 10 | In8 |
const long SERIAL_COM_SPEED = 115200L;
This sets the communication speed back to the player. This will have to match the controller setup in your player. 115,200 baud is equivalent to 115,200 bps which translates to:
115,200 / 8 bits of data plus 2 bits of overhead = 11,520 bytes per second
11,520 bytes / 20 fps (50 ms) = 576 bytes per frame
This is way more than enough for this setup but this becomes more important when we start doing pixels. So, we might as well use the faster speed.
const int CONTROLLER_HEADER[3] = {33, 34, 35}; This is how we find the beginning of a packet. This is also set in the controller setup in the player. The player will send these bytes before sending the data bytes. We define them in integer so consult an ASCII chart to find the appropriate values. Using three values and using values that are one digit apart will make it hard to accidentally send these values. The reason we do this is because the communication stream could be interrupted and this will re-sync the stream. This also means that if something is wrong with your lights, you can fix it, turn the power back on and it will find which lights to turn on in order.
const int ON = LOW; const int OFF = HIGH; Most mechanical relays turn on when we send off (LOW or x'00'). If your relays are off when they should be on (and on when they should be off), then you will need to flip the LOW and HIGH.
Everything else in this sketch should just work with generic serial controller. As of June, 2018, this limits you to Vixen 2 or Vixen 3. If you need a Renard sketch, see Arduino and the mechanical relay using Renard.