Hobby Science&Experiment

愛と工作の日々

趣味でやっている工作や勉強したことのメモ書きです。

Lenovo H330の現状と改造に関する外部記事

https://kakaku.com/item/K0000258277/images/

現状

Lenovo H330を11年も使用してきたが、もっと使えるなら可能な限り使い倒したい。
あまりPCのスペックにこだわりはないが、仕事で良スペックのPCを使うようになっため、相対的に重さを感じるようになった。
ブラウザでメモリが半分使われてるのもどうかと思うので、今回はメモリ増設を検討中。

CrystalDiskMark8.0.4によるベンチマーク
メモリ、CPU使用率

そういえば急に電源が落ちることもあるので、もしかしたらHDDも異常があるかもしれない。高速化も兼ねてメモリの次はSSDへの換装もアリ。
先人たちの記録がネット上に多く残っているもの有難い。

機種

機種:Lenovo H330 11851GJ
購入日: 2011年8月9日(11年3か月前)
購入金額:¥ 47,320

購入日

ケース交換

下記サイトを参考に実施済(2015頃)
revive-pc.seesaa.net

HDD交換

下記サイトを参考に実施済(2015頃)
revive-pc.seesaa.net

HDD→SSD交換

hitomaru1.net

Arduino分圧回路による抵抗測定(回路・プログラム)

ロガー代わりにArduinoで分圧回路を使うことが良くありますのでここにメモっておきます。n回積算の平均化も行っています。

原理

f:id:tara-chang:20210918075852p:plain

コード

デジタルピンを分圧回路への電源供給に使っちゃってます。多分あんまりよくない方法です。

#define voltPin1 2
#define readPin1 A2
float Rref1 = 10.03;
float voltAplied = 4.97;//V
byte num1 = 5;

void setup()
{
  Serial.begin(9600);
  pinMode(voltPin1, OUTPUT);
}

void loop()
{ 
digitalWrite(voltPin1,HIGH);
float resistance1 = resMeasure(readPin1, num1, Rref1);
digitalWrite(voltPin1,LOW);
Serial.println(resistance1);
delay(500);
}

float resMeasure(byte pin, byte num, float resRef){
  float test[num];
  for (byte i=0; i<num; i++){
    int analogData = analogRead(pin);
    float voltSmp = analogData* voltAplied; 
    voltSmp /= 1024;
    float voltRef = voltAplied - voltSmp ;
    float resSmp = voltSmp/voltRef;
    resSmp *= resRef;
    test[i] = resSmp;}
  float resAve = makeAve(test, num);     
  return resAve;
}

float makeAve(float readArray[], byte number){
  byte i;
  float sum = 0;
  for (i=0; i<number; i++){
    sum += readArray[i];
  }
  float averate = sum / number;
  return averate;
}

参考リンク

qiita.com
note.com

Raspbianへのpython3.7.11インストール

セットアップしたてほやほやのRaspberry Pi3はPython3.4が入っています。そこにPython3.7をインストールしたので記録します。

情報ソース

最近少しずつセキュリティ意識とリテラシーが芽生え始めたので、なるべく多くの人に試された信用に足る方法を使いたいものです。GitHubにて良さそうな手順を発見。
Installing Python 3.7.4 on Raspbian · GitHub
成功コメントも多く、投稿者も信用に足りそうですので、こちらの方法を取りたいと思います。こういうのはGitHubの良いところですね。

国内のブログ、Quitaでもほぼ同様の手順でインストールされていることが確認出来ました。
Raspberry Pi に Python 3.7.0 をインストールする - Qiita
Raspberry Pi python3.5.3をpython3.7.2にアップグレード - Qiita
Raspberry PiにPython3.7.2をインストール – OKASHIMOZE
Rasbianにpython3.7を入れ、ついでに仮想環境を構築する。 │ Pei's Lab

環境

$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"

インストール手順

必要なビルドツールのインストール。aptコマンドについてはこちらにまとまっています。

$ sudo apt update
$ sudo apt upgrade
$ sudo apt autoremove
$ sudo apt-get install build-essential tk-dev libncurses5-dev libncursesw5-dev libreadline6-dev libdb5.3-dev libgdbm-dev libsqlite3-dev libssl-dev libbz2-dev libexpat1-dev liblzma-dev zlib1g-dev libffi-dev -y

Pythonのダウンロードとインストールを行う。チュートリアルでは3.7.4でしたが、3.7.11までリリースされていたので3.7.11としました。

$ wget https://www.python.org/ftp/python/3.7.11/Python-3.7.11.tar.xz
$ tar xf Python-3.7.11.tar.xz
$ cd Python-3.7.11
$ ./configure
$ make -j 4
$ sudo make altinstall

reboot後にversion確認するとインストールされていることが確認出来ました。すんなり行けてよかったです。

$ python3 -V
Python 3.7.11

ESP32ボードのボタンノイズを対策(debounce)した【ソフトウェア編】

前回ESP32ボードでISR(割り込みサブルーチン)を利用したボタンカウンタを作成しましたが、ボタンが2重・3重に押されてしまう問題がありました。
ESP32のInterrupt Service Routine(割り込みサブルーチン)でButton counterを作る - 愛と工作の日々
調べてみるとチャタリング(chattering)、バウンス(bounce)等と呼ばれる現象のようです。
f:id:tara-chang:20210704172115p:plain
f:id:tara-chang:20210704172138p:plain
一回押しただけのつもりでもスイッチの接点が振動してしまっているような感じですね。
メジャーな現象のようで、回路を使った対策、ソフトを使った対策それぞれあるようです。英語では[chattering][button noise][debounce]などのワードで検索すると多くヒットします。
www.marutsu.co.jp
techtutorialsx.com
www.syncfusion.com
jumbleat.com
今回はソフト面から簡易的に対策してみることにしました。

修正コード

struct Button {
  const uint8_t PIN;
  uint32_t numberKeyPresses;
  bool pressed;
  uint32_t lastMillis;
};

Button button1 = {18, 0, false, 0};
Button button2 = {19, 0, false, 0};

void IRAM_ATTR isr() {
  if (millis() - button1.lastMillis > 500) {
    button1.numberKeyPresses += 1;
    Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses);  
  }
  button1.lastMillis = millis();
}

void IRAM_ATTR isr2() {
  if (millis() - button2.lastMillis > 500) {
    button2.numberKeyPresses += 1;
    Serial.printf("Button 2 has been pressed %u times\n", button2.numberKeyPresses);  
  }
  button2.lastMillis = millis();
}

void setup() {
  Serial.begin(9600);
  pinMode(button1.PIN, INPUT_PULLUP);
  pinMode(button2.PIN, INPUT_PULLUP);
  attachInterrupt(button1.PIN, isr,  FALLING);
  attachInterrupt(button2.PIN, isr2, FALLING);
}

void loop() {
  if (button1.pressed) {
  }
  if (button2.pressed) {
  }
  delay(100);
}

FALLINGの検出をした際、前回の検出から500msec以上経過してる場合のみボタンプッシュとしてカウントするようにしました。500msecより早くボタン操作が出来ないことも意味していますが、そんなに連打する用途は今のところ想定していないので良しとします。動作は良好です。
f:id:tara-chang:20210704173325p:plain
今回はソフトウェア編ですがハードウェア編もあるかもしれません。ハード面からの対策もいろいろやってみましたがいまいちうまく行ってません。

ESP32のInterrupt Service Routine(割り込みサブルーチン)でButton counterを作る

ESP32開発ボードとタクトスイッチでボタンカウンターを作ります。ボタンカウンターを使うと一つのボタンで複数の機能を切り替えたりパラメータをデジタルに調節できるので好きです。
Arduinoと同じように割り込みが使用可能なようです。以下サイトのコードをベースにしています。ボタンを二つに増やしています。
https://lastminuteengineers.com/handling-esp32-gpio-interrupts-tutorial/lastminuteengineers.com
D18およびD19ピンがLOWに落ちる瞬間(FALLING)を監視しています。

struct Button {
  const uint8_t PIN;
  uint32_t numberKeyPresses;
  bool pressed;
};

Button button1 = {18, 0, false};
Button button2 = {19, 0, false};

void IRAM_ATTR isr() {
  button1.numberKeyPresses += 1;
  button1.pressed = true;
}

void IRAM_ATTR isr2() {
  button2.numberKeyPresses += 1;
  button2.pressed = true;
}

void setup() {
  Serial.begin(9600);
  pinMode(button1.PIN, INPUT_PULLUP);
  pinMode(button2.PIN, INPUT_PULLUP);
  attachInterrupt(button1.PIN, isr, FALLING);
  attachInterrupt(button2.PIN, isr2, FALLING);

}

void loop() {
  if (button1.pressed) {
      Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses);
      button1.pressed = false;
  }

  if (button2.pressed) {
      Serial.printf("Button 2 has been pressed %u times\n", button2.numberKeyPresses);
      button2.pressed = false;
  }

}

structを使ったコードを始めて見ましたが、これはこれでエレガントで良いですね!使いこなせるようになりたいです。

動作

タクトスイッチを押してD18,D19ピンがオフになるとそれぞれボタン1,2が押されたと表示されています。一回のプッシュで2~4回程度押されたとカウントするときもあること(これはArduinoでもありました)、ENボタンを押しても正常にプログラムが始まらないことが多いことなどの問題があります。
f:id:tara-chang:20210703231849p:plain
※2021.7.4 追記
スイッチを複数回推したことになってしまう現象はチャタリングと呼ばれる現象のようです。対策が必要ですね。
jumbleat.com

天災に備え、非常用バッテリー電源の選定してみた

毎年のように豪雨や台風が続きますね。一度停電で痛い目に遭ったことがありますので、今年も台風の季節が来る前に非常用電源(バッテリーとAC電源の一体型タイプ)を購入しようと考えています。折角なので選定の際の考えを記録しておくことにします。

電源の基本スぺック

重要となるスペックはやはり「電力」と「容量」です。以下簡単に説明します。

  • 電力[単位:W(ワット)]

バッテリーが出力できる電力の大きさを表します。動かす家電の種類を考える上で必要となります。使用電力の総量[Wh]は電力[W]*使用時間[hour]から求めることが出来ます。

  • 容量[単位:Wh(ワットアワー)]

バッテリーに蓄えられた電力の総量です。どれくらいバッテリーが持つかが決まります。300Whの容量であれば300Wの電化製品が1時間使用することが出来ます。mAhで表記されることもありますが、Whのみに着目して問題はありません。

価格とスペックの関係

各社バッテリーの価格と電力・容量の関係をまとめてみました。価格は2021年6月20日時点Amazonでの価格(値引含む)となります。

f:id:tara-chang:20210620225725p:plain
各社バッテリー電源の価格と容量の関係

バッテリーの容量は価格に綺麗に比例していることが分かります。容量が大きいバッテリーはその分高価ということですね。

f:id:tara-chang:20210620225644p:plain
各社バッテリー電源の価格と電力の関係

一方で電力はもその様な傾向ですが、容量よりはばらつきが大きいようです。単純に比較するとJackeryは値段の割に電力が低く、Somikon、EF Ecoflow、BALDRなどは値段の割に電力が大きいということが分かります。Jackeryはレビュー数、レビュー内容から見ても評価の高い商品のイメージがありますが、単純な電力や容量の数値面では他の製品に劣っていることが分かりました。

電力・容量はどれくらいがいいのか?

まず停電の際にどのように非常電源を運用するかを考える必要があります。まず私の家庭で主に使用する電化製品の消費電力を調べてみました。

機器 消費電力[W] 1回使用時の消費電力(Wh)
スマホ充電
10
10 (1時間使用時)
冷蔵庫
29
--
扇風機
42
--
140
66 (カタログ値)
炊飯器(3合)
350
105 (カタログ値)
テレビ(55インチ)
352
--
電子レンジ
600
53 (5分使用時)
トースター
1000
83 (5分使用時)
980
850
1000
83 (5分使用時)

※冷蔵庫は1年あたりの消費電力から算出しているので、連続運転が前提になります。
さて非常時にどこまで家電を動かす必要があるでしょうか?電子レンジを動かすことが出来れば冷凍食品を食べることが出来ますが、ある程度はカセットコンロで代用することも可能です。
とりあえず「スマホ充電器」「炊飯器」「扇風機」辺りまでが動けば良しとしましょう。となると300Wくらいは必要になるものと思います。逆に500Wとかではオーバースペックになってしまうと思われます。価格と電力のバランスがちょうどいいのが300W付近と思われます。

結局

疲れてしまったので、結論です(;・∀・)。BALDRの330W, 288Whを購入しました。安価な割に電力、容量ともに優れた良コスパ品です。サポートが手厚そうであることや、液晶に充電・使用の電力が表示されることも決め手となりました。

使用感

扇風機が動くことは確認しましたが、炊飯器は動くのか、試したら追記します。

【Arduino MIDIドラムシーケンサ⑥】16分対応

ドラムシーケンサの続きです。8分だけではかなり単調なパターンしか演奏できないので、16部対応させてみました。好きなドラムパターンを再現できるのは楽しいですね。メトロノームの代わりに使うと楽しいです。

スケッチ

// Arduino MIDI Drum sequencer 
// Sending MIDI messages to the host PC.
// DAW: Waveform Free
//
// Author: Tara-chang
// 
// Revision History:
// Date        |    Author    |  Change
// ---------------------------------------------------
// 2021-05-09  |  Tara-chang  |  Initial Release
// 2021-05-09  |  Tara-chang  |  Added LCD and Trimpot to tempo control 
// 2021-05-16  |  Tara-chang  |  Added BUTTONS to change channel 
// 2021-05-19  |  Tara-chang  |  Sixteenth note available 


#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include <MIDI.h> 
MIDI_CREATE_DEFAULT_INSTANCE();

#include <avr/io.h>
#include <avr/interrupt.h>

#define CRUSH 49 //C#3
#define KICK 36 //C2
#define CLAP 39 //D#2
#define SNARE 38 //D2
#define RIDE 51 //D#3
#define HITOM 50 //D3
#define MIDTOM 48 //C3
#define LOWTOM 45 //A2
#define OPHIHAT 46 //A#2
#define CLHIHAT 42//F#2

byte DRUM[] = {SNARE, KICK, CLHIHAT, OPHIHAT, CRUSH, RIDE};
byte VELOCITY[] = {127, 100, 70, 70, 60, 60};
int BPMLIST[] = {175, 146, 150, 133, 150};
const byte NUM_DRUM = sizeof(DRUM)/sizeof(DRUM[0]);
const byte NUM_BEAT = 16;

boolean RTM0[NUM_DRUM][NUM_BEAT] = {
 //1   2   3   4   5   6   7   8
  {0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},//SNARE
  {1,0,0,0,1,1,1,0,1,0,0,0,1,1,1,0},//KICK
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CLHIHAT
  {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0},//OPHIHAT
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CRUSH
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}//RIDE
  };

boolean RTM1[NUM_DRUM][NUM_BEAT] = {
 //1   2   3   4   5   6   7   8
  {0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},//SNARE
  {1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0},//KICK
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CLHIHAT  
  {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0},//OPHIHAT
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CRUSH
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}//RIDE
  };

boolean RTM2[NUM_DRUM][NUM_BEAT] = {
 //1   2   3   4   5   6   7   8
  {0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},//SNARE
  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},//KICK
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CLHIHAT
  {1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},//OPHIHAT  
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CRUSH
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}//RIDE
  };

boolean RTM3[NUM_DRUM][NUM_BEAT] = {
 //1   2   3   4   5   6   7   8
  {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},//SNARE
  {1,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0},//KICK
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CLHIHAT
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//OPHIHAT  
  {1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},//CRUSH
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}//RIDE
  };

boolean RTM4[NUM_DRUM][NUM_BEAT] = {
 //1   2   3   4   5   6   7   8
  {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},//SNARE
  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},//KICK
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//CLHIHAT
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//OPHIHAT  
  {1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},//CRUSH
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}//RIDE
  };

byte nt = 0;
byte in = 0;
byte i = 0;
byte BPM = 0; //X beats/60sec = 60/X sec/beat
byte interval;// = 60/double(BPM)*(4/double(NUM_BEAT))*1000; // 

boolean changed = 1;
byte CHANNELS[] = {0, 1, 2, 3, 4};
byte BUTPIN[] =   {4, 5, 6, 8, 7};
byte LEDPIN[] =   {9,11,12,13};

const byte NUM_CHANNELS = sizeof(CHANNELS)/sizeof(CHANNELS[0]);
const byte NUM_BUTPIN = sizeof(BUTPIN)/sizeof(BUTPIN[0]);
const byte NUM_LEDPIN = sizeof(LEDPIN)/sizeof(LEDPIN[0]);

byte NEXT_CHANNEL = 1;
byte CHANNEL = 0;
byte BUTTON_INT0 = 2;
byte BUTTON_INT1 = 3;

byte firstline;
byte secondline;
byte nowchannel;

void setup()
{ 
  Serial.begin(115200);
  MIDI.begin(4); //

  for (i=0;i<NUM_BUTPIN;i++){   
    pinMode(BUTPIN[i], INPUT);
    digitalWrite(BUTPIN[i], HIGH);     
  }
  for (i=0;i<NUM_LEDPIN;i++){   
    pinMode(LEDPIN[i], OUTPUT);
    digitalWrite(LEDPIN[i], LOW);     
  }
  
  lcd.init();
  lcd.backlight();
  lcd.clear();

  pinMode(BUTTON_INT0, INPUT);
  digitalWrite(BUTTON_INT0, HIGH);    // Enable pullup resistor
  pinMode(BUTTON_INT1, INPUT);
  digitalWrite(BUTTON_INT1, HIGH); 
  
  EICRA |= (1 << ISC01);    // Trigger on falling edge
  EIMSK |= (1 << INT0);     // Enable external interrupt INT0 = pin2
  EICRA |= (1 << ISC11);    // Trigger on falling edge
  EIMSK |= (1 << INT1);     // Enable external interrupt INT1 = pin3
  sei();                    // Enable global interrupts

}

ISR(INT0_vect)//pin2
{
  BPMLIST[CHANNEL]++;
  changed =1;      
}

ISR(INT1_vect)//pin3
{
  changed =1;
  BPMLIST[CHANNEL]--;      
}


void loop(){    
  for (nt = 0; nt < NUM_BEAT; nt++){
    digitalWrite(LEDPIN[nt/(NUM_BEAT/4)], HIGH);
    for (in = 0; in < NUM_DRUM; in++){    
           
      if (GetRTM(CHANNEL, in, nt)){
      MIDI.sendNoteOn(DRUM[in],VELOCITY[in],1);  // (pitch, velocity, channel)         
      MIDI.sendNoteOff(DRUM[in],0,1);   //        
      }
    }
    NEXT_CHANNEL = Getchannel(CHANNEL);
    if((changed)){
      LCDisplay(BPMLIST[NEXT_CHANNEL],NEXT_CHANNEL);
      changed=0;
    }
    delay(interval);
    digitalWrite(LEDPIN[nt/(NUM_BEAT/4)], LOW);     
    }

  BPM = BPMLIST[NEXT_CHANNEL];
  interval = 60/double(BPM)*(4/double(NUM_BEAT))*1000;
  CHANNEL = NEXT_CHANNEL;            
}

byte Getchannel(byte oldchannel){
    for (i=0;i<NUM_BUTPIN;i++){
      if ((digitalRead(BUTPIN[i])==LOW)){
        nowchannel = CHANNELS[i];
        changed=1;
      }
      else{
      }    
    }
    return nowchannel;
}

boolean GetRTM(byte nowchannel, byte in, byte nt){
    if(nowchannel==0){return RTM0[in][nt];}
    else if(nowchannel==1){return RTM1[in][nt];}
    else if(nowchannel==2){return RTM2[in][nt];}
    else if(nowchannel==3){return RTM3[in][nt];}
    else if(nowchannel==4){return RTM4[in][nt];}
    else{return 0;}
}

void LCDisplay(byte firstline, byte secondline){
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Tempo:"+String(firstline));
    lcd.setCursor(0, 1);
    lcd.print("Ch:"+String(secondline));
}

動作

毎度ながら音小さめです。

課題

0,0,0…と数字が並んでると可読性、デバッグ性が悪いですね…。4分ごとにカッコで囲むとか出来たら良い感じだと思いますが、そこまでやるかはわかりません。32部以上とか2小節以上の対応はしたいですね。いちいちDAWを起動するのは面倒ですがギター・ベース練習用のドラムマシンとして使えそうではあります。