🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

2回答

648閲覧

データの取得方法についてのプログラム

Yokkii

総合スコア2

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2021/01/29 08:02

編集2021/02/03 12:42

わからないことは聞いて解決するもよし、自分で解決するのもよし
うまいこと利用して勉強するべし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2021/01/29 12:09

全体的に妥当かざっくりと考えるのに、そもそも何を測定してどれだけデータを残せばいいのかを明らかにしてください。それを提示しないなら、「自分で考えて下さい」としかいいようがなくなります。 ・一回転のパルス数 ・一回転の時間(あるいはパルス間隔の時間) ・どれだけの連続したデータが取れればよいのか なんていうあたり。 > SDカードに保存する時間分だけ遅れが生じるが、何周分のデータも取れるのではないか そういう作りも出来なくはないですが、当然「一回転の時間」が「一回転分のデータをSDカードに書き込む時間」より長くなければいけません。もちろん、SDカードを書き込んでいる間にもデータ取得ができる構造にしなければいけません。そんなことを考えるためにも、各種パラメータが明らかになっていないと。 それともう一つ、micros()自体はunsigned longの値を返すかもしれませんが、パルス間隔は65ms以下で16bitデータで収まったりする、なんてことはありませんか? そうであれば、前回のパルスからの時間を求めることでおよそ倍のデータを蓄積できることになります。
thkana

2021/01/29 12:13

それと、コード部分を独立した行の```で ``` コード部分 ``` のように囲って下さい。コードが読みにくいので。
Yokkii

2021/01/29 13:13

回答していただきありがとうございます。 teratailの利用が今回で2回目で至らないところがあり、申し訳ありませんでした。 見やすく、改善いたしました
Yokkii

2021/01/30 03:58

ひとつお聞きしたいのですが、パルス間隔が65ms以下で16bitデータで収まっていると、なぜ倍のデータが取れるのですか?
thkana

2021/01/30 04:35

パルス一発目が時刻12345678だったとして、その次のパルスが12345778でした、というときに、 知りたいのがパルス間隔であればこの値を全て記録する必要はないですよね? バルス間隔が100だった、ということだけわかれば十分です。もし絶対時刻も必要なら最初の12345678を一つだけ覚えておけば、以下間隔が100, 105, 93, 104 ...というのだけ記録しておけば、12345678, 12345778, 12345871, 12345975 ...というのも導けます。 で、16bitあれば0~65535の値が表現できるので、65535μsは65.535ms、というそれだけの話です。 (もし、値のぶれが255以下であることが確かなら1byte=0~255の記録でもいいですけど...)
Yokkii

2021/01/30 05:20

わかりやすく説明していただきありがとうございます 理解できました! 変数の型をunsigned int型に変更すれば、条件を満たしている場合については倍のデータがとれますね! やってみます。ありがとうございました
thkana

2021/01/30 10:02

Arduino dueではunsigned intは32bit幅です。
Yokkii

2021/01/30 10:15

unsigned short intですね
guest

回答2

0

ベストアンサー

一回転が2秒ならかなりゆっくりですね。であれば、1回転したら直前の1回転分のデータをSDカードに記録するようにしてそれを9回繰り返す、と考えたほうが(3周分をまとめようとするよりも)ややこしくならないのではないかと思います。ただし、SDカードへの記録中も測定を止めてはいけない、というのが注意点。

データを貯めるエリアは2面(周)分もって、
パルスのエッジの記録は「割り込み」による。割り込みハンドラ内でmicros()の値を配列に保存
Z相が来たら記録面を切り替えて、記録済の面をSDカードに書き出す、とかいうところでしょうか。

(話だけでわかるか? とも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)


面倒といいながら、SD書き込み中にちゃんと割り込みがかかるか等、色々と気になったので作ってみました。ただし、ターゲットはArduino m0/PROで、そのままDueに持っていけるかどうかは知りません。どちらもATMELのARMだし、m0の方が低クロック少メモリなので期待は出来ますが。

動作チェックとして他のマイコンで2s/555μs/694μs(それぞれ設定値、パルス同士は同期をとっていません)のパルスを作ってそれを突っ込んで大体2.0002s/22b(555)~22d(557)/ 2b6(694)~2b7(695)ぐらいの値が出ているのでそこそこかと。

SDカードの書き出しは数字で打ちたかったのですが、2秒に確実に収まるとは言えない感じだったのでバイナリにしています。書き込み時間は200~500msぐらいでばらつきます。Dueの方がCPUが早いのでもしかしたら数字でも出せるかもしれませんが、SDのI/Fが律速しているのかも。

Arduino

1//Items.h 2#include <cstddef> 3#include <SD.h> 4 5class Items { 6 //バッファ管理変数 7 volatile unsigned short *buf[2]; 8//データインデックス管理 9 volatile size_t idx[2]; 10//データ最大数 11 size_t bufSize; 12//周数 13 volatile unsigned int round; 14//周の最初の立ち上がりエッジ保存 15 unsigned long t0[2]; 16//前回の立ち上がり時刻保存 17 volatile unsigned long tPrev[2]; 18//周の初回判定 19 bool start; 20 21 public: 22 Items(size_t ); 23//割り込みハンドラ本体 24 void handle(); 25//周送り処理 26 void turnRound(); 27//データ書き出し 28 void logWrite(File); 29};

Arduino

1//Itmes.cpp 2#include <Arduino.h> 3#include <cstddef> 4#include <SD.h> 5#include "Items.h" 6 7Items::Items(size_t sz) : bufSize(sz) { 8 start = false; 9 round = 0; 10 buf[0] = new unsigned short[bufSize]; 11 buf[1] = new unsigned short[bufSize]; 12}; 13 14//割り込みハンドラ本体 15void Items::handle() { 16 unsigned long tt = micros();//時刻取得 17 size_t rr = round % 2; //使用バッファブロック選択 18 if (!start) { //周の初回の処理 19 idx[rr] = 0; 20 t0[rr] = tt; 21 tPrev[rr] = tt; 22 start = true; 23 } 24 if (idx[rr] < bufSize) { //バッファに余裕あるなら 25 buf[rr][idx[rr]++] = tt - tPrev[rr]; //前回との差分値を保存 26 } 27 tPrev[rr] = tt;//今回値を保存(次回差分計算用) 28} 29 30//周送り 31void Items::turnRound() { 32 round += 1; 33 start = false; 34} 35 36//データ書き出し 37void Items::logWrite(File logFile) { 38 if (round > 0) { 39 size_t rr = (round - 1) % 2; 40 //前回の周の最初の立ち上がりエッジ時刻 41 unsigned long tmp = t0[rr]; 42 logFile.write((uint8_t*)&tmp, sizeof(unsigned long)); 43 //前回の周のデータ数 44 tmp = idx[rr]; 45 logFile.write((uint8_t*)&tmp, sizeof(unsigned long)); 46 //データ本体書き込み 47 for (unsigned int i = 0; i < idx[rr]; i++) { 48 unsigned short tmp; 49 tmp = buf[rr][i]; 50 logFile.write((uint8_t*)&tmp, sizeof(unsigned short)); 51 } 52 } 53}

Arduino

1//main.ino 2#include <SPI.h> 3#include <SD.h> 4 5#include "Items.h" 6 7typedef const int Pin; 8Pin PhA = 6; 9Pin PhB = 4;//m0のD2は割り込みを受けないみたいなので変更 10Pin PhZ = 5; 11 12//Z相読み出しのレイテンシを見込んで少し余裕を持たせる 13const int RATIOA = 2880 + 32; 14const int RATIOB = 3600 + 32; 15 16Items pha(RATIOA), phb(RATIOB); 17 18volatile bool isSDtriggered = false;//カード書き込みトリガ 19 20volatile unsigned int roundZ = 0;//回転回数 21volatile unsigned long bufZ[2];//Z相時刻 22 23File logFile; 24 25//A相割り込みハンドラ 26void handleA() { 27 pha.handle(); 28} 29 30//B相割り込みハンドラ 31void handleB() { 32 phb.handle(); 33} 34 35//Z相割り込みハンドラ 36void handleZ() { 37 if (isSDtriggered) { 38 return; //前の処理が終わっていない 39 } 40 bufZ[++roundZ % 2] = micros();//時刻記録 41 pha.turnRound();//A相次の周へ 42 phb.turnRound();//B相次の周へ 43 isSDtriggered = true;//一周回ったので記録開始(SD操作はmainコンテキストで) 44} 45 46void setup() { 47 Serial.begin(115200); 48 pinMode(PhA, INPUT); 49 pinMode(PhB, INPUT); 50 pinMode(PhZ, INPUT); 51 //各相割り込み設定 52 attachInterrupt(digitalPinToInterrupt(PhA), handleA, RISING); 53 attachInterrupt(digitalPinToInterrupt(PhB), handleB, RISING); 54 attachInterrupt(digitalPinToInterrupt(PhZ), handleZ, RISING); 55 56 if (!SD.begin(10)) { 57 Serial.println("SD initialization failed!"); 58 while (1);//カード初期化失敗したら停止 59 } 60 Serial.println("SD initialization done."); 61} 62 63void loop() { 64 if (isSDtriggered) { //SD書き込みトリガ掛かっていたら書き込み 65 if ( roundZ > 1&& roundZ<11) { //1周目完=2周目~9周目完=10周目のときSD書き込み 66 char fname[128];//ファイル名生成 67 68 Serial.println("SD start"); 69 sprintf(fname, "/enc/round%d.txt", roundZ - 1); //round周数.txt 70 Serial.println("File: " + String(fname)); 71 logFile = SD.open(fname, FILE_WRITE & ~O_APPEND); //ファイル先頭から書き込み 72 if (!logFile) { 73 Serial.println("File open error."); 74 while (1); //ファイルオープン失敗したら停止 75 } 76 unsigned long tmp = roundZ - 1; //現在(収集中)の前の周(収集完了)のデータ 77 logFile.write((uint8_t*)&tmp, sizeof(unsigned long)); 78 tmp = bufZ[(roundZ - 1) % 2]; 79 logFile.write((uint8_t*)&tmp, sizeof(unsigned long)); 80 pha.logWrite(logFile); //A相データ書き込み 81 phb.logWrite(logFile); //B相データ書き込み 82 logFile.close(); 83 Serial.println("SD done"); 84 } 85 isSDtriggered = false; 86 } 87} 88/*ファイルフォーマットは 89 * 4byte 周ナンバー 90 * 4byte Z相立ち上がり時刻(micros値) 91 * 4byte A相立ち上がり時刻(micros値) 92 * 4byte A相データ数 93 * 2byte x データ数 A相間隔データ 94 * 4byte B相立ち上がり時刻(micros値) 95 * 4byte B相データ数 96 * 2byte x データ数 B相間隔データ 97 */

投稿2021/01/30 05:14

編集2021/01/31 13:23
thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yokkii

2021/01/30 05:30

回答していただきありがとうございます おっしゃっていることは理解できますし、3回転ごとにまとめるより1回転ごとの方がよさそうですね 今の自分の実力ではここまでのプログラムは書けそうにないので、他の方法でやるしかないかなと思ってます。 力がつけばチャレンジしてみたいと思います。 ありがとうございました
Yokkii

2021/02/01 06:37

回答していただきありがとうございます プログラムの理解をして、実際に試してみたいと思います。 うまくいけば後々報告させていただきます
guest

0

エンコーダのパルスをカウントして、3周分のパルスカウントで保存する、ということになろうかと思います。

投稿2021/01/29 08:11

y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問