メモではあるが、注射器の接続部分に使われていたISO594/1の規格を参照している。現在ISO594は廃止された規格だが、多分現在のISO80369に引き継がれている、、に違いない。ISO80369は形状違いで注射用、麻酔用などが別れているが、未確認です。
ISO594/1では0.06のテーパーの直径約4mmの形状が使われているようです。
とりあえず、寸法のメモ。テーパー6/100で作っておけば入りそう。
メモではあるが、注射器の接続部分に使われていたISO594/1の規格を参照している。現在ISO594は廃止された規格だが、多分現在のISO80369に引き継がれている、、に違いない。ISO80369は形状違いで注射用、麻酔用などが別れているが、未確認です。
ISO594/1では0.06のテーパーの直径約4mmの形状が使われているようです。
とりあえず、寸法のメモ。テーパー6/100で作っておけば入りそう。
時々使っているマイコンのADCは10bitなので1024段階(0-1023)での出力が得られるが、時間応答を犠牲にしてももうちょっと分解能を高くしたいときがある。温度計とか。
ArduinoではAnalogRead(A0)といった関数でA0端子のアナログ値を得られるのでコレを使って書くと、
ADC = r* ADC + AnalogRead(A0);
という加算をしていくと、ADCの値にはAnalogRead(A0)/(1-r)の値が入るので、コレをつかうことでADCの見かけ上の分解能を増大させることができる、はず。
解説:
ADC += AnalogRead(A0);
というコードを書くとADCの値は無限に増大していく。なので、ある程度値を抜いてやると値がある値に収束するであろうことがわかる。
例えば、
ADC = 0.9*ADC+AnalogRead(A0);
と計算をすると、現在の加算値の0.9倍に読み取りの値を加算するので、感覚的に、AnalogRead(A0)の10倍の値に収束する感じがわかる。
で、0.9のところをr(0<r<1)にして見ると、
ADC = r*ADC + AnalogRead(A0);
で、AnalogRead(A0)の値が一定で、ADCが一定にに収束した状態では、左辺と右辺が等しいので、
(1-r)*ADC = AnalogRead(A0)となり、ADC = AnalogRead(A0) / (1-r)となる。
r=0.9の場合が、上の例なので、そのとおりである。
次に、マイコンの演算として浮動小数点演算は重い場合があるので、ビットシフトで除算相当をやるといいのではないだろうかと思うと・・・・
r=3/4, 7/8, 15/16, 31/32といった(2^n-1)/2^nという値にするとビットシフトで計算できて良いのではと思う。
実際には、
ADC = ADC - ADC>>4 + AnalogRead(A0);
とやると、4bitシフトなので、ADC*(1-1/16)+AnalogRead(A0)という演算と等価のはず。
と、ここまで思ったが、四捨五入問題どうなるんだろうか?
16>>4は1なので16で割ってもビットシフトしても同じ値。
24>>4はやはり1ではあるものの、24/16=1.50なので、四捨五入を食らってしまうので値がずれる。
少数第一まで計算するので、例えば4ビットシフトは16で除算、なので16の半分の8を加算してからビットシフトするとちょうど良くなるのでは無いだろうか。
そうすると、ビットシフト量をsとすると、次のような演算をするのが四捨五入にも対応するようだ。きっとsは固定値だからコンパイラがうまく処理してくれるだろう。
ADC = ADC - (ADC + 2^(s-1))>>s + AnalogRead(A0);
これが、読み取り値の、2^s倍の値になっていることにだけ気をつけたらいい。
10進数でも全くおなじことが言える。
1025を100で割ったら10.25で四捨五入して整数にすると10
1051を同上で11
除算前に四捨五入相当するとなると、除算する100の半分の値の50を加算しておいてから100で割って切り捨てると同じことになる。
ArduinoIDEでプログラムを作っていると、AD変換の時間とか余り意識しないのだが、一体どの程度の時間で処理できるのかと気になった。
一回あたりは早いだろうから、10000回ループさせて出力させてみたところ、10000回で1120msという結果。
つまり、一回あたり、0.112msでADCが完了するということである。サンプリング速度はだいたい9kHzか。
十分な速度である。気になるのは、シリアル通信しているあいだCPU待ってるんじゃないかと思うところかな。こういう細かいところを考えるとArduinoでは難しいのかもしれないが、簡単に作れるのがArduinoなので、このへんはしょうがない。
プログラム:
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
long ADCValue;
int LevegGaugeValue;
ADCValue=0;
for(int i=0;i<10000;i++){
ADCValue += analogRead(A0);
}
Serial.print(ADCValue);
Serial.print(",");
Serial.println(millis());
}
10回平均にして115200bpsで読み込むとこんな感じでハムノイズっぽいのが拾えているようである。
SparkFunというところのProMicroのクローンがAliexpressで安価に出ている。
621円で購入したものを使って見る。もはや書き込みとか含めてマイコンボード使ってしまったらプロトタイプはそれでいい気がする。裸のマイコンでもいいのだが、USBで指すだけで書き込みとかできる便利さがよい。
で、7セグのドット意外の端子を使うので、8bitが割り振られているポートを探す。
AD変換はPortFというもののようだ。デジタルピンはD0からD17まであるが、ポートフルで引き出されているものはないようだ。7bit分は一つのポートで確保できず、PB1〜PB6の6bit分とどこかで1bit確保といった感じになりそうである。
PB0:外部引き出しなし(TX LED)
PB1:D15
PB2:D16
PB3:D14
PB4:D08
PB5:D09
PB6:D10
PB7:外部引き出しなし!
PD0:D03
PD1:D02
PD2:D00(RXI)
PD3:D01(TXO)
PD4:D04
PD5:外部引き出しなし
PD6:外部引き出しなし
PD7:D06
で、仕様を考えていこうかと。
将来2桁表示になったときに対応できるように、アノードを2ch割り振っておく。2chとも一つのLEDに接続したら1桁表示と思ったのだが、ダイナミック点灯を1桁でやるとまず読めたものでは無いので、無理だった。
全体のアルゴリズムとしてはこんな感じでしょうか。待機時間を延々AD変換させまくってもいいのですが、余り意味がありませんので、そのままです。
for(){
・AD変換する
・1-5Vに対応する値を0-99に割り付ける
・10の位(10で割った商)を表示する(0.5s)
・消灯0.1s
・1の位(10で割った余り)を表示する(0.5s)
・消灯0.5s
}
では7セグのマップを作っていきませんといけません。
追記予定
試しにデジタルストレージオシロのデータを吐き出させてみた。
ストレージ12Mポイント。特にこの時点で何も考えてなかった。
吐き出しにかなりの時間がかかってようやく完了。
どんだけでかいんだよ、と思いつつ、あれ?測定点が12Mってことは、1200万行のcsvファイル?
ちゃんと1200万行ありました。エクセルが最近行数増えたとはいえ、100万行なので全部表示できない。
ヘッダはあるものの、文字数は、時間のインクリメント分で8文字、カンマが2文字、浮動小数点が8文字、合計18文字と改行コードで20バイト/行くらい。これが12Mポイントで、240MBくらいとちょうどリーズナブルなサイズ。
この行数には素直にびっくりだよ。
使い勝手の都合、メモリデプスをAutoにしておくと垂直方向の動きが遅い(カクカクどころか、1fpsくらいでしか動かない)のだが、メモリーデプスをAutoから軽くしておいたほうがいいかもしれないな。
垂直分解能8bitのオシロだと、単純にメモリーレコード数=DRAMに必要なメモリーだと思うので、12Mポイント分のストレージだと12MBでしか無いとは思うが色々CPUやらのリソースの都合はあるんだろうな。安価なオシロなのであまり多くを求めるのも酷であろう。スマホより安いくらいだし・・・
6.5桁のDMMを買ってしまった。ヤフオクで32,000円なり。
先に買ったR6452よりも高速なAD変換なのでSlowの測定でも十分な測定速度を誇っているように思う。
充電前のNiMH電池の電圧は1uVまで表示可能。
Raspberry Piというシングルボードコンピュータが発売されて久しいが、このラズベリー財団がRP2040というマイコンを売り出して若干気になっていたのだが、ヘタをすると8bitマイコンより安いので、これはと思って買ってみた。
AtmelのATMega32u4のボードは1250円くらいだったのだが、RP2040Zeroというボードは400円+送料140円くらいだった(Aliexpressで)。
Type-Cの端子で、多分表についているのグラッシュメモリ、裏のがマイコン。
はじめは表の写真だけみでやけに入出力ピンの少ないマイコンだなと思ってたが、そんなことは無かった。裏面にでかいのあった。
CPU:Cortex M0+ 133MHzマイコン デュアルコア
メモリ:264kB
フラッシュ:外付け2MB
その他色々。
133MHzのデュアルコア、メモリがちょっと少ないけど相当色々できそうだな。
最近データロガーとか欲しいのだが、16bit ADCとRTCなんかをつないでやったら自分でできそうだな。きっとmicroSDカードへの書き込みなんかもできるだろう。
現状ではArduinoの開発環境でやっているが、MicroPythonでもできるらしい。
MAX3232というICがある。チャージポンプ回路を内蔵し、TTLレベルから真のRS232Cレベルに変換してくれるIC!!
ナイス!名前からしてマキシム・インテグレーテッドだろうとおもったら、Analog Devicesが買収していた。リニアテクノロジーもまさかの買収されたとおもったら、こっちもか。
さて、それはおいておき、このMAX3232を搭載したものが非常に安価で販売されている。
RS232Cコネクタ付いて48円??え?
Amazonでも5個で750円?
買ったのだが、買ってから気がついた、これメスコネクタ?装置はオスコネクタで、えーっと?クロスケーブルがいいのかストレートケーブルがいいのか判断できないぞ?ちょっと配線図を確認しないといけないですね。
かk人すると、、、ICのレシーバーRXが3ピン、トランスミッターTXが2ピンという配置のようだ。
今回ターゲットにしている電子天秤はA&Dのものなので、、例えばGH-252の取説を見ると2が、ん?Rxが送信データ?ん?レシーバーでRx、トランスミッタでTxだとおもったが、どうなってるんだろう?接続相手の配線を書いているのだと思うのだが・・・また検討しようと思います。
Arduino Pro MicroというATMega32U4というUSBがそのあま接続できるマイコンボードを買った。
アマゾンで2つで2500円くらい。
サイズが小さくて、特定の目的のために使うものならば結構使い勝手がいいのではないだろうか。
マイコンに書き込むプログラムは下記のようなもの。
A&Dの電子天秤はRS232Cが2400baudがデフォルトのようなので、2400baudでやっている。あれ、パリティーとかストップとか7bit 8bitとかそのへんどうなってんだろ?多分世の中のメジャーな設定になっているはず。
#include "Keyboard.h"
void setup() {
// open the serial port:
Serial.begin(2400,SERIAL_7E1);
// initialize control over the keyboard:
Keyboard.begin();
}
void loop() {
// check for incoming serial data:
if (Serial.available() > 0) {
// read incoming serial data:
char inChar = Serial.read();
Keyboard.write(inChar);
}
}
しかし、肝心の電子天秤が今ないので、一旦作業は保留。さてうまく通信できるかな。
そして、次の疑問。RS232Cって何ボルトの電圧振幅必要なのかな??
今使っているOSがUbuntuなので、Windowsとはちょっと違う認識方法だが、うまく行っている様子。
Bus2にデバイス8としてArduinoがぶら下がっているようだが、CDC_ACM, HIDの2パターンで認識されていて、Arduino IDEなどからはおそらくシリアルポート越しの書き込み、HIDデバイスはHIDデバイスとして書き込まれるのかな、なんて思っている。
$ lsusb Bus 002 Device 008: ID 2341:8036 Arduino SA Leonardo (CDC ACM, HID) Bus 002 Device 004: ID 045e:0039 Microsoft Corp. IntelliMouse Optical Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 001 Device 003: ID 5986:051b Acer, Inc Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ lsusb -t /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M |__ Port 2: Dev 4, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 3: Dev 8, If 2, Class=Human Interface Device, Driver=usbhid, 12M |__ Port 3: Dev 8, If 0, Class=Communications, Driver=cdc_acm, 12M |__ Port 3: Dev 8, If 1, Class=CDC Data, Driver=cdc_acm, 12M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M |__ Port 2: Dev 3, If 0, Class=Video, Driver=uvcvideo, 480M |__ Port 2: Dev 3, If 1, Class=Video, Driver=uvcvideo, 480M
HIDデバイスのコードを書き込んだデバイスであっても接続すると、シリアルポートの書き込み先にデバイスが出てくる。
ふと思ったが、キーを適当に叩くようなプログラムを入れておけば良かったんじゃないだろうか。よしやってみよう。
デバイス認識に時間かかりそうだから、5秒待たせて出力。
できた。この機能、シリアル通信の中身をテキストファイルに吐き出すのにも少し便利かもしれない。
いや、シリアル-USB変換使ってTeraTermとかで受信したらそれでOKかもしれないけど。
Keyboardには次の関数があるらしい。
Keyboard.begin()
Keyboard.end()
Keyboard.press()
Keyboard.print()
Keyboard.println()
Keyboard.release()
Keyboard.releaseAll()
Keyboard.write()
文字だが、あくまでもHIDデバイスなので送信できる文字に制約がある。Shiftを押して操作みたいなこともできるが、処理が煩雑になるので一旦は数字の伝送に専念してみる。
例えば、
+-,.0123456789abcdefghijklmnopqrstuvwxyz<>?_/ という文字を送信すると
~-,.0123456789abcdefghijklmnopqrstuvwxyz<>?=/ という文字になって返ってくる
+の記号がうまく処理できていないことがわかる
なんでだろうかと調べてみると、日本語キーボードと英語キーボードの配置が違う生だったようだ。
日本語キーボードに慣れないかと思って調べたらやっているひとがいた。
が、どうやったらいいのかわからないので色々調べている。
電子天秤など、読み取りボタンを押すと測定データをRS232Cから出力するものが結構ある。
便利な端子ではあるが、今どきだとUSB-RS232C変換ケーブルをさしてドライバをインストールして・・・面倒臭い。
ミツトヨのビッカース硬さ試験は読み取り値をPCに転送するとき、USB HID(Human Interface Device)のキーボードに扮してくれるので接続してすぐ使えるというメリットがある。
このモデルはすでにArduinoの標準にあるっぽい。
https://docs.arduino.cc/built-in-examples/usb/KeyboardSerial
マイコンにはUSB HIDに化けてくれるものがあるし、シリアル通信に対応したものがあるので、これ自分で作れるんじゃないか?というように思った次第。→作った
例えば電子天秤の場合、読み取った値をそのままHIDデバイスとして吐き出せばいいので、すが、
A&Dのフォーマットを見ていると標準だと、Stable, Unstableとかヘッダ、カンマ、測定値、スペース、単位、CRLFになっているようだ。面倒くさいな。
ただ、SIF TYPE4はNumericalフォーマットなのであろう、数字をバコーンと出すだけなので、液晶画面に表示サれている数字をそのまま吐き出すだけ。これなら、マイコンはシリアル通信で受け取った文字列をHIDデバイスとして吐き出して行けばいいだけである。
AandDの天秤は下記の状態がデフォルトの状態のようだ。
ボーレート:2400bps
ビットパリティ:7ビットEven
ターミネータ:CRLF
データフォーマット:A&D標準フォーマット(上記のST,+2.300000 g CRLF)
さて、データが7bitって何?って思ったのだが、アスキーコードが7bitなので、英語文字列を送るだけなら7bitで十分な様子。
ということは、マイコンのシリアルポートは、
Serial.begin(2400,SERIAL_7E1)
ということになる。
MPLABX 5.45のtarファイルが解凍でエラーになる。予期しないEOFって。
MPLABX5.40は無事に解凍できて、インストールできそうな予感。
8bitマイコンにAVRも含まれるだろうか。
AVRの開発環境はATMEL Studioしかないのかと思いつつ、マイクロチップに買収された後にどうなっているのかあまりウォッチしていなかったが、今月号のトランジスタ技術がAVRマイコン特集だったので、買って読んでみるとどうやらマイクロチップの開発環境でもAVRの開発が十分にできるようだ。
そして、今まではデータシートとにらめっこして面倒くさかったレジスタ設定が多少楽になっているらしい。
さらに、開発環境はLinuxにも対応しているようなので、現在主に使っているUbuntuのノートPCでも動くかもしれないという期待感。
AVRマイコンも新しい世代が出てきているようで、ATTiny13Aとう50円マイコンは秋月電子で在庫切れ。ATTiny202という40円のマイコンも登場しており、Tiny202は新世代製品らしい。ADCとか速くなっているので使いどころがあれば使ってみようかな。
ATTiny10も小さくていいが、小さすぎて困る。
異物認識をする上でまずは認識するところから。
昨日Anaconda(Python)をインストールして、openCVもインストールして使ってみたが、そこそこいい感じである。
Pythonのプログラムは多少の慣れが必要だろうが、openCVはできることが多すぎてインターネットにある情報のコピペでなんとかしていく感じ。
Pythonも繰り返しの動作とか、どうするのかと思ったら、
for i in range(10)
がfor(i=0;i<10;i++)に相当するものだった。かんたんなような簡単でないような・・・
MPL3115A2を使う上での注意点をまとめる。またArdunoでデータを送出してパソコン側ではProcessingというソフトでデータを受信し、テキストファイルに保存する。
MPL3115A2は上のように実装、ちょっとホコリがたまっちゃった。奥に見える基盤は5VのArduinoと3.3VのMPL3115A2のレベルシフタ。
Arduino側プログラム
#include
#include
#define OverSample 128.0 //デジタルフィルタの定数として
#include "SparkFunMPL3115A2.h" //どこかから適当に手に入れてくれ
//Create an instance of the object
MPL3115A2 myPressure;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
float Altitude = 0;
float Ondo = 0;
float Pressure = 0;
float tempAltitude = 0;
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
//timer割り込み設定
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 <
OCR1A = 312500-1;
TIMSK1 |= (1 <
lcd.clear();
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("Hello! Wait!");
lcd.setCursor(0,1);
lcd.print("OverSample:");
lcd.print(OverSample);
Wire.begin(); // Join i2c bus as Master
myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
myPressure.setOversampleRate(7); // Set Oversample to the recommended 128
myPressure.enableEventFlags(); // Enable all three pressure and temp event flags
}
void loop(){
myPressure.begin(); // Get sensor online
//はじめに10回くらい測定を読み捨ててみる。意味があるかはわからない。初期値が怪しいときがあるので。
for(int i = 0; i
Pressure = myPressure.readPressure();
Ondo = myPressure.readTemp();
}
while(1){
float ReadPressure; //読み取った圧力
float ReadOndo; //読み取った温度、Tempは別で定義があるようなのでOndoにしています。
ReadPressure = myPressure.readPressure();
ReadOndo = myPressure.readTemp();
Pressure = Pressure * (OverSample-1)/OverSample + ReadPressure/OverSample;
Ondo = Ondo* (OverSample-1)/OverSample + ReadOndo/OverSample;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(Ondo, 1);
lcd.print("C ");
lcd.print(Pressure, 1);
lcd.print("Pa");
lcd.setCursor(0,1);
lcd.print(ReadOndo, 2);
lcd.print(" ");
lcd.print(ReadPressure, 2);
Serial.print(ReadOndo,3);
Serial.print("\t");
Serial.println(ReadPressure,2);
}
}
ISR(TIMER1_COMPA_vect) {
digitalWrite(13, !digitalRead(13)); //特に意味もなくLEDを光らせる
}
液晶モニタにも表示させているのでLCDのライブラリと書き込みを使っています。
液晶画面には上のように表示しています。
Processing側プログラム
import processing.serial.*;
PrintWriter file;
Serial myPort; // set Serial port to
String inString; // string to read from serial port
int lf = 10; // ASCII \n
int UpDate = 0; //set 1 when minute changed while serial interrupt
int DataCount = 0;
int TempMin;
double OndoSummary =0; //倍精度にしないと気圧の有効数字が怪しい気がした(温度は大丈夫だと思うが)
double PressureSummary =0; //同上
void setup() {
file = createWriter("balomatic_tester"+nf(year(),4)+nf(month(),2)+nf(day(),2)+"_"+nf(hour(),2)+nf(minute(),2)+".log");
size(200,200);
printArray(Serial.list());
myPort = new Serial(this,Serial.list()[1], 9600); //list()[1]の数値はArduinoの接続先に依存します。
myPort.bufferUntil(lf);
TempMin = minute();
}
void draw() {
if(UpDate == 1){
UpDate = 0;
String now;
now = nf(year(),4)+"/"+nf(month(),2)+"/"+nf(day(),2)+" "+nf(hour(),2)+":"+nf(minute(),2)+":"+nf(second(),2)+"\t";
file.print(now);
file.print(nf((float)(OndoSummary/DataCount),2,3));
file.print("\t");
file.println(nf((float)(PressureSummary/DataCount),2,3));
file.flush();
OndoSummary = 0;
PressureSummary = 0;
DataCount = 0;
}
}
void serialEvent(Serial p) {
inString = p.readString(); //read String from Serial Port
String SplitedData[];
SplitedData = split(inString, "\t"); //Split data to temperature and pressure(or altitude)
OndoSummary += float(SplitedData[0]); //temperature summary like \Sigam(temperature)
PressureSummary += float(SplitedData[1]); //pressure summary like \Sigma(pressure)
DataCount++; //Average temperature or
String now;
now = nf(year(),4)+"/"+nf(month(),2)+"/"+nf(day(),2)+" "+nf(hour(),2)+":"+nf(minute(),2)+":"+nf(second(),2)+"\t";
print(now);
print(nf(float(SplitedData[0]),2,3));
print("C ");
print(nf(float(SplitedData[1]),6,2));
print("Pa ");
print(nf(DataCount,3,0));
print(" ");
print(nf((float)(OndoSummary/DataCount),2,3));
print(" ");
println(nf((float)(PressureSummary/DataCount),2,3));
// file.print(now + inString);
if(TempMin != minute()){
UpDate=1;
TempMin = minute();
}
}
void keyPressed(){
println(key);
if(key == 'f'){
file.flush(); //fキーを押したらファイルに書き込み(もうほとんどいらない)
}
else if(key == 'q'){
file.flush();
file.close(); //qキーを押したらファイルに書き出して、ファイルを閉じてプログラムストップ
exit();
}
}
とりあえずこんな感じで動いているようです。
日毎にデータファイルを分けてもいいかもしれません。