ともさんのHP >ものつくり >ラズパイ(Raspberry Pi)で電子工作 >RaspberryPi用Javaサンプルプログラム

RaspberryPiとJavaで水遣りプログラム

RaspberryPiを使って毎日決まった時間に水ポンプを動かす装置を作りました。
Javaで作ったプログラムと回路図などを公開しています。
raspberrypi操作GUIプログラム

広告


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のモーター駆動回路を参考に、というか、ほぼそのまま利用して作りました。
モータードライバーとターミナルブロックは秋月電子通商で購入。
ラズパイモーター駆動回路 RaspberryPi Motor

こんな感じです。10年ぶりくらいにはんだ付け作業。芋はんだになってしまいましたが、まあ、大丈夫。 所定の抵抗が手持ちになかったので、いくつか直列に並べました。

RaspberryPiのPIN配置

今回使ったピンは下の図の通り。
RaspberryPi3の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サンプルプログラム

広告
新着ページ

AIを利用し、衣服のデザイン画から型紙を制作する方法  
2つのアパレル3D技術でひらくオーダーメイド生産の手法  
【洋裁型紙】前後身頃の肩の傾きは何故前身頃の方が傾いているのか  
電子追尾式天体写真撮影法  
日本ミツバチ巣箱の種類  
ドラフター(製図台)でソーイング  
日本ミツバチが逃亡  
カメさんの箱庭  
天体用デジタルカメラの構造と天体写真  
Javaで静止画像(Jpeg)を動画(Mov)に変換  
USBカメラをJAVAで制御  

他のサイト

3D-CAD
洋裁CAD

いいねなど

 RSS 

Author: Tomoyuki Ito

このサイトの文章・写真の無断転載を禁じます