GMU:CyberSpace/electrochemical closed circuit system: Difference between revisions

From Medien Wiki
No edit summary
No edit summary
 
(14 intermediate revisions by the same user not shown)
Line 6: Line 6:
Wood<br>
Wood<br>
Plexiglas cylinder<br>
Plexiglas cylinder<br>
Copperbar massive<br>
Copper bar massive<br>
Coppersulfatesolution<br>
Copper sulfate solution<br>
Arduino Uno<br>
Powersupply 12V 2.1A DC<br>
Powersupply 12V 2.1A DC<br>
2x Resitor 2.2Ω<br>
3x Resitor 2.2Ω<br>
1x 8x Relais<br>
6x Relais<br>
1x Arduino Uno<br>


----
'''electrochemical closedcircuit system #3''':


'''Diagram''':
The electrochemical closedcircuit system #3 comprises of three units. Each unit acts independently, but they share the same source of energy.<br>
The units strive to close the gap between their electrodes through electrochemical processes. While solid copper at the anode gets reduced and copper ions are pulled into solution, copper ions at the kathode get oxidized and go into solid state. The reaction is driven by the electric potential differences between the electrodes. When the growing copper fractal closes the gap between the potentials, the unit registers the resulting drop in resistance and reverses the polarity of the electrodes. In this way the growth process is also reversed, which usually results in the breaking of a grown structure or their dissolution.<br>
In case of a breaking structure the resistance jumps up again, which again results in a reversal of polarity. This behaviour continues until the units use up their electrodes and therefore have no more way to transport energy.<br>


[[File:diagram_cb.png|frameless|800px]]
For this work i was inspired by the thinking of how a complex system could find a way to organize itself and pay demand to the everchanging environment that it is in and also part of. Important works for my context were done by Gordon Pask and Roman Kirschner. Gordon Pask was trying to find a system that could possibly assemble itself and adapt to stimuli of its surrounding. With his "Ear" he found a way to differentiate between two different audio frequencies through an electrochemical device. Roman Kirschner with "Roots" was especially interested in what transformations emergence can bring forward in a sufficiently open system.<br>


For my work the emergence is an important aspect. Although each unit is a rather simple system with simple rules, the fractal structure that arises cannot be predicted. Still the result can be interpreted very easily. Either the gap is open or closed - zero or one. With this work i want to emphasise the state in between two states. Virtually every process can be broken down to a composition of atomic decisions. When is the tipping point reached? When does a neuron "decide" to fire? When is a category not fitting any longer? In general: how does decision making look like?<br>


Another important aspect is the constantly growing fractal structure in each unit. It resembles a simplified process of a system to respond to its environment. The structure is the result of the system paying demand to the electric stimuli. It tries to find the most - energy - efficient way to close the gap. The "better" the structure the higher the current running through the unit the faster the growth. But faster growth also results in a faster wear off of the electrodes.<br>
Even if the starting conditions for each unit are the same, there will never be exactly the same structure. If the gap is closed the grown structure destroys itself to start growing from anew. The new structure starts growing on parts of the old structure and, again, tries to find the best solution for the closing of the gap still paying tribute to the everchanging conditions in the unit.
<br><br>
----
----


'''Code''':
'''Timelapse''':
<videoflash type="vimeo">69923035</videoflash>


Arduino.ino:
----
<pre>
#include "Unit.h"
#include "RunningAverage.h"
#include "StopWatch.h"


bool doprint=true;
'''Presentation at Summaery 2013''':


const int threshold=20;
<gallery>
const int neg_threshold=-10;
File:summary1_cb.jpg
const int array_size=15;
File:summary2_cb.jpg
const int fill_array=200;
File:summary3_cb.jpg
</gallery>


unsigned int grow_time=36000;
----
unsigned int break_time=7200;
unsigned int wait_time=1200;
 
const int unit_one_sensor=A0;
const int unit_two_sensor=A1;
const int unit_thr_sensor=A2;
 
int unit_one_plus=4;
int unit_one_minus=5;
 
int unit_two_plus=6;
int unit_two_minus=7;
 
int unit_thr_plus=8;
int unit_thr_minus=9;
 
Unit one(unit_one_sensor, unit_one_minus, unit_one_plus, 1, threshold, array_size, fill_array);
Unit two(unit_two_sensor, unit_two_minus, unit_two_plus, 2, threshold, array_size, fill_array);
Unit thr(unit_thr_sensor, unit_thr_minus, unit_thr_plus, 3, threshold, array_size, fill_array);
 
 
void setup(){
 
  pinMode(unit_one_minus,OUTPUT);
  pinMode(unit_one_plus,OUTPUT);
  pinMode(unit_two_minus,OUTPUT);
  pinMode(unit_two_plus,OUTPUT);
  pinMode(unit_thr_minus,OUTPUT);
  pinMode(unit_thr_plus,OUTPUT);
 
  Serial.begin(19200);
 
  Serial.println("burnout_011");
 
  one.wachse();
  two.wachse();
  thr.wachse();
 
}
 
void loop(){
/*
  one.run();
  two.run();
  thr.run();
  */
  one.run_timed(grow_time, break_time, wait_time);
  two.run_timed(grow_time, break_time, wait_time);
  thr.run_timed(grow_time, break_time, wait_time);
 
 
  if(doprint)
  { 
    one.do_print();
    two.do_print();
    thr.do_print();
    Serial.println();
  }
  delay(1);
}
</pre>
 
Unit.h
<pre>
#ifndef Unit_h
#define Unit_h
 
#include "RunningAverage.h"
#include "StopWatch.h"
 
class Unit
{
public: 
  Unit(void);
  Unit(int const& sensor, int const& minus, int const& plus, int const& unitid, int const& threshold, int const& size, int const& fillarray);
  ~Unit(); 
  void wachse();
  void breche();
  void warte();
 
  int state();
 
  void run();
  void run_timed(unsigned int const& grow_time, unsigned int const& break_time, unsigned int const& wait_time);
 
  void emergency_break();
  void do_print();
  void fill_spaces(int const& value);
 
 
private: 
  int m_sensor;
  int m_relais_minus; 
  int m_relais_plus; 
  int m_state;
  int m_unitid;
  int m_threshold;
  int m_fillarray;
 
  RunningAverage m_RA;
  RunningAverage m_delta_RA;
 
  StopWatch m_sw;
 
 
  int m_readings;
 
};
 
#endif
 
</pre>
 
Unit.cpp
 
<pre>
#include "Unit.h"
#include "RunningAverage.h"
#include "StopWatch.h"
 
#include <Arduino.h>
 
Unit::Unit(int const& sensor, int const& r_minus, int const& r_plus, int const& unitid, int const& threshold, int const& size, int const& fillarray)
{
  m_sensor=sensor;
  m_relais_minus = r_minus;
  m_relais_plus = r_plus;
  m_unitid=unitid;
  m_threshold=threshold;
 
  m_state=0; 
  m_fillarray=fillarray;
  m_sw.start();
 
  m_RA.init(size);
  m_delta_RA.init(size);
 
  digitalWrite(m_relais_minus, HIGH);
  digitalWrite(m_relais_plus, HIGH); 
}
 
Unit::~Unit()
{
}
 
void Unit::wachse()
{   
  digitalWrite(m_relais_minus, LOW);
  digitalWrite(m_relais_plus, HIGH); 
 
  m_state=1;
}
 
void Unit::breche()
{
  digitalWrite(m_relais_minus, HIGH);
  delay(10);
  digitalWrite(m_relais_plus, LOW);
 
  m_state=2;
}
 
void Unit::warte()
{
  digitalWrite(m_relais_minus, HIGH);
  digitalWrite(m_relais_plus, HIGH);
 
  m_state=3;
}
 
int Unit::state()
{
  return m_state;
}
 
void Unit::run()
{
  m_readings=analogRead(m_sensor);
 
  emergency_break();
 
  m_RA.addValue(m_readings);
  m_delta_RA.addValue(m_readings-m_RA.getAverage());
 
  if(m_fillarray>0)
  {
    m_fillarray--;
  }
  else if(m_readings<=1000)
  {
    if(m_delta_RA.getAverage()>m_threshold)
    {
      breche();
    }
 
    if(m_delta_RA.getAverage()<(-m_threshold))
    {
      wachse();
    }
  }
}
 
void Unit::run_timed(unsigned int const&  grow_time, unsigned int const& break_time, unsigned int const& wait_time)
{
  m_readings=analogRead(m_sensor);
 
  emergency_break();
 
  m_RA.addValue(m_readings);
  m_delta_RA.addValue(m_readings-m_RA.getAverage());
 
  if(m_fillarray>0)
  {
    m_fillarray--;
  }
  else if(m_readings<=1000)
  {
    if(m_delta_RA.getAverage()>m_threshold)
    {
      breche();
      m_sw.reset();
      m_sw.start();
    }
 
    if(m_delta_RA.getAverage()<(-m_threshold))
    {
      wachse();
      m_sw.reset();
      m_sw.start();
    }
 
    if(m_state==1 && m_sw.elapsed()>grow_time)
    {
      breche();
    }
 
    if(m_state==2 && m_sw.elapsed()>break_time)
    {
      wachse();
    }
 
    if(m_state==3 && m_sw.elapsed()>wait_time)
    {
      wachse();
    }
  }
}
 
void Unit::do_print()
{
  Serial.print(" unit");
  Serial.print(m_unitid);
  Serial.print(": ");
  Serial.print(m_state);
  fill_spaces(m_readings);
  Serial.print(m_readings);
  Serial.print("  ");
  fill_spaces(m_delta_RA.getAverage());
  Serial.print(m_delta_RA.getAverage());
  Serial.print("#");
  fill_spaces(m_fillarray);
  Serial.print(m_fillarray);
  Serial.print("->");
  fill_spaces(m_sw.elapsed());
  Serial.print(m_sw.elapsed());
}
 
void Unit::emergency_break()
{
  if(m_readings>1000 && m_readings < 1010)
  {
    Serial.print(" | ");
    Serial.print(m_readings);
    Serial.print("  ");
    Serial.print("HIGH");
    Serial.print(" E_1 UNIT");
    Serial.print(m_unitid);
    Serial.print(": ");
    Serial.print(m_state);
    Serial.print(" | ");
 
    breche();
    m_sw.reset();
    m_sw.start();
 
  }
 
  if(m_readings>=1010)
  {
    Serial.print(" # ");
    Serial.print(m_readings);
    Serial.print(" # ");
    Serial.print("HIGH");
    Serial.print(" E_2 UNIT");
    Serial.print(m_unitid);
    Serial.print(": ");
    Serial.print(m_state);
    Serial.print(" # ");
 
    wachse();
    delay(10);
    breche();
    m_sw.reset();
    m_sw.start();
 
  }
 
  if(m_readings>1022)
  {
    Serial.print(" | ");
    Serial.print(m_readings);
    Serial.print("  ");
    Serial.print("HIGH");
    Serial.print(" E_3 UNIT");
    Serial.print(m_unitid);
    Serial.print(": ");
    Serial.print(m_state);
    Serial.print(" | ");
 
    warte();
    m_sw.reset();
    m_sw.start();
  }
}
 
void Unit::fill_spaces(int const& value)
{
  if(value<1000 && value>=0)
  {
    Serial.print(" ");
    if(value<100)
    {
      Serial.print(" ");
      if(value<10)
      {
        Serial.print(" ");
      }
    }
  }
 
  if(value>-1000 && value<0)
  {
    if(value>-100)
    {
      Serial.print(" ");
      if(value>-10)
      {
        Serial.print(" ");
      }
    }
  }
}
</pre>
 
RunningAverage.h
<pre>
#ifndef RunningAverage_h
#define RunningAverage_h
//
//    FILE: RunningAverage.h
//  AUTHOR: Rob dot Tillaart at gmail dot com
// PURPOSE: RunningAverage library for Arduino
//    URL: http://playground.arduino.cc/Main/RunningAverage
// HISTORY: See RunningAverage.cpp
//
// Released to the public domain
//
 
// backwards compatibility
// clr() clear()
// add(x) addValue(x)
// avg() getAverage()
 
#define RUNNINGAVERAGE_LIB_VERSION "0.2.02"
 
class RunningAverage
{
public:
  RunningAverage();
  RunningAverage(int);
  ~RunningAverage();
  void clear();
  void init(int n);
  void addValue(int);
  int getAverage();
  void fillValue(int, int);
 
protected:
  int _size;
  int _cnt;
  int _idx;
  int _sum;
  int * _ar;
};
 
#endif
// END OF FILE
</pre>
 
RunningAverage.cpp
<pre>
//
//    FILE: RunningAverage.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.2.02
// PURPOSE: RunningAverage library for Arduino
//
// The library stores the last N individual values in a circular buffer,
// to calculate the running average.
//
// HISTORY:
// 0.1.00 - 2011-01-30 initial version
// 0.1.01 - 2011-02-28 fixed missing destructor in .h
// 0.2.00 - 2012-??-?? Yuval Naveh added trimValue (found on web)
//          http://stromputer.googlecode.com/svn-history/r74/trunk/Arduino/Libraries/RunningAverage/RunningAverage.cpp
// 0.2.01 - 2012-11-21 refactored
// 0.2.02 - 2012-12-30 refactored trimValue -> fillValue
//
// Released to the public domain
//
 
#include "RunningAverage.h"
#include <stdlib.h>
 
RunningAverage::RunningAverage()
{
 
}
 
RunningAverage::RunningAverage(int n)
{
  _size = n;
  _ar = (int*) malloc(_size * sizeof(int));
  clear();
}
 
RunningAverage::~RunningAverage()
{
  free(_ar);
}
 
// resets all counters
void RunningAverage::clear()
{
  _cnt = 0;
  _idx = 0;
  _sum = 0.0;
  for (int i = 0; i< _size; i++) _ar[i] = 0.0;  // needed to keep addValue simple
}
 
void RunningAverage::init(int n)
{
  _size = n;
  _ar = (int*) malloc(_size * sizeof(int));
  clear();
}
 
// adds a new value to the data-set
void RunningAverage::addValue(int f)
{
  _sum -= _ar[_idx];
  _ar[_idx] = f;
  _sum += _ar[_idx];
  _idx++;
  if (_idx == _size) _idx = 0;  // faster than %
  if (_cnt < _size) _cnt++;
}
 
// returns the average of the data-set added sofar
int RunningAverage::getAverage()
{
  if (_cnt == 0) return 0; // NaN ?  math.h
  return _sum / _cnt;
}
 
// fill the average with a value
// the param number determines how often value is added (weight)
// number should preferably be between 1 and size
void RunningAverage::fillValue(int value, int number)
{
  clear();
  for (int i = 0; i < number; i++)
  {
    addValue(value);
  }
}
// END OF FILE
</pre>
 
Stopwatch.h
<pre>
#ifndef StopWatch_h
#define StopWatch_h
//
//    FILE: StopWatch.h
//  AUTHOR: Rob Tillaart
// PURPOSE: Simple StopWatch library for Arduino
// HISTORY: See StopWatch.cpp
//    URL: http://playground.arduino.cc/Code/StopWatchClass
//
// Released to the public domain
//
 
#define STOPWATCH_LIB_VERSION "0.1.03"
 
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
 
class StopWatch
{
public:
  enum State {
    RESET, RUNNING, STOPPED  };
  enum Resolution {
    MILLIS, MICROS, SECONDS  };
  StopWatch(enum Resolution res = SECONDS);
  void start();
  void stop();
  void reset();
  unsigned long value();
  unsigned long elapsed() {
    return value();
  };
  bool isRunning();
  enum State state();
  enum Resolution resolution() {
    return _res;
  };
 
private:
  enum State _state;
  enum Resolution _res;
  unsigned long _starttime;
  unsigned long _stoptime;
  unsigned long (*_gettime)(void);
  static unsigned long seconds() {
    return millis()/1000;
  };
};
 
#endif
// END OF FILE
</pre>
 
StopWatch.cpp
<pre>
//
//    FILE: StopWatch.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.03
// PURPOSE: Simple StopWatch library for Arduino
//
// The library is based upon millis() and therefore
// has the same restrictions as millis() has wrt overflow.
//
// HISTORY:
// 0.1.00 - 2011-01-04 initial version
// 0.1.01 - 2011-01-04 Added better state
// 0.1.02 - 2011-06-15 Added state() + #defines + lib version
// 0.1.03 - 2012-01-22 Added several improvements
//            By mromani & Rob Tillaart
//
// Released to the public domain
//
 
#include "StopWatch.h"
 
StopWatch::StopWatch(enum Resolution res)
{
  _res = res;
  switch(_res) {
  case MICROS:
    _gettime = micros;
    break;
  case MILLIS:
    _gettime = millis;
    break;
  case SECONDS:
    _gettime = seconds;
    break;
  default: 
    _gettime = millis;
    break;
  }
  reset();
}
 
void StopWatch::reset()
{
  _state = StopWatch::RESET;
  _starttime = _stoptime = 0;
}
 
void StopWatch::start()
{
  if (_state == StopWatch::RESET || _state == StopWatch::STOPPED)
  {
    _state = StopWatch::RUNNING;
    unsigned long t = _gettime();
    _starttime += t - _stoptime;
    _stoptime = t;
  }
}
 
unsigned long StopWatch::value()
{
  if (_state == StopWatch::RUNNING) _stoptime = _gettime();
  return _stoptime - _starttime;
}
 
void StopWatch::stop()
{
  if (_state == StopWatch::RUNNING)
  {
    _state = StopWatch::STOPPED;
    _stoptime = _gettime();
  }
}
 
bool StopWatch::isRunning()
{
  return (_state == StopWatch::RUNNING);
}


enum StopWatch::State StopWatch::state()
[[/Technical documentation/]]
{
  return _state;
}
// END OF FILE
</pre>

Latest revision as of 03:21, 16 July 2015

Electrochemicalsystem.01.JPG

Material:

Wood
Plexiglas cylinder
Copper bar massive
Copper sulfate solution
Arduino Uno
Powersupply 12V 2.1A DC
3x Resitor 2.2Ω
6x Relais

electrochemical closedcircuit system #3:

The electrochemical closedcircuit system #3 comprises of three units. Each unit acts independently, but they share the same source of energy.
The units strive to close the gap between their electrodes through electrochemical processes. While solid copper at the anode gets reduced and copper ions are pulled into solution, copper ions at the kathode get oxidized and go into solid state. The reaction is driven by the electric potential differences between the electrodes. When the growing copper fractal closes the gap between the potentials, the unit registers the resulting drop in resistance and reverses the polarity of the electrodes. In this way the growth process is also reversed, which usually results in the breaking of a grown structure or their dissolution.
In case of a breaking structure the resistance jumps up again, which again results in a reversal of polarity. This behaviour continues until the units use up their electrodes and therefore have no more way to transport energy.

For this work i was inspired by the thinking of how a complex system could find a way to organize itself and pay demand to the everchanging environment that it is in and also part of. Important works for my context were done by Gordon Pask and Roman Kirschner. Gordon Pask was trying to find a system that could possibly assemble itself and adapt to stimuli of its surrounding. With his "Ear" he found a way to differentiate between two different audio frequencies through an electrochemical device. Roman Kirschner with "Roots" was especially interested in what transformations emergence can bring forward in a sufficiently open system.

For my work the emergence is an important aspect. Although each unit is a rather simple system with simple rules, the fractal structure that arises cannot be predicted. Still the result can be interpreted very easily. Either the gap is open or closed - zero or one. With this work i want to emphasise the state in between two states. Virtually every process can be broken down to a composition of atomic decisions. When is the tipping point reached? When does a neuron "decide" to fire? When is a category not fitting any longer? In general: how does decision making look like?

Another important aspect is the constantly growing fractal structure in each unit. It resembles a simplified process of a system to respond to its environment. The structure is the result of the system paying demand to the electric stimuli. It tries to find the most - energy - efficient way to close the gap. The "better" the structure the higher the current running through the unit the faster the growth. But faster growth also results in a faster wear off of the electrodes.
Even if the starting conditions for each unit are the same, there will never be exactly the same structure. If the gap is closed the grown structure destroys itself to start growing from anew. The new structure starts growing on parts of the old structure and, again, tries to find the best solution for the closing of the gap still paying tribute to the everchanging conditions in the unit.


Timelapse: <videoflash type="vimeo">69923035</videoflash>


Presentation at Summaery 2013:


Technical documentation