質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Q&A

解決済

4回答

12041閲覧

RaspberryPiでロータリーエンコーダを使う

akaikumako

総合スコア19

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

0グッド

0クリップ

投稿2015/11/03 00:26

###前提・実現したいこと
ロボットの動作の処理を行うRasPi2のMainプログラムで
ロータリーエンコーダの信号を
wiringPiISRの割り込みを使って読み取り、回転速度の計算を行おうと思っています。

###発生している問題・エラーメッセージ
プログラムを実行したところ、値の読み取りがうまくできませんでした。
どうすればRasPiでロータリーエンコーダの値を読み込めるのでしょうか…?

###ソースコード

Main.cpp

1#include <iostream> 2#include <wiringPi.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <unistd.h> 6#include <math.h> 7 8// ロータリーエンコーダ用割り込みピンの設定 9const int rot_pinA = 20; 10const int rot_pinB = 18; 11signed long int rot_count = 0; 12 13void rotary_changedPinA(void); 14void rotary_changedPinB(void); 15 16int main(void){ 17 wiringPiISR(rot_pinA, INT_EDGE_BOTH, rotary_changedPinA); 18 wiringPiISR(rot_pinB, INT_EDGE_BOTH, rotary_changedPinB); 19 20 //STARTボタンとCROSSボタンが押されるまでloopする 21 UPDATELOOP(controller, !(controller.button(START) && controller.button(CROSS))){ 22 //ここにメインの処理を書きます。 23 } 24} 25 26void rotary_changedPinA(void){ 27 if(digitalRead(rot_pinA)){ 28 if(digitalRead(rot_pinB)) ++rot_count; 29 else --rot_count; 30 }else{ 31 if(digitalRead(rot_pinB)) --rot_count; 32 else ++rot_count; 33 } 34} 35 36void rotary_changedPinB(void){ 37 if(digitalRead(rot_pinB)){ 38 if(digitalRead(rot_pinA)) ++rot_count; 39 else --rot_count; 40 }else{ 41 if(digitalRead(rot_pinA)) --rot_count; 42 else ++rot_count; 43 } 44} 45

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

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

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

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

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

guest

回答4

0

ベストアンサー

ロータリーエンコーダの処理ですが、ラズパイではやったことありませんが、
いわゆる、論理的には以下の方法で検出できるはずです。(言語・変数・命令体系などは適当です。ラズパイ仕様とは違っているかと思いますが、適時読み直してください。)

肝は、A相、B相ともに、GNDレベルになった時に、その前回のA相B相の状態で、回転方向がわかるということです。

よって、こんな感じで検出可能かと思います。(ハードに問題なければです、ハード側はオシロスコープなどを当てるなどして、確認してください。特にロータリーエンコーダにおいて、チャタリング対策は必須です。)

//割り込み前のA相状態 bool oldPinA = false; //割り込み前のB相状態 bool oldPinB = false; // int main(void){ //割り込みの設定(A相割り込みもB相割り込みも同一処理で可能) wiringPiISR(rot_pinA, INT_EDGE_BOTH, rotary_changedPin); wiringPiISR(rot_pinB, INT_EDGE_BOTH, rotary_changedPin); // ・・・ // } // void rotary_changedPin(void){ // bool sigPinA = digitalRead(rot_pinA); bool sigPinB = digitalRead(rot_pinB); //A相、B相共にGNDレベルなら if(!sigPinA && !sigPinB){ //ハードでチャタリング対策をしないなら、ここで数〜数十msecのwaitで回避できます //しかしエンコードの高速回転についていけなくなります。 //ハード側でのCRなどでの対策が得策です。 //wait(10); //10msec待ちとか。 if(!oldPinA && oldPinB){ //正回転 }else{ //負回転 } } //A相、B相の状態を記録 oldPinA = sigPinA; oldPinB = sigPinB; }

なお、チャタリング対策については、A相、B相ともに、シグナル線を、
・10Kのプルアップ
・0.01uFのコンデンサでGNDに接続
で、かなり良好な結果がでるかと思います。
立ち上がりのエッジが気になるなら、プルアップ抵抗を4.7Kなど、小さくするとオシロでの見た時のシグナルは綺麗に見えてきます。ただ、CPUのトリガーエッジに引っかかるタイミングは、あまり変わらないので、このあたりは、綺麗な方形波を目指すことも無いかと?思います。

投稿2015/11/03 04:33

編集2015/11/03 04:45
ItoTomonori

総合スコア1283

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

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

akaikumako

2015/11/05 09:02

プログラム参考にさせていただきました(_ _) チャタリング対策のWaitは入れていませんが、 動くようにはなったようです! (ちなみに360p/rのロータリーエンコーダを使っています。) あまりチャタリングについて詳しくないので いろいろ調べつつさらに効率的にロータリーエンコーダを 利用できるように改善してみます。 有難うございました!
guest

0

つい先日、ラズベリーパイ(※1の方)でエンコーダ入力ソフトを
作ったばかりなので、私のソフトの違いを記載させていただきます。
これが原因かどうかはわかりませんが

1.wiringPiSetupGpio()で初期化をしていない
2.入力端子のプルアップ、プルダウンの設定をしていない
pullUpDnControl()で設定できます
3.rotary_changedPinA,rotary_changedPinBの中で
それぞれの端子が前回の値から本当に変化したかを確認してない
結構、GPIOの割り込みは値が変わってないのに発生します

これで変わるかわかりませんが、試してみてください

投稿2015/11/10 12:22

DaiGuard

総合スコア159

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

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

0

どんなエンコーダーをどの様に接続しているのか分からないのと、Raspberry Piをもっておらず試せないので、外していたらごめんなさい。

akaikumakoさんのプログラムでは、大雑把に言えば L→H ならカウントアップ、 H→L ならカウントダウンのようなロジックになっていますが、ロータリーエンコーダーからの出力は常に H と L を繰り返すものなので、これではいつまでたってもプラスマイナスゼロで変化を検出できません。

まずは下記ページの説明がとても分かりやすいのでご覧ください。

ロータリーエンコーダ

パルスはA相とB相でずれて出力されるようになっていて、回転方向によってずれかたが異なるから、それでどちらに回されたのかを知ることができる。

その説明の少し下にある 信号変化の模式図 を見ると分かるように、A相・B相の信号レベルを単独で取得してもダメで、直前の値との関係 および A・B間の関係 を調べる必要があります。

上記ページにも実装例が載っていますが、ご参考までに他の実装例も幾つかリンクを張っておきます。

Raspberry Piでロータリーエンコーダーの動作確認
Sunfounder スーパーキット For Raspberry Pi Lesson10 ロータリエンコーダ
LPC1114FN28でロータリーエンコーダ制御

どれを見ても基本は同じです。
異なっているのは、チャタリング等のノイズに対してプログラム側でどの程度対応するかと、あとは実装方法の好みの問題だと思います。

なお、Chironianさんもご指摘のように、エンコーダーをダイレクトに接続したのではノイズによる誤動作を回避するのが難しい場合もあり、Raspberry Pi との接続回路を工夫する必要があるかもしれません。
その場合には、下記ページをご参考になさってみてください。

ロータリーエンコーダーの接続

幾らかでもご参考になれば幸いです。

投稿2015/11/03 03:48

pi-chan

総合スコア5936

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

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

akaikumako

2015/11/05 08:58

プログラムが間違ってたの気づいてませんでした(・・;) ご指摘ありがとうございます。 ノイズの影響が大きいところでロータリーエンコーダを使うので 回路の方も参考にしてみます!
guest

0

こんにちは。

RaspberryPiを触ったことはないのですが、ファームウェア開発に慣れてますので、その観点から回答してみます。

割り込みを使われていますが、まずは割り込みを使わないで入力できているか見た方が良いと思います。
I/Oポートで制御できるLEDがついてませんか? もし、あるならまずLEDを点灯/消灯できるようにしてから、rot_pinAのH/LをチェックしてHなら点灯、Lなら消灯するようなソフトを走らせる等により、ちゃんと入力できているのか確認した方が良いと思います。

ここのソースをみると、なんとなくプルアップが必要な気もします。ロータリーエンコーダとRaspberryPiの接続回路によりますが。

投稿2015/11/03 02:06

Chironian

総合スコア23272

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

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

akaikumako

2015/11/05 08:52

回答ありがとうございました。 プログラムは合ってるのに値が読めない…と思っていたら プルアップをプログラムに記述すると上手く読める事が出来ました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問