PIC倒立振子

Similar documents
arduino プログラミング課題集 ( Ver /06/01 ) arduino と各種ボードを組み合わせ 制御するためのプログラミングを学 ぼう! 1 入出力ポートの設定と利用方法 (1) 制御( コントロール ) する とは 外部装置( ペリフェラル ) が必要とする信号をマイ

前回の内容 マイクロコンピュータにおけるプログラミング PC上で作成 コンパイル マイコンに転送 実行 プログラムを用いて外部の装置を動作させる LED turnonled turnoffled LCD printf プログラムを用いて外部の装置の状態を読み取る プッシュスイッチ getpushsw

目次 1 I2Cとは 13 結線写真 2 センサの多くがI2Cに対応 14 WHO_AM_I 3 マイコンでのI2C通信例 15 I2C読込みプログラム 4 とは 16 I2C読込みスクリプト概要① 5 タイミングパラメータ 17 I2C読込みスクリプト概要② 6 書込み 18 センサ読込みプログラ

-2 外からみたプロセッサ GND VCC CLK A0 A1 A2 A3 A4 A A6 A7 A8 A9 A10 A11 A12 A13 A14 A1 A16 A17 A18 A19 D0 D1 D2 D3 D4 D D6 D7 D8 D9 D10 D11 D12 D13 D14 D1 MEMR

内容 1. 仕様 動作確認条件 ハードウェア説明 使用端子一覧 ソフトウェア説明 動作概要 ファイル構成 オプション設定メモリ 定数一覧 変数一

PowerPoint プレゼンテーション

DCモータの制御

スライド 1

CMOS リニアイメージセンサ用駆動回路 C CMOS リニアイメージセンサ S 等用 C は当社製 CMOSリニアイメージセンサ S 等用に開発された駆動回路です USB 2.0インターフェースを用いて C と PCを接続

RTC_STM32F4 の説明 2013/10/20 STM32F4 内蔵 RTC の日付 時刻の設定および読み込みを行うプログラムです UART2( 非同期シリアル通信ポート 2) を使用して RTC の設定および読み込みを行います 無料の開発ツール Atollic TrueSTUDIO for

講習会 Arduino

プログラミング実習I

SpeC記述のC記述への変換 (SpecCによるソフトウェア記述の実装記述への変換)

Microsoft Word - 実験4_FPGA実験2_2015

PowerPoint プレゼンテーション

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

CCD リニアイメージセンサ用駆動回路 C CCD リニアイメージセンサ (S11155/S ) 用 C は 当社製 CCDリニアイメージセンサ S11155/S 用に開発された駆動回路です S11155/S11156-

AKI-PIC16F877A開発キット (Ver1

正転時とは反対に回転する これが逆転である 図 2(d) の様に 4 つのスイッチ全てが OFF の場合 DC モータには電流が流れず 停止する ただし 元々 DC モータが回転していた場合は 惰性でしばらく回転を続ける 図 2(e) の様に SW2 と SW4 を ON SW1 と SW3 を O

スライド 1

CoIDE 用 F4D_VCP の説明 V /07/05 USB の VCP( 仮想 COM ポート ) による非同期シリアル通信を行うプログラムです Free の開発ツール CoIDE で作成した STM32F4 Discovery 用のプロジェクトです プログラムの開始番地は 0x

Jan/25/2019 errata_c17m11_10 S1C17 マニュアル正誤表 項目 リセット保持時間 対象マニュアル発行 No. 項目ページ S1C17M10 テクニカルマニュアル システムリセットコントローラ (SRC) 特性 19-3 S1C17M20/M

電気的特性 (Ta=25 C) 項目 記号 条件 Min. Typ. Max. 単位 読み出し周波数 * 3 fop khz ラインレート * Hz 変換ゲイン Gc ゲイン =2-5 - e-/adu トリガ出力電圧 Highレベル Vdd V -

1. 使用する信号 1.1. UART 信号 UART 通信に使用する信号と接続相手との接続は以下の通りです UART 信号表 番号 CPU 機能名 CPU 信号名 基板コネクタピン番号 方向 接続相手の信号名 1 USART1_TX PA9 CN > RxD 2 USART1_R

割り込み 今までのプログラムは 順番にそって命令を実行していくのみ それはそれで良いが 不便な場合もある 例えば 時間のかかる周辺機器を使う場合 その周辺機器が動作を終了するまで CPU は待たなければいけない 方法 1( ポーリング ) 一定時間毎に 周辺機器の動作が終了したか調べる 終了していれ

PowerPoint Presentation

1. プログラム実行時の動作プログラムを実行すると以下のように動作します 1) NUCLEO-F401RE 上の LED LD2( 緑 ) が 200mSec 間隔で点滅します 2. プロジェクトの構成 2.1. プロジェクト F401N_BlinkLD2 の起動画面 TrueSTUDIO で作成し

1. A/D 入力について分解能 12bit の A/D コンバータ入力です A/D 入力電圧とディジタル値との対応は理論上 入力電圧 0V : 0 入力電圧 +3V : 4095 です 実際はオフセットと傾きがあり ぴったりこの数値にはなりません 2. A/D 入力に使用する信号 STM32L_A

1. USB の VCP( 仮想 COM ポート ) について USB の VCP( 仮想 COM ポート ) は USB を非同期シリアル通信として使用するための USB のドライバです PC には VCP ドライバをインストールする必要があります USB の VCP( 仮想 COM ポート )

スライド 1

スライド 1

スライド 1

Microsoft Word - PIC-USBマイコンボード_v1-02@WEB公開用資料.docx

81 /******************************************************************************/ 82 /* スレーブアドレスの設定 */ 83 /*****************************************

CMOS リニアイメージセンサ用駆動回路 C10808 シリーズ 蓄積時間の可変機能付き 高精度駆動回路 C10808 シリーズは 電流出力タイプ CMOS リニアイメージセンサ S10111~S10114 シリーズ S10121~S10124 シリーズ (-01) 用に設計された駆動回路です セン

GR-SAKURA-SAのサンプルソフト説明

三菱電機マイコン機器ソフトウエア株式会社

Taro-テキスト.jtd

まず,13 行目の HardwareTimer Timer(1); は,HardwareTimer というクラスを利用するという宣言である. この宣言によって Timer というインスタンスが生成される.Timer(1) の 1 は,OpenCM に 4 個用意されているタイマのうち,1 番のタイマ

スライド 1

Studuinoプログラミング環境

Microsoft PowerPoint LC_15.ppt

HDLトレーナーサンプルプログラム説明書

フロントエンド IC 付光センサ S CR S CR 各種光量の検出に適した小型 APD Si APD とプリアンプを一体化した小型光デバイスです 外乱光の影響を低減するための DC フィードバック回路を内蔵していま す また 優れたノイズ特性 周波数特性を実現しています

内容 1. 仕様 動作確認条件 ハードウェア説明 使用端子一覧 ソフトウェア説明 動作概要 ファイル構成 オプション設定メモリ 定数一覧 変数一

PIC の書き込み解説 PICライターを使うときに間違った使い方を見受ける 書き込み失敗の原因は知識不足にある やってはいけないことをしている 単に失敗だけならまだしも部品を壊してしまう 正しい知識を身に着けよう 書き込みに必要なピンと意味 ICSPを意識した回路設計の必要性 ICSP:In Cir

NCB564個別00版

Microsoft PowerPoint - RL78G14_動画マニュアル_タイマRD.ppt [互換モード]

1 1 Arduino とは Arduino アルドゥイーノ は ワンボードマイコンの一種で オープンソースハードウェアであ り 組み立て済みの基板を購入することもできるほか 誰でも自分の手で Arduino を組み立てる ことができます USBコネクタでPCと接続して利用します デジタルポートとア

Microsoft PowerPoint - RL78G1E_スタータキットデモ手順_2012_1119修正版.pptx

1. UART について UART は Universal Asynchronous Receiver Transmitter の頭文字をとったもので 非同期シリアル通信と呼ばれます シリアル通信とは 一本の信号線でデータをやりとりするために 1bit ずつデータを送出することをいいます データを受

QuartusII SOPC_Builderで利用できるGPIF-AVALONブリッジとは?

スライド 1

回路図 部品表 部品番号 型番 個数 U PIC6F823 I/ST (TSSOP 4pin) R 00Ω (/0W, 608) R2 - R9 360Ω (/0W, 608) 8 C μf (25V, 608) LED LN56RA CN ロープロファイルピンソケット CN2 ロープロファイルピン

1. LCD LS027B4DH01 について LS027B4DH01 は 400dot x 240dot のグラフィック LCD です 秋月電子通商で購入できます 外形サイズ : 62.8 x x 1.53mm LCD のフレキシブルケーブルの根元の部分はちょっと力を加えただけで表示が

パーツリスト 組み立て前にすべてのパーツがそろっているかご確認ください 種類 品番 数 種類 品番 数 基板 I2C LCD 1 コンデンサ 0.1uF (104) 積層セラミック 1 IC ATtiny コンデンサ 10uF 電解 1 半固定抵抗 10~50kΩ 1 コネクタ IC ソ

PowerPoint プレゼンテーション

TOPPERS 活用アイデア アプリケーション開発 コンテスト 部門 : 活用アイデア部門アプリケーション開発部門 作品のタイトル : Toppers_JSP と Scicos_lab / (Scilab でも可 ) による 組込みメカトロニクス制御シミュレーション 作成者 : 塩出武 ( シオデタ

UIOUSBCOM.DLLコマンドリファレンス

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

Microsoft PowerPoint - 工学ゼミⅢLED1回_2018

PSoC5LP で USBMIDI 2015/5/23 第 2 回 PSoC まつり (Sat) 於 本サイプレス本社 ( 中野 ) PSoC5LP で USBMIDI ectoyfan ectoyfan アラフィフ ( 電 回路玩具ファン ) Electronic Circui

PIC

RL78開発環境移行ガイド R8C/M16C, H8S/H8SXからRL78への移行(統合開発環境編)(High-performance Embedded Workshop→CS+)

光変調型フォト IC S , S6809, S6846, S6986, S7136/-10, S10053 外乱光下でも誤動作の少ない検出が可能なフォト IC 外乱光下の光同期検出用に開発されたフォトICです フォトICチップ内にフォトダイオード プリアンプ コンパレータ 発振回路 LE

- VHDL 演習 ( 組み合せ論理回路 ) 回路 半加算器 (half adder,fig.-) 全加算器を構成する要素である半加算器を作成する i) リスト - のコードを理解してから, コンパイル, ダウンロードする ii) 実験基板上のスイッチ W, が, の入力,LED, が, の出力とな

2. 仕様 電源 :USB バスパワー (USB 入力の 5V 電源を使用します ) 出力 : 3.5mm ステレオジャック アナログステレオ出力 最大 20mArms 対応ヘッドホンインピーダンス 1Ω~500Ω RCA ピンジャック アナログ 2ch 出力 (L R) ラインレベル ヘッドホンア

赤外線レーザー 360 距離センサ XV-11 LIDAR Sensor 取り扱い説明書 もくじ お使いになるまえに 各部のなまえと扱い方 2 使い方 (Processing GUI で使う ) 必要なソフトのインストール 3 接続方法 3 GUI の操作方法 4 使い方 ( ロボットに組み込む )

Studuinoライブラリ環境設定Mac編

Industrial shields brochure_JP

Arduinoで計る,測る,量る

PRONETA

Microsoft PowerPoint - 3.3タイミング制御.pptx

8ビットデータバスでアクセスする場合は、16ビットレジスタを上位バイト、下位バイトに分けてアクセスします

Microsoft PowerPoint pptx

竹内

Studuino ライブラリ環境設定Windows編

2CH DC (PU-2709) DC DC Arduino 製作に必要な部品などを表にまとめてみましょう 用意するもの 型番など 必要数 メモ Arduino Arduino UNO R3 1 パルスを作るマイコンボード 28BYJ-48 1 ACアダプター DC5V 1 DCジャック

Microsoft Word - BC-USB-KIT(16).docx

名称 型名 SiC ゲートドライバー SDM1810 仕様書 適用 本仕様書は SiC-MOSFET 一体取付形 2 回路ゲートドライバー SDM1810 について適用いたします 2. 概要本ドライバーは ROHM 社製 2ch 入り 180A/1200V クラス SiC-MOSFET

回路 7 レジスタ ( 同期イネーブル及び非同期リセット付 ) 入力データを保持するのに用いる記憶素子 使用用途として, マイクロプロセッサ内部で演算や実行状態の保持に用いられる Fig4-2 のレジスタは, クロック信号の立ち上がり時かつ 信号が 1 のときに外部からの 1 ビットデータ R をレ

Transcription:

PIC マイコンとジャイロセンサを使った倒立振子 2016 年 7 月 29 日蚊野浩概要 PIC マイコンと3 軸ジャイロ加速度センサ MPU6050 を使って, 二輪倒立振子を試作した.6 個のセンサ出力の中で, 一つの角速度値だけを使って倒立させることができた. 1. PIC マイコン PIC マイコンは, 米国マイクロチップ テクノロジー社が製造するマイクロコントローラ製品群である. 非常に多くの製品があり, 組み込み機器用マイクロコントローラに適したアーキテクチャを有している. 今回は PIC16F886 という製品を利用した. その理由は次の点である. 1 文献 [1] で詳細に説明されているので情報を得やすい. 2 2セットの PWM に利用できる CCP1 CCP2 モジュールを持っており, 二輪倒立振子の2 個の DC モータを容易に PWM 制御できる. 3 28 ピンの DIP であるため実装が容易. 今回利用した PIC マイコンの開発環境を説明する.PIC マイコンの統合開発環境 MPLAB X IDE を Windows10 PC にインストールした. 利用したバージョンは v3.35 である. これに,CCS 社の C コンパイラ (PCM) を組み込み,C 言語のプログラムを開発した.C コンパイラにはマイクロチップ テクノロジー社の純正品など, 幾つかの製品がある. その中で,CCS 社の製品は比較的安価でライブラリが豊富である.PIC の豊富な機能を利用するには, 充実したライブラリが重要である.CCS の C は, 今回の開発で便利に利用することができた. PIC マイコンへのプログラムライターとして PICKit3, 書き込みアダプターとしてマルツエレックの MPIC-DPPA を利用した ( 図 1).

図 1 PICkit3 と MPIC-DPPA PIC マイコンのソフト開発におけるデバッグ手段として次の方法がある. 1 PICkit3 のインサーキットデバッガを使う. 文献 [2] に記述されているように PICkit3 と PIC マイコンを接続する. この状態で, パソコンから PIC マイコンにプログラムをダウンロードできる. 続いて, リアルタイムエミュレーションが可能になる. ステップ実行や変数の値を確認することが可能である. 2 PIC マイコンとパソコンを UART で接続する.CCS の関数 printf を使うと, 書式付き文字列が UART に出力される. これをパソコン側で表示することで, プログラムの状態を確認できる. 2. 3 軸ジャイロ加速度センサ MPU6050 MPU6050 は InvenSense 社の3 軸加速度ジャイロセンサである. これをモジュール化した GY-521 を利用した ( 図 2).GY-521 と PIC マイコンを I2C インタフェースで接続する. 接続の詳細については後述する.MPU6050 は3 軸回りの角速度を 3 つの数値として,3 軸方向の加速度を 3 つの数値として, 合計 6 個の数値を出力する. 今回は, x 軸回りの角速度だけを利用する. 図 2 MPU6050( 中央のチップ ) と GY-521 3. 二輪倒立振子メカタミヤの楽しい工作シリーズ No.168 ダブルギアボックス( 左右独立 4 速タイプ ) をギア比 38.2:1 で組み立てた. これに, 同シリーズ No.193 スリムタイヤセット の 55mm 径のタイヤを装着し, 同シリーズ No.98 ユニバーサルプレートセット にネジ止めした. 図 3 に回路とバッテリーも実装した状態での外観を示す. なお, 本研究で参考にした Web サイト [4] は, ダブルギアボックス ( 左右独立 4 速タイプ ) をギア比 114.7:1 で利用している. 今回の実験でも, 当初はこのギア比で組み立てたが, 減速しすぎで, 応答が遅れているようであった.

図 3 二輪倒立振子 4. 回路 +5V% RA0 RA1 RA2 RA3 Vss CCP2 CCP1 SCL PIC16F886 1 28 LED% 2 3 4 5 6 7 8 27 26 25 24 23 22 21 SW% 9 10 11 12 13 14 20 Vdd 19 Vss 18 17 16 15 SDA +5V% GND SCL SDA RA0 RA1 CCP1 RA2 RA3 CCP2 IC%TA7291P% GND%OUT1%NC%%Vref%%IN1%%IN2%VCC%%VS%%%NC%%OUT2% 1%%%%2%%%%3%%%%%4%%%%5%%%%6%%%7%%%%8%%%%9%%%10%%%%%%%%%%%%%%%%%%%%% 1% 2% DC % SW% % + V% 10kΩ% +5V% 47uF% IC%TA7291P% GND%OUT1%NC%%Vref%%IN1%%IN2%VCC%%VS%%%NC%%OUT2% 1%%%%2%%%%3%%%%%4%%%%5%%%%6%%%7%%%%8%%%%9%%%10%%%%%%%%%%%%%%%%%%%%% 1% 2% DC % 47uF% LED% 0.1uF% 0.1uF% 330Ω% LED% % % DC% M % % DC% M MPU6050 図 4 回路図 図 4 に回路図を示す. モータードライバー IC TA7291P の機能は,5 6 番ピンに回転方向を指示するパターンを与え,4 番ピンに PWM のパルス信号を加えることで, 回転方向と回転力を制御することである. このように,PIC マイコンを用いることで, デジタル制御に必要な回路部分のほとんどを PIC マイコン内部に取り込むことができる.

5. 倒立振子の制御 今回試作する二輪倒立振子は, 図 5 のように車体を振り上げた状態で, 二輪を前進 後退させながら倒れないようにバランスをとる装置である. 図 5 二輪倒立振子の運動時刻 t における装置の運動状態を表す変数を次のように定義する. angle(t) : 車体がバランスした状態からの回転角度 angle_velocity(t) : 車体の角速度 velocity(t) : 車軸の移動速度 distance(t) : 車軸の移動量この時, 二輪倒立振子を静止させるために車輪に加える制御量を u(t) とすると, u(t) = F1*angle + F2*angle_velocity + F3*velocity + F4*distance (1) となることが知られている [3]. 式 (1) 右辺は4つの項の和になっている. それぞれの項の働きは, 次のようなものであると理解している. F1*angle は車体をバランスする方向に車輪を進めるための項である. 小さく回転しておればそれを補正するための制御量は小さく, 大きく回転しておればそれを補正するための制御量は大きくなる. この項だけで概ね倒立させることが可能であるように思える. しかし実際には安定せず, 振動する. その理由は, 角度 0 の位置を行き過ぎる時に, それを止めるための補正が働かないからである. F2*angle_velocity は車体の回転運動を抑制するための項である. 角度 0 の位置をある程度の角速度で行き過ぎ場合に, それを止めるための補正項として働く. このように考えると, 最初の2 項で倒立振子を立てることができる. しかし, 二輪倒立振子が安定している状態 ( 角度 0, 角速度 0) であっても, 車体が一定速度で移動している状態がありえる. この状態を解消して, 車速 0 で安定させるための項が

F3*velocity である. さらに最後の項 F4*distance は, 制御を開始した位置で静止させ るための項であると考えられる. 6. 二輪倒立振子のプログラム次ページ以降のリストを参照しながら二輪倒立振子のプログラムを説明する. 4 行目から 8 行目は,PIC マイコンのコンフィグレーションを設定するための,CCS の書き方である. これらの意味は文献 [1] に説明されている.5 行目は PICkit3 のインサーキットデバッガを使う場合の書き方の例,8 行間は通常の使い方をする場合の例である. BROWNOUT は電源電圧が低下した時にリセットすることを意味するパラメータである.3.3V で動作させるには NOBROWNOUT を指定する必要がある. 11 行目で内部クロックとして 8MHz を使うことを宣言している. 内部クロックの種類はコメントで記述しただけの周波数がある. 二輪倒立振子は, ある程度高速に制御する必要があるので, 結局,8MHz のクロックを使うことになった. 14 行目で I2C をマスターとして使うことを宣言している. 16 行目から 27 行目は MPU6050 自身のアドレスとその内部レジスタのアドレスを宣言している.MPU6050 の I2C アドレスは 0x68 である. それを PIC マイコン側で設定する場合,7 ビットアドレスが 8 ビットの上位に置かれるので,0xD0 になる. 30 行目は PIC のタイマー 0 のカウント値となる定数を宣言している. この例では, 後で説明するように タイマー 0 のクロックが 32μsec になっており, その状態で 4msec をカウントするための数値が 130 である. なお,4msec は二輪倒立振子の制御周期である. 38 39 行目は IO ポートの使い方に関する宣言である.PIC16F886 は A ポート,B ポート, C ポートの3つの IO ポートを持っている. これらは, 端子ごとに入出力を指定することができる.fast_io(x) と指定すれば, 一旦,IO ポートの入出力の方向を設定すれば (set_tris_x() 関数で ), それ以降, 方向を変えないため,IO ポートを高速にアクセスできる.IO 端子へのアクセスは,output_low(PIN_B7) などでできるが,fast_io() をしておけば処理が高速になるということである. 42 行目から 45 行目で, 運動状態を表す 4 の変数をグローバル変数として宣言する. 51 行目の最初に int8 i; と宣言している.CCS の C 言語が通常の C 言語と大きく異なることは, データ型の制約が大きいことである.int8 は 8 ビット整数という意味である. データ型の制約については文献 [1] を参照のこと. 53 行目から 59 行目で A ポートと B ポートの初期設定を行っている. 61 行目から 67 行目で MPU6050 を起動している.

69 行目から 73 行目で LED を 1 秒間隔で3 回点滅させている. この間に装置を平坦な場所に静置する. 75 行目から 80 行目で x 軸回りの角速度を 255 回読み取り, その平均を av_offset としている. 装置は静止させているので,av_offset は静止時にも発生する角速度のオフセットである. 82 行目から 86 行目で LED を 0.2 秒間隔で3 回点滅させている. これで, 角速度のオフセットを計測し終わったことを示す. 88 行目から 90 行目は,PIC16F886 が内蔵する2つの CCP モジュールを PWM で利用することを宣言する.CCP モジュールの説明は文献 [1] を参照のこと. 94 行目は,PWM に用いるタイマー 2の動作を設定する. システムクロックが 8MHz (0.125μsec 周期 ) のとき, タイマー 2に入力されるクロックはその 4 倍の 0.5μsec になる. これをさらに分周したものをカウントして PWM の周期とする.94 行目の設定は 16 分周して 100 カウントするという意味であるから, コメントのように 800μsec が PWM の周期である. 96 行目と 97 行目は PWM のデューティ比を設定する. ここで設定する数値は 94 行目の setup_timer_2() 関数の第 2 引数の数値 ( この例では 100) よりも小さくする. 101 行目は二輪倒立振子の制御周期を決めるタイマー 0 の動作を設定する. setup_timer_0 関数で, カウンタへの入力クロックの周期 0.5μsec を 64 分周したもの ( したがって 32μsec) を 8 ビットの数値でカウントすることを指定している.102 行目の数値を設定することで, タイマー 0の周期は 4msec となる.103 行目から 105 行目でタイマー 0による割り込みを許可している. 107 行目から 118 行目の無限ループの間に, 後で説明する割り込みが 4msec 周期で発生する. この無限ループの中でスイッチが押されるとモータの動作をストップし, 幾つかの運動パラメータを 0 にリセットする. 120 行目から 183 行目が二輪倒立振子の制御を行う割り込み処理である.126 行目と 185 行目で LED を ON/OFF し, 処理時間などを確認できるようにしている. 129 行目で, 次の割り込みのためにタイマー 0 に値をセットする. 132 行目で MPU6050 から生の角速度値を読み込み, オフセット値を引くことで高精度化している. 135 行目で角速度を積算することで角度を求めている. 138 行目から 142 行目で 4 つの運動パラメータに対するゲインを設定し,149 行目でそれらを足し合わせることで制御量を求める.

制御量の数値を PWM のデューティ比に換算する. デューティ比の値は 1 から 99 までを用いることにした. 制御量が大きければデューティ比を大きくする.152 行目の変数 max_pwr に制御量が飽和する値を設定し,153 行目の変数 min_pwr に制御を有効にする最小の制御量を設定する.max_pwr を大きな値にすれば, 制御はゆるやかになり, 小さい値にすれば制御が急速に働く. 170 行目から 183 行目で新たなデューティ比を設定し,velocity,distance の値を更新する. 180 行目から 222 行目は MPU6050 にアクセスするための関数である. ここに記述するように I2C の制御信号をコントロールする.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <16f886.h> #include <math.h> // Pickit3 のインサーキットデバッグ機能を使う場合の CONFIG, DEBUG(NODEBUG ではなく ), MCLR(NOMCLR ではなく ) //#fuses NOPROTECT,DEBUG,NOWRT,NOCPD,NOLVP,BROWNOUT,PUT,MCLR,NOWDT,INTRC,NOIESO,NOFCMEN,BORV40 // Pickit3 のインサーキットデバッグ機能を使わない場合の CONFIG, NODEBUG, MCLR #fuses NOPROTECT,NODEBUG,NOWRT,NOCPD,NOLVP,NOBROWNOUT,PUT,MCLR,NOWDT,INTRC,NOIESO,NOFCMEN,BORV40 // 内部クロック 8MHz で利用する #use delay(internal = 8MHZ) //(8MHZ,4MHZ,2MHz,1MHZ,500kHz,250kHZ,125kHz,31kHz) // I2C の定義 16F886 の場合にはハードウエアで実行する #use i2c(master, SCL=PIN_C3, SDA=PIN_C4, FAST, FORCE_HW) //MPU6050 とその内部レジスタのアドレス #define MPU6050 0xD0 //0x68 を1ビット左シフト #define MPU6050R 0xD1 //Read する場合 最下位ビットを 1 にする #define POWER_MGMT 0x6B #define CONFIG_R 0x1A #define GYRO_CONFIG 0x1B #define AX_ADR 0x3B #define AY_ADR 0x3D #define AZ_ADR 0x3F #define GX_ADR 0x43 #define GY_ADR 0x45 #define GZ_ADR 0x47 // タイマー 0のカウント値 例えば 4ms 周期の場合 255 - (4msec/32) = 130 #define T0COUNT 130 // 関数のプロトタイプ宣言 void inttimer0(); int8 mpu6050_write(int adr, int data); int8 mpu6050_read(int adr); float mpu6050_rawdata(int8 reg); #use fast_io(a) #use fast_io(b) // グローバル変数 float av_offset;// 角速度のオフセット float angle = 0.0f;//x 軸回りの角度 float velocity = 0.0f;// 車速の推定値 float distance = 0.0f;// 移動距離の推定値 #define M_PI 3.1415926f /**** main 関数 ****/ void main() { int8 i; // ポート A の下位 4 ビットを出力 上位 4 ビットを入力に設定する fast_io(x) を使う場合 最初に set_tri_x() で端子の入出力方向を決める set_tris_a(0xf0); output_a(0x00);//0x06: 順, 0x09: 逆, 0x00: ストップ, 0x0f: ブレーキ // ポート B の下位 7 ビットを入力 B7 を出力に設定する set_tris_b(0x7f); output_low(pin_b7);//led を消灯

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 //MPU6050 のパワーオンでエラーが発生すれば B7 端子を 0.1sec でトグルする if (mpu6050_write(power_mgmt, 0x00)!= 0) { while (1) { output_toggle(pin_b7); delay_ms(100); //MPU6050 のパワーオンでエラーがない場合 LED を3 回点滅させる この間に 装置を平坦な場所に置く for (i = 0; i < 6; i++) { output_toggle(pin_b7); delay_ms(1000); // 平坦な場所に置いた状態で 角速度のオフセットを求める av_offset = 0.0f; for (i = 0; i < 255; i++) { av_offset += mpu6050_rawdata(gx_adr); av_offset = av_offset/255.0f; // 角速度のオフセットを求めたことを示すために 素早く LED を 3 回点滅させる for (i = 0; i < 6; i++) { output_toggle(pin_b7); delay_ms(200); //ccp1 と ccp2 を PWM で使う ccp1 と ccp2 はモータの PWM 制御に利用する setup_ccp1(ccp_pwm); setup_ccp2(ccp_pwm); //PWM に使うタイマー 2を (T2_DIV_BY_16,100,1) と設定すると PWM の周期は 0.5usec 16 100=800usec になる // ここで 0.5usec は 8MHz の1 周期 0.125usec の4 倍の値 setup_timer_2(t2_div_by_16,100,1); // 次の関数で設定するデューティ比の数値は setup_timer_2() の第二引数よりも小さい数値に設定する set_pwm1_duty(0); set_pwm2_duty(0); // 周期的に発生する割込み用にタイマー 0を使用する // タイマー 0のクロックは 0.5us 64=32us カウンタは 8bit ここで 0.5usec は 8MHz の1 周期 0.125usec の4 倍の値 setup_timer_0(rtcc_internal RTCC_DIV_64 RTCC_8_BIT); set_timer0(t0count); // タイマー 0による割込みを許可する enable_interrupts(int_timer0); enable_interrupts(global); while(1) { // スイッチを押すとモーターを止め 角度 速度 移動距離を0にする if (input(pin_b6)) { output_a(0x00);//0x06: 順, 0x09: 逆, 0x00: ストップ, 0x0f: ブレーキ set_pwm1_duty(0); set_pwm2_duty(0); angle = 0.0f; velocity = 0.0f; distance = 0.0f;

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 // タイマー 0で周期的に割込みを発生させ MPU6050 の値を読みとり メカを制御する //2016 年 7 月 29 日のバージョンでは 割込み周期を 4msec に設定し inttimer0() の処理を 2msec で終了している #INT_TIMER0 void inttimer0() { // タイマーによる割込みが発生していることを確認するために B7 をトグルする output_high(pin_b7); // 次の割込みのためにカウンタをセットする set_timer0(t0count); // 角速度 ( 度 /sec 単位 ) を求める float angular_velocity = mpu6050_rawdata(gx_adr) - av_offset; // 角速度を積算して角度を求める angle += angular_velocity; // 制御量を求める #define F1 1.0f // 角度に対するゲイン (1.0 に固定 第一にこれを固定して max_pwr を調整する ) #define F2 4.0f // 角速度に対するゲイン (4.0 第二に調整する 小さいと制御が弱く 大きいと振動する ) #define F3 50.0f // 車速に対するゲイン (50 小さいと大きく前後移動 大きくすると前後幅が小さくなるが 大きすぎると破たんする ) #define F4 0.0f // 移動距離に対するゲイン うまく動作しないので 0 に設定している float f1angle = F1*angle; float f2angvel = F2*angular_velocity; float f3velocity = F3*velocity; float f4distance = F4*distance; float pwr = f1angle + f2angvel + f3velocity + f4distance;// 制御量 // 制御量の絶対値の最大 (F1=1.0 で この値を適切に設定する 小さいと制御が遅くなり 大きいと振動する ) float max_pwr = 200000.0f; float min_pwr = 1.0f;// 制御量の絶対値の最小 ( この値以下ではモータを駆動しない あまり意味がない ) //pwm のデューティ比を設定する int8 duty;//pwm のデューティ比 #define DUTY_MAX 99.0f //PWM の最大デューティ比 #define DUTY_MIN 1.0f //PWM の最小デューティ比 if ((pwr >= max_pwr) (pwr <= -max_pwr)) {// 制御量の絶対値が max_pwr を超えた場合 duty = DUTY_MAX; else if (pwr >= min_pwr) {// 制御量が min_pwr?max_pwr の場合 duty = (int8)(duty_min + (DUTY_MAX-DUTY_MIN)*pwr/max_pwr); else if (pwr <= -min_pwr) {// 制御量が-min_pwr?-max_pwr の場合 duty = (int8)(duty_min + (DUTY_MAX-DUTY_MIN)*(-pwr)/max_pwr); else { duty = 0; if (pwr >= 0) { output_a(0x06);//0x06: 順, 0x09: 逆, 0x00: ストップ, 0x0f: ブレーキ set_pwm1_duty(duty); set_pwm2_duty(duty); velocity += (float)duty; distance += (float)velocity;

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 else { output_a(0x09);//0x06: 順, 0x09: 逆, 0x00: ストップ, 0x0f: ブレーキ set_pwm1_duty(duty); set_pwm2_duty(duty); velocity -= (float)duty; distance -= (float)velocity; output_low(pin_b7); int8 mpu6050_write(int adr, int data) { int ack = 0; i2c_start(); ack += i2c_write(mpu6050); ack += i2c_write(adr); ack += i2c_write(data); i2c_stop(); return (ack); int8 mpu6050_read(int adr) { int val; //MPU6050 と読み出しレジスタを指定する i2c_start(); i2c_write(mpu6050); i2c_write(adr); // 指定したレジスタから読み出し i2c_start(); i2c_write(mpu6050r);// 読み出しの場合には 最下位ビットを1にする val = i2c_read(0); //0 を指定するとデータを正しく受け取るようである i2c_stop(); return val; float mpu6050_rawdata(int8 reg) { int8 high = mpu6050_read(reg); int8 low = mpu6050_read(reg+1); return (float)((signed int16)make16(high,low));

文献 [1] 改訂版 C 言語による PIC プログラミング入門, 後閑哲也, 技術評論社,2009 年. [2] http://ww1.microchip.com/downloads/jp/devicedoc/52010a_jp.pdf [3] フィードバック制御による倒立ロボットの製作, 川村伸司,CQ 出版 Interface, pp.70-77,2006 年 7 月号. [4] http://www.instructables.com/id/ 倒立振子の研究 /