鉛筆可変抵抗でLED調光

鉛筆で可変抵抗を自作できると聞きテストした. 
最終的には, 長さに比例して抵抗が大きくなる別の素材が欲しい. 
しかし, まずは試しということで. 

# 構成
![IMG_2898.jpg](https://qiita-image-store.s3.amazonaws.com/0/102253/5a348bd9-3318-bf27-6aa6-770361650af9.jpeg)


# 動画
https://www.youtube.com/watch?v=TCviH7VKQeI

<iframe width="560" height="315" src="https://www.youtube.com/embed/TCviH7VKQeI" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

# git
https://github.com/keitasumiya/arduino/tree/master/analog-in

# code
下記の段階にわけて掲載する. 
1) analog-inputする
2) inputの値を履歴のリストとして一定数保持し, その平均を求める
3) inputの履歴リストの誤差二乗平均ルートをとる(自作可変抵抗器に接触しているかどうかを検出するため)
4) 自作可変抵抗器に接触している(touch)かどうかの判定をする
5) 自作可変抵抗器に接触している際に, その抵抗の値によってLEDを調光する

## analog-inputする

```c:analog_in.ino
const int pinI = 0; //input

void setup() {
  pinMode(pinI, INPUT);
  Serial.begin(9600);
}

void loop() {
  int val = analogRead(pinI);
  Serial.println(val);
}
```

## inputの値を履歴のリストとして一定数保持し, その平均を求める

```c:analog_in_mean_fn.ino
const int PinI = 0; //input
const int ValuesSize = 10;
int Values[ValuesSize];
int Frame;

void setup() {
  pinMode(PinI, INPUT);
  Serial.begin(9200);
  for(int i=0; i<ValuesSize; i++){
    Values[i] = 0;
  }
  Frame = 0;
}

void loop() {
  Frame++;
  int val = analogRead(PinI);

  update_values(Values, sizeof(Values)/sizeof(int), val);

  float total = calc_total(Values, sizeof(Values)/sizeof(int));
  float mean = calc_mean(Values, sizeof(Values)/sizeof(int));

  print_int("", val, " ");
  print_float("total=", total, " ");
  print_float("mean=", mean, " ");
  print_ints("values=[", Values, sizeof(Values)/sizeof(int), "] ");
  
  Serial.println("");
}

//######################################################################
//######################################################################
//######################################################################

void update_values(int _values[], int _valuesSize, int _val){
  if(Frame < _valuesSize){
    _values[Frame] = _val;
  } else {
    for(int i=0; i<_valuesSize-1; i++){
      _values[i] = _values[i+1];
    }
    _values[_valuesSize-1] = _val;
  }
}

//----------------------------------------------------------------------

float calc_total(int _values[], int _valuesSize){
  float _total = 0;
  for(int i=0; i<_valuesSize; i++){
    _total+=_values[i];
  }
  return _total;
}

//----------------------------------------------------------------------

float calc_mean(int _values[], int _valuesSize){
  float _total = 0;
  float _mean = 0;
  _total = calc_total(_values, _valuesSize);
  _mean = _total/float(_valuesSize);
  return _mean;
}

//----------------------------------------------------------------------

void print_int(char* _c1, int _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_float(char* _c1, float _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_ints(char* _c1, int _x[], int _xSize, char* _c2){
  Serial.print(_c1);
  for(int i=0; i<_xSize-1; i++){
    print_int("", _x[i], " ");
  }
  print_int("", _x[_xSize-1], "");
  Serial.print(_c2);
}
```

## inputの履歴リストの誤差二乗平均ルートをとる

```c:analog_in_rootMeanSquareError_fn.ino
const int PinI = 0; //input
const int ValuesSize = 10;
int Values[ValuesSize];
int Frame;

void setup() {
  pinMode(PinI, INPUT);
  Serial.begin(9200);
  for(int i=0; i<ValuesSize; i++){
    Values[i] = 0;
  }
  Frame = 0;
}

void loop() {
  Frame++;
  int val = analogRead(PinI);

  update_values(Values, sizeof(Values)/sizeof(int), val);

  float total = calc_total(Values, sizeof(Values)/sizeof(int));
  float mean = calc_mean(Values, sizeof(Values)/sizeof(int));
  float rootMeanSquareError = calc_rootMeanSquareError(Values, ValuesSize, mean);

  print_int("", val, " ");
  print_float("total=", total, " ");
  print_float("mean=", mean, " ");
  print_float("rootMeanSquareError=", rootMeanSquareError, " ");
  print_ints("values=[", Values, sizeof(Values)/sizeof(int), "] ");
  
  Serial.println("");
}

//######################################################################
//######################################################################
//######################################################################

void update_values(int _values[], int _valuesSize, int _val){
  if(Frame < _valuesSize){
    _values[Frame] = _val;
  } else {
    for(int i=0; i<_valuesSize-1; i++){
      _values[i] = _values[i+1];
    }
    _values[_valuesSize-1] = _val;
  }
}

//----------------------------------------------------------------------

float calc_total(int _values[], int _valuesSize){
  float _total = 0;
  for(int i=0; i<_valuesSize; i++){
    _total+=_values[i];
  }
  return _total;
}

//----------------------------------------------------------------------

float calc_mean(int _values[], int _valuesSize){
  float _total = 0;
  float _mean = 0;
  _total = calc_total(_values, _valuesSize);
  _mean = _total/float(_valuesSize);
  return _mean;
}

//----------------------------------------------------------------------

float calc_rootMeanSquareError(int _values[], int _valuesSize, float _trueValue){
  float _totalSquareError = 0;
  float _meanSquareError = 0;
  float _rootMeanSquareError = 0;
  for(int i=0; i<_valuesSize; i++){
    float _error = _values[i]-_trueValue;
    _totalSquareError+=_error*_error;
  }
  _meanSquareError = _totalSquareError/float(_valuesSize);
  _rootMeanSquareError = sqrt(_meanSquareError);
  return _rootMeanSquareError;
}

//----------------------------------------------------------------------

void print_int(char* _c1, int _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_float(char* _c1, float _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_ints(char* _c1, int _x[], int _xSize, char* _c2){
  Serial.print(_c1);
  for(int i=0; i<_xSize-1; i++){
    print_int("", _x[i], " ");
  }
  print_int("", _x[_xSize-1], "");
  Serial.print(_c2);
}
```

## 自作可変抵抗器に接触している(touch)かどうかの判定をする

```c:analog_in_touch_fn.ino
const int PinI = 0; //input
const int ValuesSize = 10;
const float ErrorThreshold = 70.0;
int Values[ValuesSize];
int Frame;

void setup() {
  pinMode(PinI, INPUT);
  Serial.begin(9200);
  for(int i=0; i<ValuesSize; i++){
    Values[i] = 0;
  }
  Frame = 0;
}

void loop() {
  Frame++;
  int val = analogRead(PinI);

  update_values(Values, sizeof(Values)/sizeof(int), val);

  float total = calc_total(Values, sizeof(Values)/sizeof(int));
  float mean = calc_mean(Values, sizeof(Values)/sizeof(int));
  float rootMeanSquareError = calc_rootMeanSquareError(Values, ValuesSize, mean);

  bool isTouch = check_touch(rootMeanSquareError, ErrorThreshold);
  
  print_bool("", isTouch, " ");
  print_int("", val, " ");
  print_float("total=", total, " ");
  print_float("mean=", mean, " ");
  print_float("rootMeanSquareError=", rootMeanSquareError, " ");
  print_ints("values=[", Values, sizeof(Values)/sizeof(int), "] ");  
  Serial.println("");
}

//######################################################################
//######################################################################
//######################################################################

void update_values(int _values[], int _valuesSize, int _val){
  if(Frame < _valuesSize){
    _values[Frame] = _val;
  } else {
    for(int i=0; i<_valuesSize-1; i++){
      _values[i] = _values[i+1];
    }
    _values[_valuesSize-1] = _val;
  }
}

//----------------------------------------------------------------------

float calc_total(int _values[], int _valuesSize){
  float _total = 0;
  for(int i=0; i<_valuesSize; i++){
    _total+=_values[i];
  }
  return _total;
}

//----------------------------------------------------------------------

float calc_mean(int _values[], int _valuesSize){
  float _total = 0;
  float _mean = 0;
  _total = calc_total(_values, _valuesSize);
  _mean = _total/float(_valuesSize);
  return _mean;
}

//----------------------------------------------------------------------

float calc_rootMeanSquareError(int _values[], int _valuesSize, float _trueValue){
  float _totalSquareError = 0;
  float _meanSquareError = 0;
  float _rootMeanSquareError = 0;
  for(int i=0; i<_valuesSize; i++){
    float _error = _values[i]-_trueValue;
    _totalSquareError+=_error*_error;
  }
  _meanSquareError = _totalSquareError/float(_valuesSize);
  _rootMeanSquareError = sqrt(_meanSquareError);
  return _rootMeanSquareError;
}

//----------------------------------------------------------------------

bool check_touch(float _rootMeanSquareError, float _errorThreshold){
  bool _isTouch = false;
  if (_rootMeanSquareError <= _errorThreshold){
    Serial.print("[touch!!] ");
    _isTouch = true;
  }else{
    Serial.print("[release] ");
  }
  return _isTouch;
}

//----------------------------------------------------------------------

void print_int(char* _c1, int _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_float(char* _c1, float _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_bool(char* _c1, bool _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}
//----------------------------------------------------------------------

void print_ints(char* _c1, int _x[], int _xSize, char* _c2){
  Serial.print(_c1);
  for(int i=0; i<_xSize-1; i++){
    print_int("", _x[i], " ");
  }
  print_int("", _x[_xSize-1], "");
  Serial.print(_c2);
}
```


## 自作可変抵抗器に接触している際に, その抵抗の値によってLEDを調光する

```c:analog_in_touch_pwm-out_fn.ino
const int PinI = 0; //input
const int PinO = 3;
const int ValuesSize = 10;
const float ErrorThreshold = 5.0;
const float ValueMin = 50.0;
const float ValueMax = 900.0;
int Values[ValuesSize];
int Frame;

void setup() {
  pinMode(PinI, INPUT);
  pinMode(PinO, OUTPUT);
  Serial.begin(115200);
  for(int i=0; i<ValuesSize; i++){
    Values[i] = 0;
  }
  Frame = 0;
}

void loop() {
  Frame++;
  int val = analogRead(PinI);

  update_values(Values, sizeof(Values)/sizeof(int), val);

  float total = calc_total(Values, sizeof(Values)/sizeof(int));
  float mean = calc_mean(Values, sizeof(Values)/sizeof(int));
  float rootMeanSquareError = calc_rootMeanSquareError(Values, ValuesSize, mean);

  bool isTouch = check_touch(rootMeanSquareError, ErrorThreshold);

  int outputPWM = calc_outputPWM(isTouch, val, ValueMin, ValueMax);
  analogWrite(PinO, outputPWM);

  print_touch(isTouch);
  print_bool("", isTouch, " ");
  print_int("", outputPWM, " ");
  print_int("", val, " ");
  print_float("total=", total, " ");
  print_float("mean=", mean, " ");
  print_float("rootMeanSquareError=", rootMeanSquareError, " ");
  print_ints("values=[", Values, sizeof(Values)/sizeof(int), "] ");  
  Serial.println("");
}

//######################################################################
//######################################################################
//######################################################################

void update_values(int _values[], int _valuesSize, int _val){
  if(Frame < _valuesSize){
    _values[Frame] = _val;
  } else {
    for(int i=0; i<_valuesSize-1; i++){
      _values[i] = _values[i+1];
    }
    _values[_valuesSize-1] = _val;
  }
}

//----------------------------------------------------------------------

float calc_total(int _values[], int _valuesSize){
  float _total = 0;
  for(int i=0; i<_valuesSize; i++){
    _total+=_values[i];
  }
  return _total;
}

//----------------------------------------------------------------------

float calc_mean(int _values[], int _valuesSize){
  float _total = 0;
  float _mean = 0;
  _total = calc_total(_values, _valuesSize);
  _mean = _total/float(_valuesSize);
  return _mean;
}

//----------------------------------------------------------------------

float calc_rootMeanSquareError(int _values[], int _valuesSize, float _trueValue){
  float _totalSquareError = 0;
  float _meanSquareError = 0;
  float _rootMeanSquareError = 0;
  for(int i=0; i<_valuesSize; i++){
    float _error = _values[i]-_trueValue;
    _totalSquareError+=_error*_error;
  }
  _meanSquareError = _totalSquareError/float(_valuesSize);
  _rootMeanSquareError = sqrt(_meanSquareError);
  return _rootMeanSquareError;
}

//----------------------------------------------------------------------

bool check_touch(float _rootMeanSquareError, float _errorThreshold){
  bool _isTouch = false;
  if (_rootMeanSquareError <= _errorThreshold){
    _isTouch = true;
  }else{
  }
  return _isTouch;
}

//----------------------------------------------------------------------

float calc_outputPWM(bool _isTouch, int _val, float _valueMin, float _valueMax){
  int _outputPWM;
  if (_isTouch == true) {
    float adjustedValue = 1024.0*(_val - _valueMin)/(_valueMax - _valueMin);
    if(adjustedValue<=0){adjustedValue=1;}
    if(adjustedValue>1023){adjustedValue=1023;}
    _outputPWM = int(adjustedValue/4);
  }else{
    _outputPWM = 0;
  }
  return _outputPWM;
}

//----------------------------------------------------------------------

void print_touch(bool _isTouch){
  if (_isTouch == true){
    Serial.print("[touch!!] ");
  }else{
    Serial.print("[release] ");
  }
}

//----------------------------------------------------------------------

void print_int(char* _c1, int _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_float(char* _c1, float _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}

//----------------------------------------------------------------------

void print_bool(char* _c1, bool _x, char* _c2){
  Serial.print(_c1);
  Serial.print(_x);
  Serial.print(_c2);
}
//----------------------------------------------------------------------

void print_ints(char* _c1, int _x[], int _xSize, char* _c2){
  Serial.print(_c1);
  for(int i=0; i<_xSize-1; i++){
    print_int("", _x[i], " ");
  }
  print_int("", _x[_xSize-1], "");
  Serial.print(_c2);
}
```

### 動画
https://www.youtube.com/watch?v=TCviH7VKQeI


# ref
[手作り可変抵抗器　(工作です・２)](http://www.geocities.jp/cteruru/den-kai/html/Block3-07.html)
[111.手作り抵抗器](https://sites.google.com/a/gclue.jp/fab-zang-docs/7-basic-electronics-parts/111-make-resistor)

[Vectors in Arduino](https://stackoverflow.com/questions/9986591/vectors-in-arduino)
[配列を自由自在に作る](https://9cguide.appspot.com/19-01.html)
[Arduino 日本語リファレンス 配列](http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=1333)

[Arduinoの基本プログラム(スケッチ)](http://tyk-systems.com/arduinobasic/arduinobasic.html)

[Arduino 日本語リファレンス sizeof](http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=1969)
[Arduinoで配列を関数の引数として扱う](http://www.autumn-color.com/archives/9)

# comments
- arduinoで配列を使うのは少し癖がある
- arduinoではvector(長さ可変なリスト)は作れない
- 自作関数内で配列の長さを調べるのは面倒. なので, 引数で長さを送るのがbetter
- sizeofでint配列の長さを求める際はsizeof(int)で割る必要がある(intが2byteなため)
- > [Arduinoで配列を関数の引数として扱う](http://www.autumn-color.com/archives/9)