diff --git a/src/ShapeDisplayManagers/InFormIOManager.cpp b/src/ShapeDisplayManagers/InFormIOManager.cpp index 6a99a07..08505bf 100644 --- a/src/ShapeDisplayManagers/InFormIOManager.cpp +++ b/src/ShapeDisplayManagers/InFormIOManager.cpp @@ -23,8 +23,9 @@ InFormIOManager::InFormIOManager() { // Size the 2d heights array appropriately for the specific shape display hardware, and initialize it with zero values. // This needs to happen in the subclass constructor because the superclass constructor fires first, and won't yet have the subclass specific constants. heightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); - // Also size the array that receives height values from the shape display. + // Also size the array that receives height values from the shape display, and the "previous" heights heightsFromShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); + previousHeightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); pinHeightMin = 50; pinHeightMax = 210; diff --git a/src/ShapeDisplayManagers/InFormIOManager.hpp b/src/ShapeDisplayManagers/InFormIOManager.hpp index 452956b..d4198cd 100644 --- a/src/ShapeDisplayManagers/InFormIOManager.hpp +++ b/src/ShapeDisplayManagers/InFormIOManager.hpp @@ -31,6 +31,8 @@ class InFormIOManager : public SerialShapeIOManager { vector getDisabledPins() { return {}; } + + double getMaxPowerLoad() {return 0.5;} // should pins that appear stuck be turned off at regular intervals? bool enableStuckPinSafetyToggle = false; diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index e578b4f..b8f0992 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -7,6 +7,7 @@ #include "SerialShapeIOManager.hpp" #include "constants.h" +#include "utils.hpp" //-------------------------------------------------------------- // @@ -213,6 +214,29 @@ void SerialShapeIOManager::clipAllHeightValuesToBeWithinRange() { } } +// Limit all values, to reduce the maximum transient power draw +void SerialShapeIOManager::limitPowerDraw() { + double totalCost = 0; + for(int i = 0; i < shapeDisplaySizeX; i++) { + for(int j = 0; j < shapeDisplaySizeY; j++) { + double pinDiff = heightsForShapeDisplay[i][j] - (float)previousHeightsForShapeDisplay[i][j]; + pinDiff /= pinHeightMax - pinHeightMin; // 1 for min -> max, 0 for h -> h, -1 for max -> min + totalCost += abs(pinDiff); + } + } + + if (totalCost > shapeDisplaySizeX * shapeDisplaySizeY * getMaxPowerLoad()) { + double scaleRatio = (shapeDisplaySizeX * shapeDisplaySizeY *getMaxPowerLoad())/totalCost; + for(int i = 0; i < shapeDisplaySizeX; i++) { + for(int j = 0; j < shapeDisplaySizeY; j++) { + heightsForShapeDisplay[i][j] = previousHeightsForShapeDisplay[i][j] + (heightsForShapeDisplay[i][j] - (int)previousHeightsForShapeDisplay[i][j]) * scaleRatio; + } + } + } + + previousHeightsForShapeDisplay = heightsForShapeDisplay; +} + // Copy data from storage in the 2D array to the corresponding arduino board // structures. Flip height values where needed to match the board's orientation. void SerialShapeIOManager::readyDataForArduinos() { @@ -266,6 +290,7 @@ void SerialShapeIOManager::update() { // prepare height data for sending to shape display clipAllHeightValuesToBeWithinRange(); + limitPowerDraw(); readyDataForArduinos(); // send height data. if the display talks back, ask it what it's doing diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index baae801..3db3dad 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -127,6 +127,14 @@ class SerialShapeIOManager { // shape display height values (both intended and actual values) std::vector> heightsForShapeDisplay; std::vector> heightsFromShapeDisplay; + // make sure to resize is child constructor + std::vector> previousHeightsForShapeDisplay; + + // [0, 1] range, the maximum power draw alowable + virtual double getMaxPowerLoad() {return 1.0;} + + // prevent over-draw current + void limitPowerDraw(); // pin behavior configurations std::vector> pinConfigsForShapeDisplay; diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index ec8140e..41b1e4e 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -6,6 +6,7 @@ // #include "TransformIOManager.hpp" +#include "SerialShapeIOManager.hpp" // Create new transformIOManager instance, setting up transFORM-specific board // configuration @@ -23,8 +24,9 @@ TransformIOManager::TransformIOManager() { // Size the 2d heights array appropriately for the specific shape display hardware, and initialize it with zero values. // This needs to happen in the subclass constructor because the superclass constructor fires first, and won't yet have the subclass specific constants. heightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); - // Also size the array that receives height values from the shape display. + // Also size the array that receives height values from the shape display, and the "previous" heights heightsFromShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); + previousHeightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); pinHeightMin = 50; pinHeightMax = 210; diff --git a/src/Utils/utils.cpp b/src/Utils/utils.cpp index 738479b..0e75e4e 100644 --- a/src/Utils/utils.cpp +++ b/src/Utils/utils.cpp @@ -11,3 +11,39 @@ double elapsedTimeInSeconds() { return clock() / (double) CLOCKS_PER_SEC; } +//ofImage applyFunctionToPixels(const ofImage& first, const ofImage& second, pixelFunction fn) { +// ofImage out = ofImage(first); +// +// ofPixels& outPixels = out.getPixels(); +// const ofPixels& secondPixels = second.getPixels(); +// +// // weighted average of pixel +// for (int i = 0; i < outPixels.size(); i++) { +// outPixels[i] = fn(outPixels[i], secondPixels[i]); +// } +// +// out.update(); +// return out; +// +//} +// +//ofImage absoluteDifference(const ofImage& first, const ofImage& second) { +// return applyFunctionToPixels(first, second, [](unsigned char a, unsigned char b){return (unsigned char)abs(a - int(b));}); +//} +// +//ofImage weightedAverage(const ofImage& first, const ofImage& second, double weight) { +// ofImage out = ofImage(first); +// weight = std::clamp(weight, 0.0, 1.0); +// +// ofPixels& outPixels = out.getPixels(); +// const ofPixels& secondPixels = second.getPixels(); +// +// // weighted average of pixel +// for (int i = 0; i < outPixels.size(); i++) { +// outPixels[i] = (1.0 - weight) * outPixels[i] + weight * secondPixels[i]; +// } +// +// out.update(); +// return out; +//} + diff --git a/src/Utils/utils.hpp b/src/Utils/utils.hpp index a331a2a..aff0ef2 100644 --- a/src/Utils/utils.hpp +++ b/src/Utils/utils.hpp @@ -14,5 +14,12 @@ double elapsedTimeInSeconds(); +typedef unsigned char (*pixelFunction) (unsigned char, unsigned char); +//ofImage applyFunctionToPixels(const ofImage& first, const ofImage& second, pixelFunction function); +//// weight * second + (1 - weight) * first ----- with [0, 1] bounds on weight +//ofImage weightedAverage(const ofImage& first, const ofImage& second, double weight); +//// the absolute value of the difference between each pixel +//ofImage absoluteDifference(ofImage first, ofImage second); + #endif /* utils_hpp */