某ファブ施設スタッフの落書き

某ファブ施設で働くスタッフの気まぐれな日記のようなものです。

RaspberryPi3 ファンボード


概要
RaspberryPi2→3にアップグレード。
Bluetooth、無線モジュール等を使用すると発熱していたのでファンを装着することにした。


加工
レーザーカッターでアクリル板をカット。
AutoCadLT(.dxf)→Illustrator(.ai)→JobController(jobfile)

風量と動作も良好
f:id:hogerian1306:20160904000732j:plain


ファンは下記を使用
akizukidenshi.com

c言語でデータ構造 ~hash~

概要
keyによって生成(ハッシュ)されたハッシュ値を添え字としてデータを扱うデータ構造。
データが格納された集合体をハッシュテーブル、ハッシュ値の衝突をコリジョンという。

ハッシュ方法については
http://docs.oracle.com/cd/E19253-01/819-0391/chapter6-48031/index.html
を参考にしました。

☆ソースだけ載せます。

<ソース>
構造

typedef struct hash_element {	// ハッシュテーブルに格納される一要素
  char *key;			// キー
  char *value;			// キーに対応する値
  struct hash_element *next;	// 次の要素(シノニム)へのポインタ
} HASH_ELEMENT;

typedef struct {		        // ハッシュテーブルはこのデータ型の配列
  int count;			// このエントリを共有するシノニムの数
  HASH_ELEMENT *element;	// 格納する要素(キーと値のペア)へのポインタ
} HASH_ENTRY;

サイズの定義

#ifndef TBL_SIZE		
 #define TBL_SIZE 6007		// TBL_SIZE(ハッシュテーブルサイズ)
#endif
#define KEY_LEN 32		// キーの最大サイズ
#define VAL_LEN 256		// 値の最大サイズ
// 操作関数①:ハッシュテーブルの初期化(tbl[]の全要素のcountを0に、elementをNULLにする)
//	tbl[]	:ハッシュテーブル
//	tbl_size:ハッシュテーブルのサイズ
//	戻り値	:なし
void initHashTable(HASH_ENTRY tbl[], int tbl_size)
{
  int i;

  for(i=0;i<tbl_size;i++){
    (tbl+i)->count = 0;
    (tbl+i)->element = (HASH_ELEMENT *)NULL;
  }

  return;
}
// 操作関数②:キーと値からなる要素を動的に生成する
//	key	:キー
//	value	:キーに対応する値
//	戻り値	:正常に生成できたとき     = 生成した要素へのポインタ
//		:メモリ確保に失敗したとき = NULL
HASH_ELEMENT *makeElement(char *key, char *value)
{
  HASH_ELEMENT *newelement;

  newelement = malloc(sizeof(HASH_ELEMENT));
  newelement->key = malloc(sizeof(char)*KEY_LEN);
  newelement->value = malloc(sizeof(char)*VAL_LEN);

  if(newelement == NULL || newelement->key == NULL || newelement->value == NULL){
    return(NULL);
  }
  strcpy(newelement->key,key);
  strcpy(newelement->value,value);
  newelement->next = (HASH_ELEMENT *)NULL;

  return(newelement);
}
// 操作関数③:キーに対応する要素を検索する
//	tbl[]	:ハッシュテーブル
//	key	:検索するキー
//	戻り値	:キーが見つかったとき = キーに対応する要素へのポインタ
//		:キーが見つからなかったとき = NULL
HASH_ELEMENT *searchElement(HASH_ENTRY tbl[], char *key)
{
  HASH_ELEMENT *searchelement;
  int flg,i;
  unsigned int hashvalue;

  hashvalue = hash(key,TBL_SIZE);
  flg = 0;
  if(tbl[hashvalue].count == 0){
    return(NULL);
  }else{
    searchelement = tbl[hashvalue].element;
    while((searchelement != (HASH_ELEMENT *)NULL) && flg == 0){
      if(strcmp(searchelement->key,key) == 0){
	flg = 1;
      }else{
	searchelement = searchelement->next;
      }
    }
  }

  if(flg == 0){
    return(NULL);
  }else{
    return(searchelement);
  }
}
// 操作関数④:キーに対応する値のみを取得する
//	tbl[]	:ハッシュテーブル
//	key	:検索するキー
//	戻り値	:キーが見つかったとき       = キーに対応する値(文字列)へのポインタ
//		:キーが見つからなかったとき = NULL
char *getValue(HASH_ENTRY tbl[], char *key)
{
  HASH_ELEMENT *searchelement;

  searchelement = searchElement(tbl,key);

  if(searchelement == NULL){
    return(NULL);
  }else{
    return(searchelement->value);
  }
}
// 操作関数⑤:キーとそれに対応する値からなる要素をハッシュテーブルに挿入する
//	tbl[]	:ハッシュテーブル
//	key	:検索するキー
//	value	:キーに対応する値
//	戻り値	:正常に追加できたとき     = 1
//		:メモリ確保に失敗したとき = 0
int insertElement(HASH_ENTRY tbl[], char *key, char *value)
{
  HASH_ELEMENT *buff;
  unsigned int hashvalue;

  hashvalue = hash(key,TBL_SIZE);

  if(tbl[hashvalue].element == 0){
    tbl[hashvalue].element = makeElement(key,value);
    if(tbl[hashvalue].element == NULL){
      return(0);
    }
    tbl[hashvalue].count = 1;
  }else{
    buff = tbl[hashvalue].element;
    tbl[hashvalue].element = makeElement(key,value);
    if(tbl[hashvalue].element == NULL){
      return(0);
    }
    tbl[hashvalue].element->next = buff;
    tbl[hashvalue].count += 1;
  }
  return(1);
}
// 操作関数⑥:指定したキーがあればその値を更新し、なければ新たに要素を挿入する
//	tbl[]	:ハッシュテーブル
//	key	:検索するキー
//	value	:キーに対応する値
//	戻り値	:更新または追加できたとき = 1
//		:メモリ確保に失敗したとき = 0
int updateElement(HASH_ENTRY tbl[], char *key, char *value)
{
  HASH_ELEMENT *updatehash;
  int check;
  unsigned int hashvalue;

  updatehash = searchElement(tbl,key);

  if(updatehash == NULL){
    if(insertElement(tbl,key,value) == 0){
      return(0);
    }
  }else{
    strcpy(updatehash->value,value);
  }
  return(1);
}
// 操作関数⑦:キーで要素を検索し、見つかった要素を削除する
//	tbl[]	:ハッシュテーブル
//	key	:検索するキー
//	戻り値	:キーが見つかり要素を削除したとき = 1
//		:キーが見つからなかったとき       = 0
int removeElement(HASH_ENTRY tbl[], char *key)
{

  HASH_ELEMENT *removeelement,*prev;
  int flg,check=1;
  unsigned int hashvalue;

  hashvalue = hash(key,TBL_SIZE);
  flg = 0;
  if(tbl[hashvalue].count == 0){
    return(0);
  }else{
    removeelement = tbl[hashvalue].element;
    prev = removeelement;
    while((removeelement != (HASH_ELEMENT *)NULL) && flg == 0){
      if(strcmp(removeelement->key,key) == 0){
        flg = 1;
      }else{
	prev = removeelement;
	removeelement = removeelement->next;
	check++;
      }
    }
  }

  if(flg == 1){
    prev->next = removeelement->next;
    tbl[hashvalue].count -= 1;
    free(removeelement->key);
    free(removeelement->value);
    free(removeelement);
    return(1);
  }else if(check == 1){
    removeelement = removeelement->next;
    tbl[hashvalue].count -= 1;
  }else{
    return(0);
  }
}
// 操作関数⑧:ハッシュテーブルの要素をすべて削除する(メモリを解放する)
//	tbl[]	:ハッシュテーブル
//	tbl_size:ハッシュテーブルのサイズ
//	戻り値	:なし
void freeHashTable(HASH_ENTRY tbl[], int tbl_size)
{
  int i;
  HASH_ELEMENT *element,*buff;

  for(i=0;i<tbl_size;i++){
    element = (tbl+i)->element;
    while(((tbl+i)->count) != 0){
      if((tbl+i)->count > 1){
        buff = element;
	element = element->next;
      }else{
	buff = element;
      }
      free(buff);
      (tbl+i)->count -= 1;
    }
    free(tbl+i);
  }

  return;

}
// 操作関数⑨:ハッシュテーブルのすべての要素をキーと値のペアで表示する
//	tbl[]	:ハッシュテーブル
//	tbl_size:ハッシュテーブルのサイズ
//	戻り値	:なし
void printHashTable(HASH_ENTRY tbl[], int tbl_size)
{
  int i,count;
  char *value,*key;
  HASH_ELEMENT *element;

  printf("Index  Key                  Value\n");
  printf("-------------------------------------------------------------------------\n");
  for(i=0;i<tbl_size;i++){
    count = tbl[i].count;
    if(count != 0){
      element = tbl[i].element;
      while(element != (HASH_ELEMENT *)NULL){
	printf("%4d:  %-20s %-20s\n",i,(element->key),(element->value));
	element = element->next;
      }
    }
  }

  return;

}
// 操作関数⑩	:キーからハッシュ値を求める ELFhash
//	tbl_size:ハッシュテーブルのサイズ
//	戻り値	:ハッシュ値(ハッシュテーブルのサイズを超えない非負整数)
unsigned int hash(unsigned char *key, int tbl_size)
{
  unsigned long hash_value,g;

  hash_value = 0;

  while(*key){
    hash_value = (hash_value<<4)+*key++;
    if(g = hash_value & 0xf0000000){
      hash_value ^= g>>24;
    }
    hash_value &= ~g;
  }
  return(hash_value % tbl_size);
}

RobotArm ~開発継続中~

概要
プロフィール画像にもあるロボットアームを紹介します。
元々は、高校時代に研究していた作品だったのですが、現在も少しずつ改良しているところです。
以前の状態では、予めプログラムされた位置の物体しか掴めません。
なので、カメラから物体を自動認識して掴めるように現在OpenCVと格闘中です。

画像
f:id:hogerian1306:20160601213148j:plain:h300:w600

こだわりポイントとしては、せっかく部品や基板といったところから作ったので中のコンピュータ、モーターが見えるように本体の上部はアクリル板を加工したものをはめ込んであります。
f:id:hogerian1306:20160601213205j:plain:h200:w350

 RaspberryPiのロゴの部分はファンの換気口。
         f:id:hogerian1306:20160601213208j:plain:h350:w250

構造
コンピュータ:RaspberryPi2
    言語:Python

クロスケーブルで接続したPCとターミナルからSSHで接続します。

本体に近いアームにDCモーター、先端のアームには、軽量なサーボモーターを使用しています。
DCモーターを使用するアームは、ポテンショメータ(角度センサー)を取り付けてあり、フィードバックして角度制御しています。

補足
動作動画、回路図等は今後更新します。

c言語でデータ構造 ~list~

概要
基本的なデータ構造の一つ。単方向リスト。
ノード(要素)は次のノードの情報(ポインタ)を持つ。

☆ソースだけ載せます。

実装
リストの構造を定義

typedef struct cell{
  int data;
  struct cell *next;
}LIST;
//[機能]リストの初期化
//[返り値]空リストへのポインタ (LIST *)NULL
LIST *initList(void)
{
  return(((LIST *)NULL));
}
[機能]与えられたリストが空リストかどうか判定
[引数]*head:リストの先頭へのポインタ
[返り値]headが空リスト:1,headが空リストではない:0
int isEmptyList(LIST *head)
{
  if(head == ((LIST *)NULL)){
    return(1);
  }else{
    return(0);
  }
}
//[機能]新しいセルをリストの先頭へ挿入する
//[引数]**head:リストへの先頭アドレスを格納している変数へのポインタのポインタ
//    data:リストの先頭へ挿入するセルの整数値データ
//[返り値]追加に成功:1,失敗した:0(元のリストは不変)
int insertHead(LIST **head,int data)
{
  LIST *newcell;
  
  newcell = ((LIST *)malloc(sizeof(LIST)));
  if(newcell == NULL){
    return(0);
  }else{
    newcell->data = data;
    newcell->next = *head;
    *head = newcell;
    return(1);
  }
}
//[機能]リストの先頭セルを削除する
//[引数]**head:リストの先頭アドレスを格納している変数へのポインタのポインタ
//[返り値]正常削除:1,空リストから削除:0
int removeHead(LIST **head)
{
  LIST *buff;

  if(isEmptyList(*head)){
    return(0);
  }else{
    buff = *head;
    *head = (*head)->next;
    free(buff);
    return(1);
  }
}
//[機能]リストに格納されているデータを先頭から順に表示する
//[引数]*head:リストの先頭セルへのポインタ(リストの先頭アドレス)
void printList(LIST *head)
{
  LIST *buff;
  
  for(buff=head;isEmptyList(buff)==0;buff=buff->next){
    if(isEmptyList(buff->next)){
      printf("%d",buff->data);
    }else{
      printf("%d -> ",buff->data);
    }
  }
  return;
}

RaspberryPiでA/D変換を使う

概要:
RaspberryPiはA/Dコンバータが搭載されていません。このままではアナログ値を出力するセンサー群を使うことができません。(I2C,SPIのモジュールを作れば…)
そこで今回は、RaspberryPiでアナログ値を読み取る方法を書きます。

通信方法:SPI
  言語:Python

部品:
・MCP3208(12bit8chA/Dコンバータ)
f:id:hogerian1306:20160504153814p:plain:h160:w250
画像引用:http://akizukidenshi.com/catalog/g/gI-00238/

データシート:
startとchannel情報、合わせて5bit送信することでA/Dコンバータ側に求めるchannelを指定する。
f:id:hogerian1306:20160510231042p:plain:h400:w250

受信するデータはもちろん12bit(A/Dコンバータの分解能)
f:id:hogerian1306:20160510232406p:plain
データシート一部参照


回路:
f:id:hogerian1306:20160510213002p:plain:h240:w360

プログラム:
使用するピン

SPI_CLK = 11
SPI_MOSI = 10
SPI_MISO = 9
SPI_SS = 8

GPIOのI/O設定

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO.setup(SPI_CLK,GPIO.OUT)
GPIO.setup(SPI_MOSI,GPIO.OUT)
GPIO.setup(SPI_MISO,GPIO.IN)
GPIO.setup(SPI_SS,GPIO.OUT)

アナログ値取得関数

def getMCP3208(channel):
  GPIO.output(SPI_SS,False)
  GPIO.output(SPI_CLK,False)
  GPIO.output(SPI_MOSI,False)
  GPIO.output(SPI_CLK,True)
  GPIO.output(SPI_CLK,False)

  order = (channel | 0x18) << 3
  for i in range(5): #データシート参照
    if (order & 0x80):#マスクを取り1bitずつ送信する
      GPIO.output(SPI_MOSI,True)
    else:
      GPIO.output(SPI_MOSI,False)
    order <<= 1
    GPIO.output(SPI_CLK,True)
    GPIO.output(SPI_CLK,False)
  
  GPIO.output(SPI_CLK,True)
  GPIO.output(SPI_CLK,False)
  GPIO.output(SPI_CLK,True)
  GPIO.output(SPI_CLK,False)

  value = 0
  for i in range(12): #12bitのデータを受信する
    value <<= 1
    GPIO.output(SPI_CLK,True)
    if(GPIO.input(SPI_MISO)):
      value |= 0x1
    GPIO.output(SPI_CLK,False)

  GPIO.output(SPI_SS,True)
  return value

c言語でデータ構造 ~queue~

概要
基本的なデータ構造の一つ。FIFO(FirstIn,FirstOut)先に挿入されたデータから先に取り出される構造をもっている。

操作
・enQueue
キューにデータを挿入する
・deQueue
キューからデータを取り出す

実装

#define Head (q->head)
#define Tail (q->tail)
#define Storage (q->storage)

キューの構造を定義

typedef struct{
  int storage[QUEUE_SIZE];
  int head;
  int tail;
}QUEUE;
//[機能]キューを初期化し、空の状態にする
//[引数]q:初期化するキュー(ポインタ)
void initQueue(QUEUE *q){
  Head = 0;
  Tail = 0;
  return;
}
//[機能]キューにデータを格納する
//[引数]*q:データの格納対象となるキュー(ポインタ)
//      data:格納するデータ
//[返り値]正常終了:1 ,キューが満杯(オーバーフロー):0
int enQueue(QUEUE *q,int data)
{
  if((Tail+1)%(QUEUE_SIZE)==Head){
    return(0);
  }else{
    Storage[Tail] = data;
    Tail = (Tail+1)%(QUEUE_SIZE);
    return(1);
  }
}
//[機能]キューからデータを取り出す
//[引数]*q:データの取り出し対象となるキュー(ポインタ)
//      *data:取り出したデータの格納先(ポインタ)
//[返り値]正常終了:1 ,キューが空(アンダーフロー):0
int deQueue(QUEUE *q,int *data)
{
  if(Head == Tail){
    return(0);
  }else{
    *data = Storage[Head];
    Head = (Head+1)%(QUEUE_SIZE);
    return(1);
  }
}