Open Toby66 opened 4 years ago
It is always a good idea to reduce the amount of resources. :-) But the "waste" can be very little. The overhead between one 200 byte universe compared to two 100 byte universes is not much. But with one universe you will get only one call to the callback, that's a timing bonus. If you had shared your code snippet, it would be much easier to help you. I would guess something like this:
if (universe == 1) {
strip1.update(data);
}
if (universe == 2) {
strip2.update(data);
}
if (universe == 3) {
stepper.setPos(data);
}
Doing it all in one universe is as simple as:
if (universe == 0) {
strip1.update(&data[0]);
strip2.update(&data[200]);
stepper.setPos(&data[201]);
}
Note: This is more pseudo code than copy/paste-ready!
I have a Similar Question.
I am Planning on Having Multiple ESP32 Each with a String on LEDS attached to Create Free standing light poles.
My question is how do I offest the Start address for each string of lights.
my setup is 30 RGB Lights per ESP32, Which is 90 Channels using this code
#include <WiFi.h>
#include <WiFiUdp.h>
#include <ArtnetWifi.h>
#include <FastLED.h>
//Wifi settings - be sure to replace these with the WiFi network that your computer is connected to
const char* ssid = "SSID";
const char* password = "pAsSwOrD";
// LED Strip
const int numLeds = 30 // Change if your setup has more or less LED's
const int numberOfChannels = numLeds * 3; // Total number of DMX channels you want to receive (1 led = 3 channels)
#define DATA_PIN 12 //The data pin that the WS2812 strips are connected to.
CRGB leds[numLeds];
// Artnet settings
ArtnetWifi artnet;
const int startUniverse = 0;
bool sendFrame = 1;
int previousDataLength = 0;
// connect to wifi – returns true if successful or false if not
boolean ConnectWifi(void)
{
boolean state = true;
int i = 0;
WiFi.begin(ssid, password);
Serial.println("");
Serial.println("Connecting to WiFi");
// Wait for connection
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (i > 20){
state = false;
break;
}
i++;
}
if (state){
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("");
Serial.println("Connection failed.");
}
return state;
}
void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
{
sendFrame = 1;
// set brightness of the whole strip
if (universe == 15)
{
FastLED.setBrightness(data[0]);
}
// read universe and put into the right part of the display buffer
for (int i = 0; i < length / 3; i++)
{
int led = i + (universe - startUniverse) * (previousDataLength / 3);
if (led < numLeds)
{
leds[led] = CRGB(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);
}
}
previousDataLength = length;
FastLED.show();
}
void setup()
{
Serial.begin(115200);
ConnectWifi();
artnet.begin();
FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, numLeds);
// onDmxFrame will execute every time a packet is received by the ESP32
artnet.setArtDmxCallback(onDmxFrame);
}
void loop()
{
// we call the read function inside the loop
artnet.read();
}
How would i do this?
@chaosdesignnz There are many ways to do the splitting. Just a selection:
For a "reasonable" scaling option, the DHCP-based solution is the best one. There is only one firmware for all nodes, but you have to control the DHCP-server inside the network. All ESP-Nodes need a IP-address anyway. So use addresses from, lets say 192.x.x.100 to .110 for 11-nodes. The starting address doesn't matter, but you have to know it, and the addresses must be in a row.
uint8_t my_id = 0;
static const uint8_t offset = 100;
void setup() {
uint32 local_ip = WiFi.localIP();
my_id = (local_ip & 0xFF) - offset;
// maybe error-checking ??
}
...
void onDmxFrame(...) {
uint16_t index = my_id * 90;
// handle overflow !!
}
Note: Pseudo code!!
Don't like any of the above options? Let me know.
Hallo rstephan,
thanks for your great Project. Im still new in the micro controller programming, so sorry if im dont understand everything. My Project ist to create a device with Stepper and Led im using your Project and AccelStepper including WebServer on a ESP8266. The Plan for my project is to use Web based settings option with the all parameters. There for im looking for a option to set DMX start Channel for the device.
Can you give me a hint ?
Best Regard from Hannover
Hey all, rstephan thanks for your help on this unfortunately the project got postponed and I didn't make much process on the code, hopefully the project starts up again this year though!
However, on the off chance this helps anyone browsing I've included the code (at the end) which sends different universe to different pins and includes AccelStepper (just random positions).
Andreas you may be able to use this as a base and control the steper position with a DMX address as per the reccomendation on the second post;
if (universe == 3) {
stepper.setPos(data);
or setting chanels from one universe
if (universe == 0) { //SET UNIVERSE NUMBER
strip1.update(&data[0]); //SET [START CHANNEL]
strip2.update(&data[100]);
stepper.setPos(&data[201]);
}
Compiled Code:
//********************************STEPPER DEFINE******************************** #include <Stepper.h> const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution // Define a stepper and the pins it will use Stepper myStepper(stepsPerRevolution, 15, 2, 0, 4); //********************************ARTNET DEFINE******************************** #include <ArtnetWifi.h> #include <Arduino.h> #include <FastLED.h> // Wifi settings const char* ssid = "SSID"; const char* password = "pAsSwOrD"; // FASTLED settings //LED Strip 01 const int numLeds1 = 128; // CHANGE FOR YOUR SETUP const int numberOfChannels1 = numLeds1 * 3; // Total number of channels you want to receive (1 led = 3 channels) const byte dataPin1 = 12; CRGB leds1[numLeds1]; //LED Strip 02 const int numLeds2 = 128; // CHANGE FOR YOUR SETUP const int numberOfChannels2 = numLeds2 * 3; // Total number of channels you want to receive (1 led = 3 channels) const byte dataPin2 = 14; CRGB leds2[numLeds2]; //Total Number of Channels const int numberOfChannelsTot = numberOfChannels1 + numberOfChannels2; // Art-Net settings ArtnetWifi artnet; const int startUniverse = 1; // CHANGE FOR YOUR SETUP most software this is 1, some software send out artnet first universe as 0. // Check if we got all universes const int maxUniverses = numberOfChannelsTot / 512 + ((numberOfChannelsTot % 512) ? 1 : 0); bool universesReceived[maxUniverses]; bool sendFrame = 1; int previousDataLength = 0; // connect to wifi – returns true if successful or false if not boolean ConnectWifi(void) { boolean state = true; int i = 0; WiFi.begin(ssid, password); Serial.println("Connecting to WiFi"); // Wait for connection Serial.print("Connecting"); while (WiFi.status() != WL_CONNECTED) { delay(random(250, 1000)); Serial.print("..."); if (i > 0) { state = false; break; } i++; } if (state) { Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } else { Serial.println("Connection failed."); ConnectWifi(); } return state; } //RGB Light Test //LED 01 void initTest1() { for (int i = 0 ; i < numLeds1 ; i++) { leds1[i] = CRGB(127, 0, 0); } FastLED.show(); delay(500); for (int i = 0 ; i < numLeds1 ; i++) { leds1[i] = CRGB(0, 127, 0); } FastLED.show(); delay(500); for (int i = 0 ; i < numLeds1 ; i++) { leds1[i] = CRGB(0, 0, 127); } FastLED.show(); delay(500); for (int i = 0 ; i < numLeds1 ; i++) { leds1[i] = CRGB(0, 0, 0); } FastLED.show(); delay(500); } //LED 02 void initTest2() { for (int b = 0 ; b < numLeds2 ; b++) { leds2[b] = CRGB(127, 0, 0); } FastLED.show(); delay(500); for (int b = 0 ; b < numLeds2 ; b++) { leds2[b] = CRGB(0, 127, 0); } FastLED.show(); delay(500); for (int b = 0 ; b < numLeds2 ; b++) { leds2[b] = CRGB(0, 0, 127); } FastLED.show(); delay(500); for (int b = 0 ; b < numLeds2 ; b++) { leds2[b] = CRGB(0, 0, 0); } FastLED.show(); } //DMX Set Up void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data) { sendFrame = 1; // set brightness of the whole strip if (universe == 15) { FastLED.setBrightness(data[0]); FastLED.show(); } // Store which universe has got in if ((universe - startUniverse) < maxUniverses) { universesReceived[universe - startUniverse] = 1; } for (int i = 0 ; i < maxUniverses ; i++) { if (universesReceived[i] == 0) { //Serial.println("Broke"); sendFrame = 0; break; } } // read universe and put into the right part of the display buffer if (universe == 1) { for (int i = 0; i < length / 3; i++) { int led = i; if (led < numLeds1) leds1[led] = CRGB(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]); } } if (universe == 2) { for (int i = 0; i < length / 3; i++) { int led = i; if (led < numLeds1) leds2[led] = CRGB(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]); } } previousDataLength = length; if (sendFrame) { FastLED.show(); // Reset universeReceived to 0 memset(universesReceived, 0, maxUniverses); } } void setup() { //********************************STEPPER SET UP******************************** myStepper.setSpeed(15); //********************************ARTNET SET UP******************************** Serial.begin(115200); ConnectWifi(); artnet.begin(); FastLED.addLeds<WS2812, dataPin1, GRB>(leds1, numLeds1); FastLED.addLeds<WS2812, dataPin2, GRB>(leds2, numLeds2); initTest1(); initTest2(); // this will be called for each packet received artnet.setArtDmxCallback(onDmxFrame); } void loop() { // we call the read function inside the loop artnet.read(); myStepper.step(random(0, 2048)); }
Thanks Toby66 for your Help,
im still not sure how to implement this part in my Code:
if (universe == 0) { //SET UNIVERSE NUMBER
strip1.update(&data[0]); //SET [START CHANNEL]
strip2.update(&data[100]);
stepper.setPos(&data[201]);
}
Im know what the Code mean but not how to insert this. I've done it bit other way, im not Sure if its the right way. I'm still learning, but for the moment it Works. Im still looking for Optimization.
#include <ESP8266WiFi.h>
#include <ArtnetWifi.h>
#include <Arduino.h>
#include <FastLED.h>
#include <AccelStepper.h>
//Stepper
#define STEPPER1_DIR_PIN D4
#define STEPPER1_STEP_PIN D3
//#define STEPPER1_EN_PIN D2
AccelStepper stepper(AccelStepper::DRIVER, STEPPER1_STEP_PIN, STEPPER1_DIR_PIN);
int curpos = stepper.currentPosition();
int prevpos = 0;
int chan = 1;
int led_start = chan + 1;
// WiFi stuff
const char* ssid = "FRITZ!Box 7490";
const char* password = "123456789";
// LED settings
const int numLeds = 5; // CHANGE FOR YOUR SETUP
const int numberOfChannels = numLeds * 3; // Total number of channels you want to receive (1 led = 3 channels)
const byte dataPin = 2;
CRGB leds[numLeds];
// Art-Net settings
ArtnetWifi artnet;
WiFiUDP UdpSend;
const int startUniverse = 0; // CHANGE FOR YOUR SETUP most software this is 1, some software send out artnet first universe as 0.
// Check if we got all universes
const int maxUniverses = numberOfChannels / 512 + ((numberOfChannels % 512) ? 1 : 0);
bool universesReceived[maxUniverses];
bool sendFrame = 1;
int previousDataLength = 0;
// connect to wifi – returns true if successful or false if not
boolean ConnectWifi(void)
{
boolean state = true;
int i = 0;
WiFi.begin(ssid, password);
Serial.println("");
Serial.println("Connecting to WiFi");
// Wait for connection
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (i > 20){
state = false;
break;
}
i++;
}
if (state){
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("");
Serial.println("Connection failed.");
}
return state;
}
void initTest()
{
for (int i = 0 ; i < numLeds ; i++) {
leds[i] = CRGB(127, 0, 0);
}
FastLED.show();
delay(500);
for (int i = 0 ; i < numLeds ; i++) {
leds[i] = CRGB(0, 127, 0);
}
FastLED.show();
delay(500);
for (int i = 0 ; i < numLeds ; i++) {
leds[i] = CRGB(0, 0, 127);
}
FastLED.show();
delay(500);
for (int i = 0 ; i < numLeds ; i++) {
leds[i] = CRGB(0, 0, 0);
}
FastLED.show();
}
void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
{
sendFrame = 1;
if ((universe - startUniverse) < maxUniverses)
{
universesReceived[universe - startUniverse] = 1;
}
for (int i = 0 ; i < maxUniverses ; i++)
{
if (universesReceived[i] == 0)
{
//Serial.println("Broke");
sendFrame = 0;
break;
}
}
// read universe and put into the right part of the display buffer
for (int i = 0; i < length / 3; i++)
{
int led = i + (universe - startUniverse) * (previousDataLength / 3);
if (led < numLeds)
leds[led] = CRGB(data[i * 3 + led_start], data[i * 3 + 1 + led_start], data[i * 3 + 2 + led_start]);
}
previousDataLength = length;
// get 16Bit Data for Stepper part
for (int i = 0 ; i < chan ; i++)
{
int long newval = 0;
newval = map(data[i], 0, 255, 0, 512);
char hi = data[i];
char lo = data[i + 1];
int StepperPos = hi << 8 | lo;
Serial.print("data: ");
Serial.println(StepperPos, HEX);
stepper.moveTo(StepperPos);
}
if (sendFrame)
{
FastLED.show();
// Reset universeReceived to 0
memset(universesReceived, 0, maxUniverses);
}
}
void setup()
{
Serial.begin(115200);
ConnectWifi();
artnet.begin();
FastLED.addLeds<WS2812, dataPin, GRB>(leds, numLeds);
initTest();
// this will be called for each packet received
artnet.setArtDmxCallback(onDmxFrame);
// set Current Position to 0
stepper.setCurrentPosition(0);
} //End Setup
void loop(){
// we call the read function inside the loop
artnet.read();
//Stepper stuff
stepper.setMaxSpeed(13000);
stepper.setSpeed(9000);
stepper.setAcceleration(6500);
stepper.runSpeedToPosition();
}
As next is the Webserver with Filesystem todo.
Best Regards Andreas
@ all Don't put WiFi credentials into the posts ;-)
@andreas-git How to set the start-address? If you are using the Web-interface, than put in a textbox and a button and set a variable inside the code. How to do this? I don't know. Look for examples included in the Web-server framework. Also look for an option to store the setting (EEPROM?) so it will "remember" the setting after a reset.
For your code-example a hint:
void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
{
if (universe == 0) { //SET UNIVERSE NUMBER
//strip1.update(&data[0]); //SET [START CHANNEL]
//strip2.update(&data[100]);
//stepper.setPos(&data[201]);
// NOTE: 100 LEDs (300 channels) !!!!
for (int led = 0; led < 100; led++) {
int pos = (i * 3) + channelStart;
leds[led] = CRGB(data[pos + 0], data[pos + 1], data[pos + 2]);
}
FastLED.show();
// whatever to do with the stepper motor ...
}
}
Note: As always, pseudo code !! Don't copy-paste!
Maybe my strip1.update()
wasn't the best for the example. There is no update()
in Adafruit Neopixel or FastLED. You have to loop over the data and put it, with the right color-conversion, into the LED buffer.
Thanks for reply @rstephan,
@ all Don't put WiFi credentials into the posts ;-)
Thanks for advise, thats already pseudo credentials. :-)
How to set the start-address? If you are using the Web-interface, than put in a textbox and a button and set a variable inside the code. How to do this? I don't know. Look for examples included in the Web-server framework. Also look for an option to store the setting (EEPROM?) so it will "remember" the setting after a reset.
Yes, that was my idea using variables for set the needed parameters thrue WebServer and store it on Filesystem. But im still not sure im my Copy Pasted code is ok, still looking optimization. Or is the Code ok ?
if (universe == 0) { //SET UNIVERSE NUMBER
//strip1.update(&data[0]); //SET [START CHANNEL]
//strip2.update(&data[100]);
//stepper.setPos(&data[201]);
Its looks what ive done already in my Code, but not so nice like you advise.
leds[led] = CRGB(data[i * 3 + led_start], data[i * 3 + 1 + led_start], data[i * 3 + 2 + led_start]);
Im still not sure how do that at the moment, im still beginner.
@andreas-git The code-snippets I write are not tested! So expect it that they don't compile properly (misspelled variable or forgotten bracket, ...). These snippets don't have to work. They should give you a direction where to go.
Don't copy-past "blind" and start crying if it is not work or it don't solve your exact problem!
But sure, use it as a start, maybe you are lucky.
The part:
//strip1.update(...)
//..
is just a comment to give you an orientation where to put the code. The for
-loop is the important part and the fact
to remove the universesReceived
stuff.
I've been using this for a while now and it has been super helpful. Currently, I'm using a collection of ESP32s to control both LED's and stepper motors via ArtNet, splitting the information over different universes as set out in #9 .
However, I'm scaling up the project and it seems wasteful to use two universes per ESP32 when all the information could fit within one universe.
What would be the best way to be able to split a universes' channels into multiple outputs?
I.E:
Cheers!