回答編集履歴
5
修正
test
CHANGED
@@ -150,13 +150,13 @@
|
|
150
150
|
|
151
151
|
完成寸前まで作っちゃったんで載せときます。nac_tnkさんのタイマー版をベースにしてます。1度単位での制御はソフトループだと苦しいので。
|
152
152
|
|
153
|
-
制約として、①の前半と後半の立ち上がり間隔が、①の
|
153
|
+
制約として、①の前半と後半の立ち上がり間隔が、①の後半の立ち上がりと②の立ち上がりの間隔より短い必要があります(パルス全体の幅と切れ込みの入れ方によってはその関係は崩れます)。「一番短い立ち上がり間隔」を①の検出の要件としましたので。図が現物通りなら特に問題ないでしょう。
|
154
154
|
|
155
155
|
あまり明確にかかれていませんが、LEDの点灯開始は各パルスの立ち上がりと勝手に解釈しました。
|
156
156
|
|
157
157
|
|
158
158
|
|
159
|
-
LED制御ぐらいは自分でやって下さい。そもそもの質問の①を知ることはできているはずなので。
|
159
|
+
LED制御ぐらいは自分でやって下さい。そもそもの質問の「①を知る」ことはこれでできているはずなので。
|
160
160
|
|
161
161
|
|
162
162
|
|
4
画像追加
test
CHANGED
@@ -355,3 +355,5 @@
|
|
355
355
|
}
|
356
356
|
|
357
357
|
```
|
358
|
+
|
359
|
+
![実行結果](a7af8ba67ab56a12b49d386f65e81894.png)
|
3
これで最後、かな?
test
CHANGED
@@ -119,3 +119,239 @@
|
|
119
119
|
|
120
120
|
|
121
121
|
羽根3枚を検出しないといけない状況があるのでしょうか? それこそ羽根の隙間を狙わなきゃいけない、とかだと真面目に羽根を検出したほうがいいかも知れませんが。
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
---
|
126
|
+
|
127
|
+
質問情報の追記をうけての追記
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
> 例えば1の羽根が90度の位置に来た時にLEDを点灯させるという感じ
|
132
|
+
|
133
|
+
消灯のタイミングはパルス幅の真ん中に来た時です
|
134
|
+
|
135
|
+
|
136
|
+
|
137
|
+
とか、「どこにいっちゃったんだぁ?」と思いますけれど。
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
> 回転スピードは一定していません。
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
とかのびっくりネタはもう隠していませんか?
|
146
|
+
|
147
|
+
10倍のダイナミックレンジってのは結構インパクトありますよ。最初に「どのくらいの時間をみているのか」と聞きましたよね? なぜかというと、それが設計の基本的なところで押さえるべきパラメータだからです。そこを、最初に言った9msから平気で120msまでしかも可変で引っ張る、なんていうのは、「バカにしている」と怒られても文句は言えないレベルです(怒らないけど思ってます)。
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
完成寸前まで作っちゃったんで載せときます。nac_tnkさんのタイマー版をベースにしてます。1度単位での制御はソフトループだと苦しいので。
|
152
|
+
|
153
|
+
制約として、①の前半と後半の立ち上がり間隔が、①の終わりと②の始まり(②の終わりと③の始まり、③の終わりと①の始まり)より短い必要があります。「一番短い立ち上がり間隔」を1の検出の要件としましたので。図が正しいなら特に問題ないでしょう。
|
154
|
+
|
155
|
+
あまり明確にかかれていませんが、LEDの点灯開始は各パルスの立ち上がりと勝手に解釈しました。
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
LED制御ぐらいは自分でやって下さい。そもそもの質問の①を知ることはできているはずなので。
|
160
|
+
|
161
|
+
|
162
|
+
|
163
|
+
```Arduino
|
164
|
+
|
165
|
+
#include <limits.h>
|
166
|
+
|
167
|
+
const int LEDPORT[] = {11, 12, 13};
|
168
|
+
|
169
|
+
const int TM_STOP = 0;
|
170
|
+
|
171
|
+
const int TM_RUN = 0b11;
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
volatile bool roundComp;
|
176
|
+
|
177
|
+
|
178
|
+
|
179
|
+
void pulse_read() {
|
180
|
+
|
181
|
+
//立ち上がり位置の記録。
|
182
|
+
|
183
|
+
unsigned int edge = TCNT1;//即座にタイマー値を取得することでばらつきを防ぐ
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
static unsigned int lastEdge;//前回の立ち上がり位置
|
188
|
+
|
189
|
+
static unsigned int width[4];//各パルスの幅を保存
|
190
|
+
|
191
|
+
static int cnt = 0;//パルスのインデックス
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
if (cnt == 3 ) {
|
196
|
+
|
197
|
+
//タイマー操作を優先するため同条件のif文が分かれている
|
198
|
+
|
199
|
+
TCCR1B = TM_STOP; //数μs狂うかも知れないけど、安全なタイマーカウンタ操作のため止める
|
200
|
+
|
201
|
+
if (OCR1A > TCNT1) { //未実行のコンペアがあったら移行する
|
202
|
+
|
203
|
+
OCR1A -= TCNT1;
|
204
|
+
|
205
|
+
}
|
206
|
+
|
207
|
+
TCNT1 = 0; //タイマーカウンタをリセット
|
208
|
+
|
209
|
+
TCCR1B = TM_RUN;
|
210
|
+
|
211
|
+
}
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
//バルス立ち上がりの間隔を求める
|
216
|
+
|
217
|
+
width[(cnt + 3) % 4] = edge - lastEdge;
|
218
|
+
|
219
|
+
if ( cnt == 3 ) {
|
220
|
+
|
221
|
+
roundComp = true;//一周データ取り終わったことを記録
|
222
|
+
|
223
|
+
edge = 0;
|
224
|
+
|
225
|
+
}
|
226
|
+
|
227
|
+
lastEdge = edge;
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
// いちばん幅が狭いところつまり1のパルスの検出。
|
232
|
+
|
233
|
+
unsigned int wMin = width[0];
|
234
|
+
|
235
|
+
int firstEdge = 0;
|
236
|
+
|
237
|
+
for (int i = 1; i < 4; i++) {
|
238
|
+
|
239
|
+
if (width[i] < wMin) {
|
240
|
+
|
241
|
+
wMin = width[i];
|
242
|
+
|
243
|
+
firstEdge = i;
|
244
|
+
|
245
|
+
}
|
246
|
+
|
247
|
+
}
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
//一周分のデータが揃っているならLED処理
|
252
|
+
|
253
|
+
if (roundComp ) {
|
254
|
+
|
255
|
+
// 直前での120度分の回転時間
|
256
|
+
|
257
|
+
int w_3 = width[(cnt + 3) % 4];
|
258
|
+
|
259
|
+
//1のパルスが割れている分の補正
|
260
|
+
|
261
|
+
if (cnt == (firstEdge + 2) % 4) {
|
262
|
+
|
263
|
+
w_3 += width[firstEdge];
|
264
|
+
|
265
|
+
}
|
266
|
+
|
267
|
+
|
268
|
+
|
269
|
+
if (cnt == firstEdge) {//1のセンサが発報
|
270
|
+
|
271
|
+
OCR1A = edge + w_3 * 40l / 120; //例として40度回る時間後タイマーで消灯
|
272
|
+
|
273
|
+
//計算途中でのオーバーフローを防ぐため一部をlong型にしている
|
274
|
+
|
275
|
+
digitalWrite(LEDPORT[0], HIGH);//センサが発報したら点灯
|
276
|
+
|
277
|
+
}
|
278
|
+
|
279
|
+
if (cnt == (firstEdge + 2) % 4 ) { //2のセンサが発報
|
280
|
+
|
281
|
+
OCR1A = edge + w_3 * 20l / 120; //20度
|
282
|
+
|
283
|
+
digitalWrite(LEDPORT[1], HIGH);//センサが発報したら点灯
|
284
|
+
|
285
|
+
}
|
286
|
+
|
287
|
+
if (cnt == (firstEdge + 3) % 4 ) { //3のセンサが発報
|
288
|
+
|
289
|
+
OCR1A = edge + w_3 * 60l / 120; //60度
|
290
|
+
|
291
|
+
digitalWrite(LEDPORT[2], HIGH);//センサが発報したら点灯
|
292
|
+
|
293
|
+
}
|
294
|
+
|
295
|
+
}
|
296
|
+
|
297
|
+
|
298
|
+
|
299
|
+
cnt=(cnt+1)%4;//立ち上がり取得カウンタを進めておく
|
300
|
+
|
301
|
+
}
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
ISR (TIMER1_OVF_vect) {//低速、停止時に0にする為
|
306
|
+
|
307
|
+
roundComp = 0;
|
308
|
+
|
309
|
+
}
|
310
|
+
|
311
|
+
|
312
|
+
|
313
|
+
ISR (TIMER1_COMPA_vect) {//OCRA一致割り込みでLED OFF
|
314
|
+
|
315
|
+
//面倒なので全部OFF
|
316
|
+
|
317
|
+
for ( auto l : LEDPORT) {
|
318
|
+
|
319
|
+
digitalWrite(l, 0);
|
320
|
+
|
321
|
+
}
|
322
|
+
|
323
|
+
}
|
324
|
+
|
325
|
+
|
326
|
+
|
327
|
+
void setup() {
|
328
|
+
|
329
|
+
Serial.begin(115200) ;
|
330
|
+
|
331
|
+
for ( auto l : LEDPORT) {
|
332
|
+
|
333
|
+
pinMode(l, OUTPUT);
|
334
|
+
|
335
|
+
}
|
336
|
+
|
337
|
+
TCCR1A = 0;
|
338
|
+
|
339
|
+
TCCR1B = TM_RUN; //1/64=4us/countでタイマー1を回す
|
340
|
+
|
341
|
+
OCR1A = 0;
|
342
|
+
|
343
|
+
OCR1B = 0;
|
344
|
+
|
345
|
+
TIMSK1 = 0b11; //必要な割り込みON
|
346
|
+
|
347
|
+
attachInterrupt(0, pulse_read, RISING);//センサーD2ピン
|
348
|
+
|
349
|
+
}
|
350
|
+
|
351
|
+
|
352
|
+
|
353
|
+
void loop() {
|
354
|
+
|
355
|
+
}
|
356
|
+
|
357
|
+
```
|
2
追記
test
CHANGED
@@ -17,6 +17,10 @@
|
|
17
17
|
|
18
18
|
|
19
19
|
---
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
(追記)質問と条件が変わってしまいますが、センサーは羽根1枚だけを、切込み無しで検出するという前提で簡易的(=タイマ使わなくてフリーランのループ)なプログラムを試してみました。それでこれだけ出来るのですが、これじゃダメなんですか?
|
20
24
|
|
21
25
|
|
22
26
|
|
@@ -106,6 +110,10 @@
|
|
106
110
|
|
107
111
|
これで、コメントしてあるSerial.printlnを活かすと183とか4とかの値になったので、タイマーを使わなくても2度分くらいのばらつきで動くことはできるようです。
|
108
112
|
|
113
|
+
(追記) 波形をみたところ、目視で100μs以下ぐらいのジッタはあるようです。要求される精度はどのくらいですか?
|
114
|
+
|
115
|
+
|
116
|
+
|
109
117
|
タイマーを使うにしても原理としては同じようにできるでしょう。精度や分解能は随分よくなる期待が持てるかと思います。
|
110
118
|
|
111
119
|
|
1
軽く実験
test
CHANGED
@@ -13,3 +13,101 @@
|
|
13
13
|
|
14
14
|
|
15
15
|
あるいはタイマ使わなくてフリーランのループでも測れるかなぁ? その切れ込みパルスは一周に対してどういう比率になるのでしょう?
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
---
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
おおよそ9ms毎に1msのパルスを作って、以下のプログラムに突っ込んでみました。Arduino UNOなので16MHzのAVR 328Pです。
|
24
|
+
|
25
|
+
```Arduino
|
26
|
+
|
27
|
+
void setup() {
|
28
|
+
|
29
|
+
pinMode(2, INPUT);
|
30
|
+
|
31
|
+
pinMode(13, OUTPUT);
|
32
|
+
|
33
|
+
Serial.begin(115200);
|
34
|
+
|
35
|
+
}
|
36
|
+
|
37
|
+
const unsigned int LED_ON_PHASE = 0;
|
38
|
+
|
39
|
+
const unsigned int LED_OFF_PHASE = 180;
|
40
|
+
|
41
|
+
unsigned int count;
|
42
|
+
|
43
|
+
unsigned int totalCount;
|
44
|
+
|
45
|
+
unsigned int dummy1, dummy2;
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
int lastStat;
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
void loop() {
|
54
|
+
|
55
|
+
int stat = digitalRead(2);
|
56
|
+
|
57
|
+
if (!stat) {
|
58
|
+
|
59
|
+
if (lastStat) {
|
60
|
+
|
61
|
+
totalCount = count;
|
62
|
+
|
63
|
+
count = 0;
|
64
|
+
|
65
|
+
// Serial.println(totalCount);
|
66
|
+
|
67
|
+
} else {
|
68
|
+
|
69
|
+
dummy1 = count;//プログラムの経路によって実行時間が変わるのを緩和するためのダミー
|
70
|
+
|
71
|
+
dummy2 = 0;
|
72
|
+
|
73
|
+
}
|
74
|
+
|
75
|
+
} else {
|
76
|
+
|
77
|
+
if (lastStat) {
|
78
|
+
|
79
|
+
dummy1 = count;
|
80
|
+
|
81
|
+
dummy2 = 0;
|
82
|
+
|
83
|
+
} else {
|
84
|
+
|
85
|
+
dummy1 = count;
|
86
|
+
|
87
|
+
dummy2 = 0;
|
88
|
+
|
89
|
+
}
|
90
|
+
|
91
|
+
}
|
92
|
+
|
93
|
+
int led = ((unsigned long)totalCount * LED_ON_PHASE / 360 < count) &&
|
94
|
+
|
95
|
+
(count < (unsigned long)totalCount * LED_OFF_PHASE / 360);
|
96
|
+
|
97
|
+
digitalWrite(13, led);
|
98
|
+
|
99
|
+
count++;
|
100
|
+
|
101
|
+
lastStat = stat;
|
102
|
+
|
103
|
+
}
|
104
|
+
|
105
|
+
```
|
106
|
+
|
107
|
+
これで、コメントしてあるSerial.printlnを活かすと183とか4とかの値になったので、タイマーを使わなくても2度分くらいのばらつきで動くことはできるようです。
|
108
|
+
|
109
|
+
タイマーを使うにしても原理としては同じようにできるでしょう。精度や分解能は随分よくなる期待が持てるかと思います。
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
羽根3枚を検出しないといけない状況があるのでしょうか? それこそ羽根の隙間を狙わなきゃいけない、とかだと真面目に羽根を検出したほうがいいかも知れませんが。
|