ホーム » t-saitoh の投稿 (ページ 148)

作者アーカイブ: t-saitoh

2025年6月
1234567
891011121314
15161718192021
22232425262728
2930  

検索・リンク

ビニールハウスの制御システム

連携事業での取り組みの案として、 エコへの取り組みを農業に応用できれば、 面白そうとのアイデアを頂き、 ビニールハウスの制御システムについて検討してみた。

丁度、卒業研究で組み込み系の通信システムに興味を 持っている人がいるので、XBeeを用いた無線通信ネットワーク を構築し、このビニールハウスの制御システムに適用 することを卒研テーマにしようと検討している。

さて、うまくシステム構築の話に結びつくかな….

1205211442_605x442.png

前川先生のエコ実践

前川先生は、卒業研究でも太陽電池パネルの太陽光追尾システムを構築し、 常時動かしている電波実験設備の給電にも利用している。

機械工業会さんとの連携事業でエコシステム構築で、追尾システムの お話を聞いていたら、太陽電池をさらに興味深いエコ利用を 試されているみたい。

1205191155-2_320x240.jpg
1205191155-3_320x240.jpg

太陽光発電で自宅菜園の貯水システム

休耕田の自宅菜園の散水用の水を、太陽光発電で貯水する実験をしているとのこ とであった。

1205191155_320x240.jpg
1205191155-1_320x240.jpg

(前川先生): 休耕田で野菜を作っています。 夏場の水やりのために自動車用バッテリーとインバータ でバスポンプを動かして、田んぼの中に置いた水槽に水をためています。

バッテリーにソーラーパネルをつないで充電をしています。 田んぼの中に置いてある水槽は、80リッターのもので1980円でした。 バスポンプは、直接12Vで動かすことも出来、約1A電流が流れます。 1000円ほどのポンプで1分8リットルから10リットルの水を吸い上げられます。 2000円だとその倍の水が汲めます。 5000円も出すとさらに大きいものがあります。

放っておくと水があふれるので、タイマーを付けようと考えています。 今のところ水槽とホースを3組用意しています。

Arduino+Xbee Shield/Pr…(05/18)

この記事は、twitter の @TohruSaitohに掲載した #fnct タグ付き記事を、まとめたものです。


60%の人間はプログラミングの素質がない…

個人的には、なかなか、的を得た数字のように思うな…

「ふたこぶラクダ」という名前の有名な論文に書かれているんだってさ。

引用:プログラミングの素質は、構築したメンタルモデルを、 ブレずに一貫して適用できるかどうかにかかっているようだ。

それぞれのプログラミング言語の都合に合わせて、動くようにプログラムを書くのだから、 わけのわからない言語のルールに、ブレずにしたがって頭の中で動く様をシミュレートできるか…って感じかな。

引用:一貫したグループにプログラミングを教育するのは、はるかに簡単である。 このグループは、観測的に、さらにふたつに分かれるようだ。 ひとつは、プログラミングを非常に簡単に感じ、プログラミングを楽しみ、 その後も成長してソフトウェアを書く良いプログラマーになるグループ。 もうひとつのグループは、プログラミングはできるものの、 それ自体には楽しみを見出さず、管理職になってUML図に溺れるグループ(やれやれ)。

爆笑….

ヒープメモリの演習

先週のmalloc+freeの説明後ということで、今日は演習の時間とした。

ヒープメモリ演習テーマ

大きさの解らないデータを入力し、何らかの処理を加えて出力する。 例えば、きわめて長い名前の人がいるかもしれないクラスの名簿を読み込む。 名簿の人数は、プログラム作成時は解らないものとする。 もしくは、成績表の集計を行うプログラムを作る。ただし、科目数や対象人数は変更できること。 演習の自信の無い人は、プログラムを実行し処理を始める前に、 データ件数を入力などを入力するという方法でもよい。

途中で配列サイズを変えるテクニック

最初にデータ件数などを入力するのは、現実の処理ではあまりない。 プログラミングでよく使われるテクニックは、 あらかじめ適当な大きさで配列を作り、その中にデータを保存していく。 途中で配列サイズからあふれる場合は、新しく2倍の大きさの配列を確保し、 新しい配列に、元の配列の中身をすべてコピーする。 そのあと、配列を指すポインタを、2倍の配列側に切り替え、元々の配列はfreeで廃棄する。

C++でのnewとdelete

前回の授業では、malloc+freeを用いたけど、最近はオブジェクト指向のC++を使うことが多い。 簡単に、new-deleteの使い方を説明する。

// C言語であれば
int size = 適当な大きさ ;
int *p ;
if ( (p = (int*)malloc( sizeof( int ) * size )) != NULL ) {
pを配列として使った処理... ;
free( p ) ;
}
// C++であれば、
p = new int[ size ] ; // C++ではメモリ確保失敗は例外処理で対応
pを使った処理... ;
delete [] p ;         // [] は配列をdeleteする場合のみ

deleteの[]をつける意味が分かりにくいので、普通の使い方の例を、おまけで書いておく。

struct A {
なんらかの要素 ;
} *p ;
// C言語の場合
if ( (p = (struct A*)malloc( sizeof(struct A) )) != NULL ) {
pの構造体を使った処理 ;
free( p ) ;
}
// C++の場合
p = new A ;
pの構造体を使った処理 ;
delete p ;

ポインタ処理と演習

前回のN進数変換のプログラム演習で、 まだまだ完成していない人が多いようなので、前半で説明・後半を演習とした。

ポインタ演算の説明として、以下のような例をしめす。 関数とのポインタ渡しなどは説明済み。

int  a[ 4 ] = { 11 , 22 , 33 , 44 } ;
int*p = a ;
printf( "%d" , *p + 1 ) ;   // 11 + 1 = 12
printf( "%d" , *(p + 1) ) ; // ひとつ後ろの場所22
p += 2 ;
printf( "%d" , *p ) ;       // 参照場所を2つ後ろに移動33
printf( "%d %d" , *(p + 1) , p[ 1 ] ) ;  // 44,44 ポインタ記述
printf( "%d %d" , *(p - 1) , p[ -1 ] ) ; // 22,22 と配列記述

また、ポインタを動かしながら参照などの理解をするために、 前置インクリメント、後置インクリメントの違いを説明。

// ポストインクリメント
int x = 1 ;
printf( "%d" , x++ ) ; // printfの後に増やす。
printf( "%d" , x++ ) ; // 1 2 を表示
// プレインクリメント
int x = 1 ;
printf( "%d" , ++x ) ; // printfの前に増やす。
printf( "%d" , ++x ) ; // 2 3 を表示

以上のネタが解かった所で、配列加算とstrcpyの例を示す。

// 配列で0までの数値を加算する
int a[ 4 ] = { 12 , 23 , 34 , 0 } ;
int s = 0 ;
for( i = 0 ; a[i] != 0 ; i++ )
s += a[i] ;
// forの部分をポインタ移動に書き換え
int *p = a ;
while( *p != 0 )
s += *p++ ;

C言語の標準関数のstrcpyの中身を色々な書き方で示す。返り値はひとまずvoidにて… これにより、ポインタの移動処理と、条件判定が0/0以外であることを説明する。

void strcpy( char*t , char*s ) {
for( int i = 0 ; s[i] != '¥0' ; i++ )
t[i] = s[i] ;
}
// forの部分を次々と書き変える
for( ; *s != '¥0' ; s++ , t++ ) // コンマ演算子にも注意
*t = *s ;
while( *s != '¥0' ) // ポストインクリメントを使って
*t++ = *s++ ;
while( (*t++ = *s++) != '¥0' ) ; // 条件内で代入
while( *t++ = *s++ ) ; // 偽=0,真=0以外

継承と仮想関数

オブジェクト指向の授業での、前回までのカプセル化の次の段階として、 継承について説明を行う。

継承(派生)

データを扱っている際に、基本的な部分では共通性があるけど、 様々なバリエーションが存在するデータには、継承(派生)が使われる。

例として人の情報に、親子関係を表すデータを追加する場合を考える。 これを構造体で実装すると、追加されたデータ側で、同じような処理を 沢山書く必要がでてくる。

// C言語ベースで破綻する例
// 元となるデータ構造
struct Person {
char name[ 10 ] ;
int  age ;
} ;
void setPerson( struct Person* p , char* s, int a ) {
strcpy( p->name , s ) ;
p->age = a ;
}
void printPerson( struct Person* p ) {
printf( "%s %d" , p->name , p->age ) ;
}
// 子どもの情報をもつ拡張したデータ
struct Parent {
struct Person  base ;
struct Person* child ;
} ;
void setParent( struct Parent* p ,
char* s , int a , struct Person* c ) {
setPerson( p , s , a ) ;
child->child = c ;
}
void main() {
struct Person mitsuki ;
setPerson( &mitsuki , "mitsuki" , 12 ) ;
struct Parent tohru ;
setParent( &tohru , "tohru" , 47 , &mitsuki ) ;
printPerson( &mitsuki ) ;
printParent( &tohru ) ; // printParent() を書く必要あり。
// 名前と年齢を表示したいだけなのに...
}

これと同じようなプログラムは、C++であれば派生を使って簡単にかける。

class Person { // 基底クラス
private:
char name[ 10 ] ;
int  age ;
public:
Person( char*s , int a ) {
strcpy( name , s ) ; age = a ;
}
void print() {
printf( "%s %d" , name , age ) ;
}
} ;
class Parent : public Person { // 派生クラス
private:
Person* child ;
public:
Parent( char* s , int a , Person* c )
: Person( s , a )  // 基底クラスのコンストラクタの呼び出し
{ child = c ; }
} ;
void main() {
Person mitsuki( "mitsuki" , 12 ) ;
Parent tohru( "tohru" , 47 , &mitsuki ) ;
mitsuki.print() ;
tohru.print() ; // 継承により"tohru 47"が表示できる
}

上記のtohru.print() の様に、基底クラスの同名メソッドを流用できることを、 継承と呼ぶ。

仮想関数

上記の派生クラスで、Parentを表示する時に、子どもも一緒に表示させたければ、 以下の様に派生クラスでprint()を再定義しても良い。

class Parent : public Person {
     :
public:
void print() {
Person::print() ;  // 基底クラスメソッド呼び出し
child->print() ;
}
} ;
void main() {
    :
tohru.print() ; // "tohru 47 mitsuki 12" の表示。

しかし、親子関係がもう1世代加わるとどうなるか?

void main() {
Person mitsuki( "mitsuki" , 12 ) ;
Parent tohru( "tohru" , 47 , &mitsuki ) ;
Parent kinmatsu( "kinmatsu" , 78 , &tohru ) ; // 型の不一致?
}

本来なら、&tohru は、Parent*型。 Parent::Parent(char*,int,Person*)コンストラクタ第3引数は、Person*型で型が違う。 しかし、オブジェクト指向では、 派生クラスのポインタは、安全に基底クラスのポインタに暗黙の変換が可能なので、 問題は無い。

一方で、以下の命令を実行した場合、何が表示されるのか?

kinmatsu.print() ; // kinmatsu 78 tohru 47 までしか表示されない。

これは、Parent型のchildは、Person型であり、tohruを表示しようとしても、 すでに"Person"の子供なしと思われてしまっている。 ここで、tohru は、元々Parent型であり、孫のmitsuki まで表示したい場合は、 どうすべきか?データ自信が、自分は"Person"なのか"Parent"なのか知っていれば、都合がよい。こういう場合は、仮想関数にて宣言する。

class Person {
   :
private:
virtual void print() {
printf( "%s %d" , name , age ) ;
}
} ;
class Parent : public Person {
   :
private:
virtual void print() {
Person::print() ;
child->print() ; // 仮想関数呼び出し
}
} ;

この例では、kinmatsu.print() を実行する時に、child->print() を実行する場合には、 tohruは、Parent型なので、Parent::print() を呼び出し、tohru.print()の時には、 mitsukiは、Person型なので、Person::print() を呼び出してくれる。

"virtual"を使うと、データ構造の中に、型情報が自動的に埋め込まれるため、 このような、データに応じた処理の呼び分けが可能となる。

質問で、virtual のキーワードを一方にしか付けなかったらどうなるの? ということで、調べてみた。 基底クラスで virtual 付き、派生クラスで virtual 無しだと、両方に付けた時と同じ動きとなった。資料をみると、派生クラスでは virtual は書かなくてもいいとのことであった。 一方、基底クラスで virtual 無し、派生クラスで virtual 有りだと、 処理の呼び分けができなかった。 うーん昔、書き間違えてvirtual忘れた時には、エラーが出た記憶があるのだが…

キャンパスウォーク・デモ(part2)

H8とLEDパネルで、テト◯スを動かしてくれました。 デモのためとはいえ、一晩で作ってくれました。

剛体の衝突運動シミュレーションの説明中。 難しいお話の前段階。

低学年での実験の雰囲気を説明するために、 トランジスタで音声を増幅…の説明中。

キャンパスウォーク(5/12)

5/12には、中学生への学校紹介ということで、キャンパスウォークが開催されました。 電子情報工学科でも、ロボットやプロコン作品の説明など、 幅広く内容を見てもらいました。

1205121117_320x240.jpg

本日5/12は、キャンパスウォーク

今日は中学生向けのキャンパスウォーク、 電子情報では、電子系実験・プロコン・ロボットなどを見てもらいました。

動画での様子

スナップ写真

スタンプウォークラリー形式なので、各ブース見学でスタンプを押してもらいます。 途中で校長先生と出会うと、1ポイント追加ゲット。

1205121117_320x240.jpg

昨年度の高専プロコン作品の紹介中

1205121117-2_320x240.jpg

電子情報デモの電脳メガネをかける校長先生。

1205121117-1_320x240.jpg

システム

最新の投稿(電子情報)

アーカイブ

カテゴリー