ともさんのHP >ものつくり >ラズパイ(Raspberry Pi)で電子工作 >RaspberryPi用Javaサンプルプログラム
RaspberryPiとJavaで水遣りプログラム
RaspberryPiを使って毎日決まった時間に水ポンプを動かす装置を作りました。
Javaで作ったプログラムと回路図などを公開しています。
Javaプログラム
Java
楽天 Swingを使ってGUIプログラムにしました。最初JavaFXで書いたのですが、ラズパイではまだFX使えなかったのでSwingに書き直しました。
ほとんどをパソコン上のEclipceで書き、RaspberryPi楽天 にコピーしてGPIO部分をBlueJを利用して書き足しています。
プログラムの動作手順
立ち上げると無限ループに入ります(MIzuyari2.run)。2秒ごとに今日が始まってからの経過時間(mm秒)を得て(Jikoku.getTodaymms)、
設定した時間(MizuyariPane2.getSt、MizuyariPane2.getEt)と比較し、
設定時間内であればGPIOをHIGHに設定。設定外であればLOWにします。
設定時間は3つまで設定可能。
ほかにトグルボタンをONにするとその間だけ通電させることが可能です。
GPIOの操作
GPIOの設定は下記のようにします。
まずGpioControllerオブジェクトを作り、
GpioController gpio = GpioFactory.getInstance();
個別のIOピンオブジェクトを作る。
GpioPinDigitalOutput pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_02, "MOTOR1", PinState.LOW);
続いて個別のIOピンのシャットダウン時の状態を設定。
pin.setShutdownOptions(true, PinState.LOW);
設定ののち、PINのHIGH、LOWを操作。
pin.high();
pin.low();
com.pi4j.io.gpioのドキュメントを読むと、こちら、
high()/low()のほかに blink()、pulse() も設定できるようになっています。名前から大体想像はできるけど、どういうメソッドか不明。
GPIOを組み入れるとエラー発生
GPIO以外の記述はPCで行い、ラズパイ楽天 に移動してGPIO部分を追記しました。
BlueJのデバッグモードでは正常に動くのですが、Jarファイルをつくって、これを走らせるとなぜかGPIOのところで止まってしまいます。
どうやら一時ファイルを作るときに拒絶されているようです。付け焼刃ですが、管理者権限で実行したらうまくゆきました。
java -jar Mizukanri.jar
↓
sudo java -jar Mizukanri.jar
モーター駆動回路
ラズパイマガジン2016年6月号、P41のモーター駆動回路を参考に、というか、ほぼそのまま利用して作りました。
モータードライバーとターミナルブロックは秋月電子通商で購入。
こんな感じです。10年ぶりくらいにはんだ付け作業。芋はんだになってしまいましたが、まあ、大丈夫。
所定の抵抗が手持ちになかったので、いくつか直列に並べました。
RaspberryPiのPIN配置
今回使ったピンは下の図の通り。
ソースコード
メインclass
package tomojavalib.raspberrypi;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.*;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
public class MizuKanri2 extends Jframe implements Runnable{
//配水ボタン楽天
JToggleButton b;
//時刻設定パネル
MizukanriPane2[] mkp;
//開始時刻
long[] st ;
//終了時刻
long[] et ;
//状態表示ラベル
Jlabel tx;
//水やりフラグ
boolean flug = false;
Thread timer;
//スレッドを終えるフラグ
boolean run = true;
//出力PIN
final GpioPinDigitalOutput pin;
public static void main(String[] args) {
MizuKanri2 mk2 = new MizuKanri2();
}
public MizuKanri2() {
Container contentPane = getContentPane();
Jpanel pane = new Jpanel();
pane.setLayout( new FlowLayout(FlowLayout.LEFT, 5, 5));
contentPane.add( pane );
//現在の状態
tx = new Jlabel();
tx.setText("現在の状態:停止中");
pane.add( tx );
//配水ボタン
b = new JToggleButton( " 停止 " );
pane.add( b );
b.addActionListener( new Haisui() );
//時刻設定
mkp = new MizukanriPane2[3];
st = new long[ mkp.length ];
et = new long[ mkp.length ];
for(int i=0;i<mkp.length;i++){
mkp[i] = new MizukanriPane2();
pane.add( mkp[i] );
st[i] =0l;
et[i]=0l;
}
//時刻設定パネル
this.setTitle("配水フレーム");
this.getContentPane().setPreferredSize(new Dimension(400,240));
this.pack();
//タイマースタート
timer = new Thread(this);
timer.start();
//ウインドウ関連イベント
addWindowListener(new frameClose());
this.setVisible( true );
//GPIOの設定
final GpioController gpio = GpioFactory.getInstance();
//個別のピン設定
pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_02, "MOTOR1", PinState.LOW);
//シャットダウン時のPIN設定
pin.setShutdownOptions(true, PinState.LOW);
}
class Haisui implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.println( "ボタンの状態:" + b.isSelected());
if(b.isSelected()){
b.setText( " 配水 " );
flug = true;
}else{
b.setText( " 停止 " );
flug = false;
}
}
}
/**
*formを閉じる場合の処理
*/
class frameClose implements WindowListener{
public void windowIconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e) {}
public void windowOpened(WindowEvent e){}
public void windowDeactivated(WindowEvent e) {}
public void windowClosing(WindowEvent e){
MizuKanri2.this.run=false;
}
public void windowClosed(WindowEvent e){
}
}
public void run()
{
Jikoku j = new Jikoku();
boolean bkflug = flug;
//無限ループ
do{
// 2000/1000秒休憩
try{ timer.sleep(2000);}catch(InterruptedException e){}
//System.out.println( "1");
for(int i=0;i<mkp.length;i++){
st[i] = mkp[i].getSt();
et[i] = mkp[i].getEt();
}
//いまの時刻を得る
long ima = j.getTodaymms();
flug = false;
for(int i=0;i<mkp.length;i++){
if(mkp[i].c1.isSelected()){
if( ima > st[i] ){ if( ima < et[i] ){ flug = true; } }
System.out.println("今"+ima+" 開始"+st[i]+" 終了"+et[i] +flug );
}
}
//ボタンチェック
if(b.getText().indexOf("配")>0){ flug = true; }
//フラグが変わったときの処理
if(bkflug==false){if(flug==true){
bkflug = flug;
tx.setText("現在の状態:配水中");
//GPIO設定
}}
if(bkflug==true){if(flug==false){
bkflug = flug;
tx.setText("現在の状態:停止中");
//GPIO設定
}}
}while(run);
}
}
時刻関連class。本来はほかにたくさんメソッドがあるのだけど、HP用に割愛。
package tomojavalib.raspberrypi;
import java.util.*;
public class Jikoku {
/**現在が今日始まってから何mm秒経過したかを返す*/
public long getTodaymms(){
Calendar c = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
int yr = c.get(Calendar.YEAR); int mn = c.get(Calendar.MONTH);
int dy = c.get(Calendar.DATE);
c2.set(yr, mn, dy, 0, 0, 0);
long l = c2.getTimeInMillis();
long l2 = c.getTimeInMillis();
l = l2-l;
return l;
}
}
時刻設定用のパネル
package tomojavalib.raspberrypi;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.*;
public class MizukanriPane2 extends Jpanel{
TJTextField t1;
TJTextField t2;
TJTextField t3;
JCheckBox c1;
public MizukanriPane2(){
t1 = new TJTextField( 10 , 1 , 0 , true ); t1.setMax(23); t1.setMin(0);t1.setPreferredSize(new Dimension(40,20));;
Jlabel l1 = new Jlabel("時 ");
t2 = new TJTextField( 0 , 1 , 0 , true ); t2.setMax(59); t2.setMin(0);t2.setPreferredSize(new Dimension(40, 20));
Jlabel l2 = new Jlabel("分 ");
Jlabel l3 = new Jlabel(" 継続時間");
t3 = new TJTextField( 10 , 10 , 0 , true ); t3.setMax(1800); t3.setMin(10);t3.setPreferredSize(new Dimension(60, 20));
Jlabel l4 = new Jlabel("秒 ");
c1 = new JCheckBox("使用");
this.setLayout( new FlowLayout(FlowLayout.LEFT, 5, 5));
this.add( t1 );this.add( l1 );this.add( t2 );this.add( l2 );this.add( l3 );this.add( t3 );this.add( l4 );this.add( c1);
}
public long getSt(){
long st = Long.parseLong( t1.getText() ) * 60l * 60l * 1000l + Long.parseLong( t2.getText() ) * 60l * 1000l;
return st;
}
public long getEt(){
long et = this.getSt() + Long.parseLong( t3.getText() ) * 1000l;
return et;
}
}
マウスホイールで数値を変更するためのテキストフィールド
package tomojavalib.raspberrypi;
import java.awt.Cursor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JTextField;
/**数値入力用のテキストフィールド*/
public class TJTextField extends JTextField {
//増減値
public double plus = 1.0;
//計算番号
public int kno=0;
//最大値最小値
public boolean maxflug = false;
public boolean minflug = false;
double maxt = 0.;
double mint = 0.;
//double/int表示
public boolean isint = false;
/**
*コンストラクタ
*S内容
*plus増加分
*kno計算NO
*intflug 表示をintにするか否か
*/
public TJTextField( double s ,double plus,int kno, boolean intflug ){
super();
this.isint = intflug;
if( this.isint ){ this.setText( (int)s + "" ); }else{ this.setText( s + "" ); }
this.plus = plus;
this.kno = kno;
this.setEvent();
}
public TJTextField(){ super( "0" ); this.setEvent();}
/**入力できる最大値をセット*/
public void setMax(double d){
this.maxt = d;
this.maxflug= true;
}
/**入力できる最小値をセット*/
public void setMin(double d){
this.mint = d;
this.minflug= true;
}
/**イベント設定*/
private void setEvent(){
//各テキスト内でマウスホイールが動かされた場合
this.addMouseWheelListener(new MouseWheelListener(){
public void mouseWheelMoved(MouseWheelEvent e){ mouseScroll( e ); }});
//各テキスト内にマウスが入った場合(マウスポインタの形状を変える)
this.addMouseListener(new MouseAdapter(){
public void mouseEntered(MouseEvent e){ mouseEnter( e ); }
public void mouseOut(MouseEvent e){ mouseOut( e ); }
});
}
private void mouseEnter( MouseEvent e ){ this.setCursor( new Cursor(Cursor.S_RESIZE_CURSOR ));}
private void mouseOut( MouseEvent e ){ this.setCursor( new Cursor(Cursor.TEXT_CURSOR ));}
/**マウススクロール時の設定*/
private void mouseScroll( MouseWheelEvent e ){
double d = Double.parseDouble(((TJTextField)e.getSource()).getText());
if( e.getWheelRotation()>0 ){ d=d+plus; }else{ d=d-plus; }
//最大最小チェック
if( maxflug ){ if( d>this.maxt ){ d=this.maxt; } }
if( minflug ){ if( d<this.mint ){ d=this.mint; } }
//intdouble表示
if( this.isint ){
this.setText( (int)d + "" );
}else{
this.setText( d + "" );
}
//以降のコントロールにイベントを渡さない
e.consume();
}
public int getInt(){ return Integer.parseInt( this.getText()); }
public double getDouble(){ return Double.parseDouble( this.getText()); }
}
最終更新日: 2017-05-29 15:22:42
ともさんのHP >ものつくり >ラズパイ(Raspberry Pi)で電子工作 >RaspberryPi用Javaサンプルプログラム
ツイート