一般社団法人 WNI 気象文化創造センター

https://www.wxbunka.com/

観客賞 賞金 5 万円
ジキル博士と hide(high voltage
demonstrator)氏
香川高等専門学校高松キャンパス

お天気実況アイス、スーちゃん
大阪教育大学付属高等学校天王寺校舎

2017 年第 6 回高校・高専気象観測機器コンテスト

磁気ル博士とhide 氏香川高等専門学校

1

4年

岩井
笠松
村田

亮大
雅史
優斗

1. 目的周辺の磁界と雷との関連性を示しかつ電磁誘導による過電流を防止する。
2. 導入
図 2-1 のように変電所から各施設に電力が供給されていることを考える。

図 2-1 配電図
仮に送電線付近に雷が落ちたと仮定する。ここで送電線又は配線系統の物は全て抵抗、誘導性リアクタンス、容量性リアクタンスの複合素子と考えられるので周辺に高圧がかかり電流が流れた場合には電磁誘導により送電線にも電流が流れる。このときに過電流によりあたかも落雷が送電線に落ちたかのように配線している機器が故障したりする。これが誘導雷というものである。(図 2-2)
このときの磁界を検出し過電流を GND（地表）に逃がすことができれば誘導雷による被害は防げる。
（図 2-3）

図 2-2 誘導雷

図 2-3 避雷回路

実際に機器が損傷する程の誘導雷を観測することは確率的に現実的ではないので高圧発生装置(high voltage demonstrator:hide: hide 氏)を用いることで仮想的に雷（電力は極小）を発生させその磁場を検出した。

2

3. 磁気ル博士
3.1 概要磁気ル博士（磁気観測装置）の外形を図 3.1-1 に示す。磁気ル博士はセンサ部と制御部に分かれ、センサ部には 3 軸磁気センサ（HMC5883L※今回は X,Y の 2 軸のみ使用）及びキャリブレーション用のモータがあり制御部には arduino、モバイルバッテリー、L6470 モー
タ制御 IC がある。（図 3.1-2）

センサ部
制御部

図 3.1-1 外形

図 3.1-2 制御部内部
3.2 センサ部
磁気センサをそのまま使うと電波や微量の磁気ノイズも検出する恐れがあるので周囲の安定磁界のみを計測するために高周波シールドの中にセンサを設置した。（図 3.2-1）
今回高周波シールドに用いた素材は銅で（図 3.2-2）、制御部のシールドには磁性体である
ステンレスを用いた。またセンサ部と制御部をつなぐ I2C 用のケーブルには同軸ケーブルを用いて信号ノイズを減衰させた。
3

HMC5883L

図 3.2-1 センサ部

図 3.2-2 高周波シールド

3.3 制御部
制御部ではセンサを校正（キャリブレー

L6470ション）するためにステッピングモータを使用した。ステッピングモータを arduino から直接制御することは難しいので、L6470（モータ制御 IC）を用いた。（図 3.3-1）
PC と arduino での通信には Xbee を用いて行った。また、L6470 と arduino の通信
は SPI 通信を用いて行った。これらの接続を簡易モデル化したものを図 3.3-2 に示した。

図 3.3-1 arduino と L6470

I2C
HMC5883L

Xbee
PC

Arduino

SPI
L6470
モータ

図 3.3-2 配線図
4

3.4 校正
磁気センサは自身の回路内部の磁界による影響でセンサを回転させたとき方向によって誤差が生じる。それを改善するためにはセンサを校正（キャリブレーション）しなければならない。（図 3.4-1）

図 3.4-1 キャリブレーション前（左）と後(右)の例
このキャリブレーションを正確に行うためにステッピングモータを用いた。手動で回転させた場合、中心がずれ、誤差を生じる場合があるため、モータを用いた ACS(AutoCalibration System)で精度を高めた。
モ ー タ の 中 心 に セ ン サ を 置 き 回 転 さ せ デ ー タ 取 得 す る こ と で X,Y の 最 大 値
X_Max,Y_Max と最小値 X_Min,Y_Min を求めそれから円の中心座標を求めた。キャリブ
レーション前の円の中心座標(X,Y)の値を(X_OFFSET,Y_OFFSET)とすると以下の式で表すことができる。
X_OFFSET

X_Max

X_min /2

(1)

Y_OFFSET

Y_Max

Y_min /2(2)

上式(1)(2)で求めた値を用いて測定値を(X,Y)を以下の式で補正した。
X

X

X_OFFSET

(3)

Y

Y

Y_OFFSET(4)

機器を動作させる前に PC から校正コマンドを Xbee 通信で送ることによりキャリブレー
ションを行うことができる。
なお、円は 3 点によって求めることができるが、そうするとデータのばらつき具合によっては誤差が大きくなるためデータ量を増やす必要があるため上記の方法で行った。
今回は基本ステップ角 1.8°のステッピングモータを用いた。

5図 3.4-2 フローチャート
校正プログラムのフローチャートを図 3.4-2 に示した。
このプログラムはモータを 7.2°ずつ動かして 50 回（360°）測定を行うものである。モータは電磁石によって構成されているためモータを回転させながら測定すると、電磁石によるノイズを拾ってしまい正しいデータが測定できなくなる。そこでモータを停止させ500ms 待機した後センサで測定することによりモータの磁界による影響を受けなくしている。また、センサで測定するたびに X_Max,

Y_Max,X_Min,Y_Min の値を判定して代入し50 回（360°）測定を行った後 X_OFFSET,Y_OFFSET の値を算出している。
なお、モータを－180°回転させていることでセンサ部と制御部をつなぐ同軸ケーブルが絡まらないようにするためである。
6

4. 高圧発生装置(high voltage demonstrator:

hide 氏)hide 氏は 6 個の乾電池からの電圧を冷陰極間インバータ回路を用いて昇圧した交流電源回路を構成し、さらにそれをコッククロフトウォルトン回路により昇圧することで30kV~40kV 程度の高圧を発生させる装置である。（図 4-1）

図 4-1 高圧発生回路

キセノンランプ

図 4-2 hide 氏の外形
なお安全のため放電は空気中ではなくカメラのストロボに用いられるキセノンランプ内で放電させた。（図 4-2）

7

5. GUI
arduino と PC との通信において GUI による操作法を導入した。（図 5-1）これにより磁気ル博士の操作が簡易でかつ複雑なものを行えるようになった。

図 5-1 GUI 画面
6. 実験
6.1 ACS(Auto Calibration System)
ACS 実行結果を以下に示した。

図 6.1-1 キャリブレーション前8図 6.1-2 キャリブレーション後
6.2 サージノイズ
磁気ル博士を用いて hide 氏からのノイズを検出した。実験はジキル博士の測定モード
75Hz、 0.88G のレンジで 3 回にわたり測定し結果を以下に記した。なお hide 氏のスイッ
チは 1~5 番目のデータで OFF、6~10 番目のデータで ON となっている。
表 6.2-1 実験 1 回目結果

n番目 磁界[mG] 平均値[mG]
1

273

2

273

3

272

4

271

5

271

6

272

7

274

8

276

9

275

10

274

9

272

274

図 6.2-1 実験 1 回目結果
表 6.2-2 実験 2 回目結果

n番目 磁界[mG] 平均値[mG]
1

269

2

268

3

268

4

269

5

269

6

272

7

274

8

272

9

271

10

272

10

269

272

図 6.2-2 実験 2 回目結果
表 6.2-3 実験 3 回目結果

n番目 磁界[mG] 平均値[mG]
1

275

2

274

3

276

4

275

5

274

6

270

7

272

8

273

9

272

10

272

11

275

272

図 6.2-3 実験 3 回目結果
7. 考察
7.1 ACS
6.1 の図 6.1-1、6.1-2 からキャリブレーション前は原点から大きく離れた円になっているがキャリブレーション後には原点を中心とする円となっていて ACS が正確に動作していることが分かる。ただ、測定点が正確な円ではなく楕円となるのはセンサ内部による回路ノイズが原因だと考えられる。
7.2 サージノイズ
6.2 の結果から hide 氏のスイッチが ON の状態と OFF の状態での平均値が 2mG 以上の差分として表れている。これは hide 氏の電源回路で用いたコッククロフトウォルトン回路の昇圧性能が交流電源（冷陰極管インバータ）の周波数に依存するためサージが発生するまでに誤差が生じたと考えられる。
8. 課題
8.1 避雷回路の構成
今回の空中放電では電流がそれほど流れておらずサージノイズが小さいため定常磁界の変化と重なる部分があったために確実にサージノイズをカットする回路を構成できなかった。しかし、実際の誘導雷では大電流が流れるため、より大きなノイズになるであろうと予想した。
8.2 シリアル通信
arduino に PC からデータ停止コマンドを送信する際に受信側と送信側で干渉してしまい停止コマンドが反応しない場合があった。これについては今後タイミングを統一することで改善する。

12

9. ソースコード
今回用いた GUI 以外のソースコードを以下に記載した。
9.1 arduino#include <JEKYLL.h>#include <SPI.h>#include <Wire.h>
JEKYLL jekyll;
void setup(){jekyll.init();}void loop(){
jekyll.run();}
9.2 JEKYLL.h#include <Arduino.h>void measure(void);#include <L6470.h>

private:#include <HMC5883L.h>

L6470 stepper;
HMC5883L compass;class JEKYLL{

boolean measureFlag;
public:
JEKYLL();};

void init(void);void run(void);void calibration(void);private:void serialEvent(void);
13

9.3 HMC5883L.h{#include <Arduino.h>

HMC5883L_RANGE_0_88GA= 0b000,

typedef enum

HMC5883L_RANGE_1_3GA{= 0b001,
HMC5883L_ADDRESSHMC5883L_RANGE_1_9GA= 0x1E,= 0b010,
HMC5883L_REG_CONFIG_A

HMC5883L_RANGE_2_5GA= 0x00,= 0b011,
HMC5883L_REG_CONFIG_B

HMC5883L_RANGE_4GA= 0x01,= 0b100,
HMC5883L_REG_MODE

HMC5883L_RANGE_4_7GA= 0x02,= 0b101,
HMC5883L_REG_OUT_X_M

HMC5883L_RANGE_5_6GA= 0x03,= 0b110,
HMC5883L_REG_OUT_X_L

HMC5883L_RANGE_8_1GA= 0x04,= 0b111
HMC5883L_REG_OUT_Z_M} hmc5883l_range;

HMC5883L_REG_OUT_Z_L

typedef enum

= 0x05,= 0x06,{
HMC5883L_REG_OUT_Y_M

HMC5883L_CONTINOUS= 0x07,= 0b00,
HMC5883L_REG_OUT_Y_L= 0x08,

HMC5883L_SINGLE=

HMC5883L_IDLE

=

0b01,
HMC5883L_REG_STATUS= 0x09,0b10
HMC5883L_REG_IDENT_A} hmc5883l_mode;

HMC5883L_REG_IDENT_B

typedef enum

= 0x0A,= 0x0B,{
HMC5883L_REG_IDENT_C

HMC5883L_DATARATE_0_75_= 0x0C,

HZ} hmc5883l_address;= 0b000,
HMC5883L_DATARATE_1_5HZ= 0b001,
typedef enum

HMC5883L_DATARATE_3HZ14

= 0b010,
HMC5883L_DATARATE_7_5HZ

Vector readRaw(void);= 0b011,

Vector readNormalize(void);
HMC5883L_DATARATE_15HZ= 0b100,

void setOffSet(Vector
HMC5883L_DATARATE_30HZvec);= 0b101,

void setOffSet(float x,
HMC5883L_DATARATE_75HZ

float y, float z);= 0b110Vector getOffSet(void);} hmc5883l_dataRate;
void setRange(hmc5883l_range
typedef enum

range);{

void setRange(int
HMC5883L_SAMPLES_1

range);=

0b00,

hmc5883l_range getRange(void);
HMC5883L_SAMPLES_2

=

0b01,

void
HMC5883L_SAMPLES_4=

setMeasurementMode(hmc5883l_mode

0b10,mode);
HMC5883L_SAMPLES_8

=

void

0b11

setMeasurementMode(int mode);} hmc5883l_samples;

hmc5883l_mode
getMeasurementMode(void);

struct Vector{

void
float XAxis;

setDataRate(hmc5883l_dataRate rate);

float YAxis;

void setDataRate(intfloat ZAxis;rate);};

hmc5883l_dataRate
getDataRate(void);class HMC5883L{

void
public:setSamples(hmc5883l_samples samples);

HMC5883L();

void setSamples(intsamples);void init(void);

hmc5883l_samples
15

getSamples(void);void setSettings(Stringstr);
void printSettings(void);
StringgetSettings(void);void writeRegister8(byte reg,byte value);unsigned charreadRegister8(byte reg);
private:Vector data;
Vector offSet;
float mgPerDigit;};

169.4 L6470.h

L6470_PIN_STAT1#include <Arduino.h>= 14,

typedef enum

L6470_PIN_STAT2

{

= 15,

L6470_PIN_SS

L6470_PIN_SWITCH

= 10,

=

8

} l6470_pin;
L6470_PIN_MOSI= 11,

typedef enum{

L6470_PIN_MISO= 12,

L6470_STEP_MODE_SYNC_0_5_STEP_
1= 0x0000,

L6470_PIN_SCK= 13,

L6470_STEP_MODE_SYNC_0_5_STEP_
2= 0x0001,

L6470_PIN_RESET=

6,

L6470_STEP_MODE_SYNC_0_5_STEP_
4= 0x0002,

L6470_PIN_BUSYN=

4,

L6470_STEP_MODE_SYNC_0_5_STEP_
8= 0x0003,

L6470_STEP_MODE_SYNC_0_5_STEP_
16= 0x0004,

L6470_STEP_MODE_SYNC_0_5_STEP_
32= 0x0005,

L6470_STEP_MODE_SYNC_0_5_STEP_
64= 0x0006,

L6470_STEP_MODE_SYNC_0_5_STEP_
17

128

= 0x0007,= 0x0026,

L6470_STEP_MODE_SYNC_1_STEP_2

L6470_STEP_MODE_SYNC_2_STEP_12= 0x0011,

8

L6470_STEP_MODE_SYNC_1_STEP_4

L6470_STEP_MODE_SYNC_4_STEP_8= 0x0012,= 0x0033,

L6470_STEP_MODE_SYNC_1_STEP_8

L6470_STEP_MODE_SYNC_4_STEP_16= 0x0013,= 0x0034,

L6470_STEP_MODE_SYNC_1_STEP_16

L6470_STEP_MODE_SYNC_4_STEP_32= 0x0014,= 0x0035,

L6470_STEP_MODE_SYNC_1_STEP_32

L6470_STEP_MODE_SYNC_4_STEP_64= 0x0015,= 0x0036,

L6470_STEP_MODE_SYNC_1_STEP_64

L6470_STEP_MODE_SYNC_4_STEP_12= 0x0016,

8

L6470_STEP_MODE_SYNC_1_STEP_12

L6470_STEP_MODE_SYNC_8_STEP_16

8= 0x0044,= 0x0017,= 0x0027,= 0x0037,

L6470_STEP_MODE_SYNC_2_STEP_4

L6470_STEP_MODE_SYNC_8_STEP_32= 0x0022,= 0x0045,

L6470_STEP_MODE_SYNC_2_STEP_8

L6470_STEP_MODE_SYNC_8_STEP_64= 0x0023,= 0x0046,

L6470_STEP_MODE_SYNC_2_STEP_16

L6470_STEP_MODE_SYNC_8_STEP_12= 0x0024,

8

L6470_STEP_MODE_SYNC_2_STEP_32

L6470_STEP_MODE_SYNC_16_STEP_3= 0x0025,

2

L6470_STEP_MODE_SYNC_2_STEP_64

L6470_STEP_MODE_SYNC_16_STEP_6
18= 0x0047,= 0x0055,

4= 0x0056,

L6470_ALARM_EN_STALL_DET_A= 0x0010,

L6470_STEP_MODE_SYNC_16_STEP_1
28= 0x0057,

L6470_ALARM_EN_STALL_DET_B= 0x0020,

L6470_STEP_MODE_SYNC_32_STEP_6
4

L6470_ALARM_EN_SW_TURN_ON= 0x0066,= 0x0040,
L6470_STEP_MODE_SYNC_32_STEP_1
28

L6470_ALARM_EN_WRONG_NPERF_C= 0x0067,

MD= 0x0080,

L6470_STEP_MODE_SYNC_64_STEP_1
28

L6470_ALARM_EN_ALL= 0x0077,= 0x00FF} l6470_alarm_en;

L6470_STEP_MODE_SYNC_DISABLE= 0x0000,

typedef enum{

L6470_STEP_MODE_SYNC_ENABLE= 0x0080

L6470_CONFIG_OSC_INT_16MHZ} l6470_step_mode;= 0x0000,
typedef enum
L6470_CONFIG_OSC_INT_16MHZ_OU{

T_2MHZ= 0x0008,

L6470_ALARM_EN_OVERCURRENT
L6470_CONFIG_OSC_INT_16MHZ_OU= 0x0001,

T_4MHZ= 0x0009,

L6470_ALARM_EN_THERMAL_SHUTD
OWN

L6470_CONFIG_OSC_INT_16MHZ_OU= 0x0002,

T_8MHZ= 0x000A,

L6470_ALARM_EN_THERMAL_WARNI
NG

L6470_CONFIG_OSC_INT_16MHZ_OU= 0x0004,

T_16MHZ= 0x000B,

L6470_ALARM_EN_UNDER_VOLTAGE
L6470_CONFIG_OSC_EXT_8MHZ_OUT= 0x0008,

_XTAL
19

= 0x0004,

L6470_CONFIG_OSC_EXT_16MHZ_OU

L6470_CONFIG_OC_SD_ENABLE

T_XTAL= 0x0080,= 0x0005,

L6470_CONFIG_OSC_EXT_24MHZ_OU

L6470_CONFIG_POW_SR_320V_us

T_XTAL= 0x0000,= 0x0006,

L6470_CONFIG_OSC_EXT_32MHZ_OU

L6470_CONFIG_POW_SR_75V_us

T_XTAL= 0x0100,= 0x0007,

L6470_CONFIG_OSC_EXT_8M_OUT_I

L6470_CONFIG_POW_SR_110V_us

NVERT= 0x0200,= 0x000C,

L6470_CONFIG_OSC_EXT_16M_OUT_I

L6470_CONFIG_POW_SR_260V_us

NVERT= 0x0300,= 0x000D,

L6470_CONFIG_OSC_EXT_24M_OUT_I

L6470_CONFIG_F_PWM_DEC_0_625

NVERT= 0x0000,= 0x000E,

L6470_CONFIG_OSC_EXT_32M_OUT_I

L6470_CONFIG_F_PWM_DEC_0_75

NVERT= 0x0400,= 0x000F,

L6470_CONFIG_SW_MODE_DISABLE

L6470_CONFIG_F_PWM_DEC_0_875= 0x0000,= 0x0800,

L6470_CONFIG_SW_MODE_ENABLE

L6470_CONFIG_F_PWM_DEC_1= 0x0010,= 0x0C00,

L6470_CONFIG_EN_VSCOMP_DISABL

L6470_CONFIG_F_PWM_DEC_1_25

E= 0x1000,= 0x0000,

L6470_CONFIG_EN_VSCOMP_ENABL

L6470_CONFIG_F_PWM_DEC_1_5

E= 0x1400,= 0x0020,

L6470_CONFIG_OC_SD_DISABLE

L6470_CONFIG_F_PWM_DEC_1_75= 0x0000,= 0x1800,20

= 0x0004,
L6470_CONFIG_F_PWM_DEC_2= 0x1C00,

L6470_STATUS_SW_EVN= 0x0008,

L6470_CONFIG_F_PWM_INT_1= 0x0000,

L6470_STATUS_DIR= 0x0010,

L6470_CONFIG_F_PWM_INT_2= 0x2000,

L6470_STATUS_MOT_STATUS_STOPP
ED= 0x0000,

L6470_CONFIG_F_PWM_INT_3= 0x4000,

L6470_STATUS_MOT_STATUS_ACCELERATION= 0x0020,

L6470_CONFIG_F_PWM_INT_4= 0x6000,

L6470_STATUS_MOT_STATUS_DECELERATION= 0x0040,

L6470_CONFIG_F_PWM_INT_5= 0x8000,

L6470_STATUS_MOT_STATUS_CONST_SPD= 0x0060,

L6470_CONFIG_F_PWM_INT_6= 0xA000,

L6470_STATUS_NOTPERF_CMD= 0x0080,

L6470_CONFIG_F_PWM_INT_7= 0xC000

L6470_STATUS_WRONG_CMD} l6470_config;= 0x0100,typedef enum

L6470_STATUS_UVLO{= 0x0200,

L6470_STATUS_HIZ

L6470_STATUS_TH_WRN= 0x0001,= 0x0400,

L6470_STATUS_BUSY

L6470_STATUS_TH_SD= 0x0002,= 0x0800,

L6470_STATUS_SW_F

L6470_STATUS_OCD
21

= 0x1000,

L6470_PARAM_MIN_SPEED= 0x0008,

L6470_STATUS_STEP_LOSS_A= 0x2000,

L6470_PARAM_FS_SPD= 0x0015,

L6470_STATUS_STEP_LOSS_B= 0x4000,

L6470_PARAM_KVAL_HOLD= 0x0009,

L6470_STATUS_SCK_MOD= 0x8000

L6470_PARAM_KVAL_RUN} l6470_status;= 0x000A,

typedef enum

L6470_PARAM_KVAL_ACC{= 0x000B,

L6470_PARAM_ABS_POS

L6470_PARAM_KVAL_DEC= 0x0001,= 0x000C,

L6470_PARAM_EL_POS

L6470_PARAM_INT_SPEED= 0x0002,= 0x000D,

L6470_PARAM_MARK

L6470_PARAM_ST_SLP= 0x0003,= 0x000E,

L6470_PARAM_SPEED

L6470_PARAM_FN_SLP_ACC= 0x0004,= 0x000F,

L6470_PARAM_ACC

L6470_PARAM_FN_SLP_DEC= 0x0005,= 0x0010,

L6470_PARAM_DEC

L6470_PARAM_K_THERM= 0x0006,= 0x0011,

L6470_PARAM_MAX_SPEED

L6470_PARAM_ADC_OUT= 0x0007,= 0x0012,

22

L6470_PARAM_OCD_TH= 0x0013,

L6470_COMMAND_MOVE= 0x0040,

L6470_PARAM_STALL_TH= 0x0014,

L6470_COMMAND_GOTO= 0x0060,

L6470_PARAM_STEP_MODE= 0x0016,

L6470_COMMAND_GOTO_DIR= 0x0068,

L6470_PARAM_ALARM_EN= 0x0017,

L6470_COMMAND_GO_UNTIL= 0x0082,

L6470_PARAM_CONFIG
L6470_COMMAND_RELEASE_SW= 0x0018,= 0x0092,
L6470_PARAM_STATUS= 0x0019

L6470_COMMAND_GO_HOME} l6470_param;= 0x0070,

typedef enum

L6470_COMMAND_GO_MARK{= 0x0078,

L6470_COMMAND_NOP

L6470_COMMAND_RESET_POS= 0x0000,= 0x00D8,

L6470_COMMAND_SET_PARAM

L6470_COMMAND_RESET_DEVICE= 0x0000,= 0x00C0,

L6470_COMMAND_GET_PARAM

L6470_COMMAND_SOFT_STOP= 0x0020,= 0x00B0,

L6470_COMMAND_RUN

L6470_COMMAND_HARD_STOP= 0x0050,= 0x00B8,

L6470_COMMAND_STEP_CLOCK

L6470_COMMAND_SOFT_HIZ= 0x0058,= 0x00A0,23

L6470_COMMAND_HARD_HIZ

void init(void);= 0x00A8,
L6470_COMMAND_GET_STATUS= 0x00D0

boolean isBusy(void);} l6470_command;
typedef enum

void delayBusy(void);{
L6470_DIRECTION_FWD

void delayBusy(long);= 0x0001,
L6470_DIRECTION_REV= 0x0000

void commandNOP(void);} l6470_deirection;
typedef enumvoid

commandSetParam(l6470_param{

param, long value);

L6470_ACTION_RESET= 0x0000,

longcommandGetParam(l6470_param

param);
L6470_ACTION_COPY= 0x0008} l6470_action;

void commandRun(l6470_deirection dir,long spd);

class L6470 {public:void
commandStep_Clock(l6470_deirection
dir);L6470();
void commandMove(l6470_deirection dir,24

long n_step);
void commandSoftHiZ(void);void commandGoTo(long pos);void commandHardHiZ(void);void
commandGoTo_DIR(l6470_deirection dir,long commandGetStatus(void);long pos);void commandGoUntil(l6470_action act,

longl6470_deirection dir, long spd);

stepsPerSec);

void

long

commandReleaseSW(l6470_action

calcRegValSPEED(float

calcRegValACC(float

act, l6470_deirection dir);stepsPerSecPerSec);

void commandGoHome(void);longcalcRegValDEC(float

stepsPerSecPerSec);
void commandGoMark(void);longcalcRegValMAX_SPEED(float

stepsPerSec);
void commandResetPos(void);longcalcRegValMIN_SPEED(float

void commandResetDevice(void);

stepsPerSec);

void commandSoftStop(void);longcalcRegValFS_SPD(float

stepsPerSec);
void commandHardStop(void);long
25

calcRegValINT_SPEED(float

stepsPerSec);

long//private:calcRegValOCD_TH(float

void setABS_POS(long abs_pos);milliAmpere);void setEL_POS(long el_pos);
longcalcRegValSTALL_TH(float

milliAmpere);void setMARK(long mark);

float calcUnitSPEED(long speed);void setACC(long acc);

float calcUnitACC(long acc);

void setDEC(long dec);

float calcUnitDEC(long dec);

void setMAX_SPEED(long max_speed);float

void setMIN_SPEED(long min_speed);

calcUnitMAX_SPEED(longmax_speed);void setFS_SPD(long fs_spd);
float

calcUnitMIN_SPEED(longmin_speed);void setKVAL_HOLD(long kval_hold);
float calcUnitFS_SPD(long fs_spd);
void setKVAL_RUN(long kval_run);float

calcUnitINT_SPEED(longint_speed);void setKVAL_ACC(long kval_acc);26

void setKVAL_DEC(long kval_dec);long getEL_POS(void);void setINT_SPEED(long int_speed);long getMARK(void);void setST_SLP(long st_slp);
long getSPEED(void);void setFN_SLP_ACC(long slp_acc);
long getACC(void);void setFN_SLP_DEC(long slp_dec);long getDEC(void);void setK_THERM(long k_therm);
long getMAX_SPEED(void);void setOCD_TH(long ocd_th);long getMIN_SPEED(void);void setSTALL_TH(long stall_th);long getFS_SPD(void);void setSTEP_MODE(long step_mode);long getKVAL_HOLD(void);void setALARM_EN(long alarm_en);long getKVAL_RUN(void);void setCONFIG(long config);
long getKVAL_ACC(void);long getABS_POS(void);long getKVAL_DEC(void);27

long getINT_SPEED(void);private:long getST_SLP(void);longcheckOverflow(long

data,

long

checkOverflow(long

data,

long

range);
long getFN_SLP_ACC(void);long

max_range, long min_range);long getFN_SLP_DEC(void);long getK_THERM(void);byte Xfer(byte data);};long getADC_OUT(void);long getOCD_TH(void);long getSTALL_TH(void);long getSTEP_MODE(void);long getALARM_EN(void);long getCONFIG(void);long getSTATUS(void);28

9.5 JEKYLL.cpp

Vector vec;#include "JEKYLL.h"float max_X, min_X, max_Y,#include "SPI.h"

min_Y;#include "Wire.h"

int data_num = 50;
stepper.commandMove(L6470_D

JEKYLL::JEKYLL() {}IRECTION_REV, 100);
stepper.delayBusy(1000);

void JEKYLL::init(void){

delay(500);
Serial.begin(9600);

vec = compass.readRaw();

measureFlag = false;

max_X = min_X = vec.XAxis;

compass.init();max_Y = min_Y = vec.YAxis;

stepper.init();for (int i = 0; i < data_num; i++){compass.writeRegister8(0x02,0x00);

stepper.commandMove(L6470_D
IRECTION_FWD, (200 / data_num));
pinMode(LED_pin_1, OUTPUT);

stepper.delayBusy();}
delay(500);
void JEKYLL::run(void)

vec =

{

compass.readRaw();
if (Serial.available() > 0){

if (max_X < vec.XAxis)
serialEvent();{}

max_X =

if (measureFlag)

vec.XAxis;{}
measure();if (min_X > vec.XAxis)

}

{

}

min_X =
vec.XAxis;

void JEKYLL::calibration(void)}{if (max_Y < vec.YAxis)
29

measureFlag = false;{
max_Y =

Serial.print("###received

vec.YAxis;
stop@");}
if (min_Y > vec.YAxis)}{

else if
min_Y =

(code.indexOf("measure") != -1)

vec.YAxis;{}

measureFlag = true;}
stepper.commandMove(L6470_D

Serial.print("###received

IRECTION_REV, 100);

measure@");stepper.delayBusy(1000);}
else ifcompass.setOffSet((max_X +(code.indexOf("calibration") != -1)

min_X) / 2, (max_Y + min_Y) / 2, 0);{
measureFlag = false;}

calibration();void JEKYLL::serialEvent(void)

Serial.print("###received{

calibration@");String code =}Serial.readStringUntil('@');else

if (code.indexOf("set") != -1)

Serial.print("###MESSAGE{

ERROR!@");
measureFlag = false;}

compass.setSettings(code);

void JEKYLL::measure(void){

Serial.print("###received set " +Vector vec;compass.getSettings() + "@");

int VEC;}else if (code.indexOf("stop") != -vec = compass.readNormalize();

1)

VEC = int(sqrt(pow(vec.XAxis,{

2.0) + pow(vec.YAxis, 2.0)));30

Serial.print("Vec =" +String(VEC_before));Serial.print("Vec =" +String(VEC_after));
Serial.print("@");}

31

9.6 HMC5883L.cpp

data.YAxis -= offSet.YAxis;#include "HMC5883L.h"

data.ZAxis =#include "Wire.h"((readRegister8(HMC5883L_REG_OUT_
Z_M) << 8) & 0xFF00) |HMC5883L::HMC5883L() {}readRegister8(HMC5883L_REG_OUT_Z_L);

void HMC5883L::init()

data.ZAxis -= offSet.ZAxis;{
Wire.begin();return data;}

setRange(HMC5883L_RANGE_1_3GA);

Vector HMC5883L::readNormalize(void){

setMeasurementMode(HMC5883L_CON

readRaw();
data.XAxis *= mgPerDigit;

TINOUS);

data.YAxis *= mgPerDigit;
data.ZAxis *= mgPerDigit;

setDataRate(HMC5883L_DATARATE_1
5HZ);

return data;
setSamples(HMC5883L_SAMPLES_1);}

setOffSet(0.0, 0.0, 0.0);}

void HMC5883L::setOffSet(Vector vec){

Vector HMC5883L::readRaw(void)

offSet = vec;{}
data.XAxis =((readRegister8(HMC5883L_REG_OUT_

void HMC5883L::setOffSet(float x, floatX_M) << 8) & 0xFF00) |y, float z)

readRegister8(HMC5883L_REG_OUT_X

{

_L);

offSet.XAxis = x;data.XAxis -= offSet.XAxis;

offSet.YAxis = y;data.YAxis =offSet.ZAxis = z;((readRegister8(HMC5883L_REG_OUT_}

Y_M) << 8) & 0xFF00) |readRegister8(HMC5883L_REG_OUT_Y

Vector HMC5883L::getOffSet(void)

_L);

{
32

return offSet;

break;

}
case
void

HMC5883L_RANGE_5_6GA:

HMC5883L::setRange(hmc5883l_range

mgPerDigit = 3.03f;

range)

break;{
switch(range)

case

{

HMC5883L_RANGE_8_1GA:
case

mgPerDigit = 4.35f;

HMC5883L_RANGE_0_88GA:

break;

mgPerDigit = 0.73f;
break;

default:
break;

case}

HMC5883L_RANGE_1_3GA:
mgPerDigit = 0.92f;
break;

writeRegister8(HMC5883L_REG_CONFI
G_B, range << 5);

case

}

HMC5883L_RANGE_1_9GA:
mgPerDigit = 1.22f;

void HMC5883L::setRange(int range)

break;{
setRange((hmc5883l_range)range);

case

}

HMC5883L_RANGE_2_5GA:
mgPerDigit = 1.52f;

hmc5883l_range

break;

HMC5883L::getRange(void){case HMC5883L_RANGE_4GA:

returnmgPerDigit = 2.27f;(hmc5883l_range)((readRegister8(HMC5

break;

883L_REG_CONFIG_B) >> 5));}case
HMC5883L_RANGE_4_7GA:

void

mgPerDigit = 2.56f;

HMC5883L::setMeasurementMode(hmc533883l_mode mode){

void
byte value;

HMC5883L::setDataRate(hmc5883l_data
Rate rate)

value ={

readRegister8(HMC5883L_REG_MODE)

byte value;;
value &= 0b11111100;

value =

value |= mode;

readRegister8(HMC5883L_REG_CONFI
G_A);value &= 0b11100011;

writeRegister8(HMC5883L_REG_MODE

value |= (rate << 2);, value);}writeRegister8(HMC5883L_REG_CONFI
void

G_A, value);

HMC5883L::setMeasurementMode(int

}

mode)
{

void HMC5883L::setDataRate(int rate){

setMeasurementMode((hmc5883l_mode)mode);

setDataRate((hmc5883l_dataRate)rate);}}

hmc5883l_mode

hmc5883l_dataRate

HMC5883L::getMeasurementMode(void)

HMC5883L::getDataRate(void){{
byte value;

byte value;

value =

value =

readRegister8(HMC5883L_REG_MODE)

readRegister8(HMC5883L_REG_CONFI

;

G_A);
value &= 0b00000011;

value &= 0b00011100;
value >>= 2;

return (hmc5883l_mode)value;}

return (hmc5883l_dataRate)value;
34

}value >>= 5;

voidreturn (hmc5883l_samples)value;

HMC5883L::setSamples(hmc5883l_samp}

les samples){void HMC5883L::setSettings(String str)
byte value;{
String sNum;value =
readRegister8(HMC5883L_REG_CONFI

str =

G_A);

str.substring(str.indexOf("set") + 3);

value &= 0b10011111;

sNum = str.substring(0,value |= (samples << 5);

str.indexOf(","));
setRange(sNum.toInt());

writeRegister8(HMC5883L_REG_CONFI

str =G_A, value);str.substring(str.indexOf(",") + 1);}

sNum = str.substring(0,str.indexOf(","));

void HMC5883L::setSamples(intsamples)setMeasurementMode(sNum.toI{

nt());

setSamples((hmc5883l_samples)samples)

str =

;

str.substring(str.indexOf(",") + 1);}

sNum = str.substring(0,str.indexOf(","));

hmc5883l_samples

setDataRate(sNum.toInt());

HMC5883L::getSamples(void){str =byte value;

str.substring(str.indexOf(",") + 1);
setSamples(str.toInt());

value =
readRegister8(HMC5883L_REG_CONFI
G_A);

}

value &= 0b01100000;
35

void HMC5883L::printSettings(void)case HMC5883L_IDLE:{

Serial.println("Idle mode");Serial.print("Selected range: ");break;

switch (getRange())

case HMC5883L_SINGLE:{

Serial.println("Single-Measurement");
case

break;

HMC5883L_RANGE_0_88GA:

case HMC5883L_CONTINOUS:

Serial.println("0.88 Ga"); break;Serial.println("Continuous-

case

Measurement"); break;

HMC5883L_RANGE_1_3GA:
Serial.println("1.3 Ga");default:

break;

Serial.println("Bad mode!");

case

}

HMC5883L_RANGE_1_9GA:
Serial.println("1.9 Ga");

Serial.print("Selected Data Rate: ");break;

caseswitch (getDataRate())

HMC5883L_RANGE_2_5GA:
Serial.println("2.5 Ga");{

break;

case

case HMC5883L_RANGE_4GA:
Serial.println("4 Ga");

HMC5883L_DATARATE_0_75_HZ:

break;

Serial.println("0.75 Hz"); break;

case

case

HMC5883L_RANGE_4_7GA:

HMC5883L_DATARATE_1_5HZ:

Serial.println("4.7 Ga");

Serial.println("1.5 Hz");

break;

case

break;

case

HMC5883L_RANGE_5_6GA:

HMC5883L_DATARATE_3HZ:

Serial.println("5.6 Ga");

Serial.println("3 Hz");

break;

case

break;

case

HMC5883L_RANGE_8_1GA:

HMC5883L_DATARATE_7_5HZ:

Serial.println("8.1 Ga");

Serial.println("7.5 Hz");

break;

default:

break;

case

Serial.println("Bad range!");

HMC5883L_DATARATE_15HZ:}

Serial.println("15 Hz");

break;

case
Serial.print("Selected Measurement

HMC5883L_DATARATE_30HZ:

Mode: ");

Serial.println("30 Hz");switch (getMeasurementMode())

break;

case{

HMC5883L_DATARATE_75HZ:
36

Serial.println("75 Hz");

break;

break;

default:

case

Serial.println("Bad data rate!");

HMC5883L_RANGE_2_5GA:}

str += "3";break;
case HMC5883L_RANGE_4GA:

Serial.print("Selected number of

str += "4"; break;samples: ");caseswitch (getSamples())

HMC5883L_RANGE_4_7GA:{

break;
case HMC5883L_SAMPLES_1:

str += "5";case

Serial.println("1"); break;

HMC5883L_RANGE_5_6GA:

case HMC5883L_SAMPLES_2:

str += "6";break;

Serial.println("2"); break;case

case HMC5883L_SAMPLES_4:

HMC5883L_RANGE_8_1GA:

Serial.println("4"); break;

str += "7";break;

case HMC5883L_SAMPLES_8:

default:

Serial.println("8"); break;str+= "-1";

default:}

Serial.println("Bad number of samples!");}str += ",";}

switch (getMeasurementMode()){

String HMC5883L::getSettings(void)case HMC5883L_CONTINOUS:{

str += "0"; break;String str = "";case HMC5883L_SINGLE:
str += "1"; break;switch (getRange())

case HMC5883L_IDLE:
str += "2"; break;{casedefault:

HMC5883L_RANGE_0_88GA: str += "0";"-1";

break;}
case

HMC5883L_RANGE_1_3GA:

str += "1";

str += ",";

break;

switch (getDataRate())
case

HMC5883L_RANGE_1_9GA:{
str += "2";

case
37

str +=

HMC5883L_DATARATE_0_75_HZ: str"-1";+= "0"; break;}case
HMC5883L_DATARATE_1_5HZ:

str

str += ",";+= "1"; break;

str += String(getOffSet().XAxis);case
HMC5883L_DATARATE_3HZ:

str += ",";
str

str += String(getOffSet().YAxis);+= "2"; break;

str += ",";

case
HMC5883L_DATARATE_7_5HZ:

str += String(getOffSet().ZAxis);
str+= "3"; break;return str;case
HMC5883L_DATARATE_15HZ:}
str+= "4"; break;void HMC5883L::writeRegister8(bytecase
HMC5883L_DATARATE_30HZ:

reg, byte value)str{+= "5"; break;case
HMC5883L_DATARATE_75HZ:

Wire.beginTransmission(HMC5883L_AD
str

DRESS);+= "6"; break;Wire.write(reg);

default:

Wire.write(value);str += "-1";Wire.endTransmission(true);}}str += ",";

byte HMC5883L::readRegister8(byte reg)switch (getSamples()){{

byte value;case HMC5883L_SAMPLES_1:
str += "0"; break;case HMC5883L_SAMPLES_2:

Wire.beginTransmission(HMC5883L_AD

str += "1"; break;

DRESS);

case HMC5883L_SAMPLES_4:

Wire.write(reg);

str += "2"; break;Wire.endTransmission(false);

case HMC5883L_SAMPLES_8:
str += "3"; break;default:

Wire.requestFrom(HMC5883L_ADDRESS, 1);

str +=
38

value = Wire.read();return value;}399.7 L6470.cpp

commandNOP();#include "L6470.h"#include "SPI.h"commandResetDevice();

L6470::L6470() {}setMAX_SPEED(calcRegValMAX_SPEE
void L6470::init(void)D(200));{
setMIN_SPEED(0x1000);
pinMode(L6470_PIN_SS, OUTPUT);
setKVAL_HOLD(0x20);
digitalWrite(L6470_PIN_SS, HIGH);
setKVAL_RUN(0x40);
pinMode(L6470_PIN_MOSI, OUTPUT);
setKVAL_ACC(0x40);
pinMode(L6470_PIN_MISO, INPUT);
setKVAL_DEC(0x40);
pinMode(L6470_PIN_SCK, OUTPUT);
setSTEP_MODE(0x00);
SPI.begin();commandHardStop();
SPI.setBitOrder(MSBFIRST);}SPI.setClockDivider(SPI_CLOCK_DIV16

boolean L6470::isBusy(void));{

SPI.setDataMode(SPI_MODE3);

return !bitRead(commandGetStatus(), 1);}

commandNOP();

void L6470::delayBusy(void){

commandNOP();
while (isBusy()) {}commandNOP();}40

void L6470::delayBusy(long milliSec)

case

L6470_PARAM_MARK:{

setMARK(value);

break;

while (isBusy()) {}case L6470_PARAM_SPEED:
delay(milliSec);/*

read only */break;

case

L6470_PARAM_ACC:}

setACC(value);

void L6470::commandNOP(void)

case

{

setDEC(value);

break;

L6470_PARAM_DEC:
break;

Xfer((byte)L6470_COMMAND_NOP);}

case

L6470_PARAM_MAX_SPEED:

setMAX_SPEED(value);

break;

void
L6470::commandSetParam(l6470_param
param, long value)case

L6470_PARAM_MIN_SPEED:{

setMIN_SPEED(value);

break;

switch (param)
case
{

case

setFS_SPD(value);

L6470_PARAM_ABS_POS:

setABS_POS(value);case

L6470_PARAM_FS_SPD:case

break;

setEL_POS(value);

L6470_PARAM_KVAL_HOLD:

setKVAL_HOLD(value);

L6470_PARAM_EL_POS:

case

break;

break;

L6470_PARAM_KVAL_RUN:

setKVAL_RUN(value);41

break;

break;

case

L6470_PARAM_KVAL_ACC:

setKVAL_ACC(value);case

break;

case

case

break;

case

L6470_PARAM_STEP_MODE:

case

break;

break;

L6470_PARAM_ALARM_EN:

setALARM_EN(value);

L6470_PARAM_ST_SLP:

setST_SLP(value);

break;

setSTEP_MODE(value);

L6470_PARAM_INT_SPEED:

setINT_SPEED(value);

L6470_PARAM_STALL_TH:

setSTALL_TH(value);

L6470_PARAM_KVAL_DEC:

setKVAL_DEC(value);

case

case

case

break;

L6470_PARAM_CONFIG:

setCONFIG(value);

L6470_PARAM_FN_SLP_ACC:

break;

break;

case L6470_PARAM_STATUS:

setFN_SLP_ACC(value); break;read only */casedefault:

L6470_PARAM_FN_SLP_DEC:

setFN_SLP_DEC(value); break;/*break;

break;}

case

L6470_PARAM_K_THERM:

setK_THERM(value);}

break;
long
L6470::commandGetParam(l6470_paramcase L6470_PARAM_ADC_OUT:
read only *//*param)

break;{
long value = 0;

case

L6470_PARAM_OCD_TH:

setOCD_TH(value);

break;
switch (param)42{= getFS_SPD();case L6470_PARAM_ABS_POS:= getABS_POS();

value

case

value

case

case

break;

L6470_PARAM_INT_SPEED:= getST_SLP();

L6470_PARAM_MAX_SPEED:

case

break;

break;

value

break;

L6470_PARAM_FN_SLP_ACC:

value = getFN_SLP_ACC(); break;L6470_PARAM_MIN_SPEED:

case

break;

case L6470_PARAM_FS_SPD:

break;

case L6470_PARAM_ST_SLP:

break;

value = getMIN_SPEED();

break;

L6470_PARAM_KVAL_DEC:

value = getINT_SPEED();value

break;

L6470_PARAM_KVAL_ACC:

value = getKVAL_DEC();

value

break;

L6470_PARAM_KVAL_RUN:

value = getKVAL_ACC();

break;

value = getMAX_SPEED();

case

case

break;

case L6470_PARAM_DEC:= getDEC();

casevalue = getKVAL_RUN();case L6470_PARAM_ACC:= getACC();

value

break;

case L6470_PARAM_SPEED:= getSPEED();

L6470_PARAM_KVAL_HOLD:

value = getKVAL_HOLD();case L6470_PARAM_MARK:= getMARK();case

break;

case L6470_PARAM_EL_POS:= getEL_POS();value

break;

L6470_PARAM_FN_SLP_DEC:

value = getFN_SLP_DEC(); break;

value

case
43

L6470_PARAM_K_THERM:

value = getK_THERM();

break;
return value;}case

L6470_PARAM_ADC_OUT:

value = getADC_OUT();

break;

void
L6470::commandRun(l6470_deirection
dir, long spd)

case

L6470_PARAM_OCD_TH:

value = getOCD_TH();{

break;
spd = checkOverflow(spd, 0x0FFFFF);

case

L6470_PARAM_STALL_TH:

value = getSTALL_TH();

Xfer((byte)L6470_COMMAND_RUN

break;|

dir);
Xfer((byte)(spd >> 16));case

L6470_PARAM_STEP_MODE:

value = getSTEP_MODE();

break;

Xfer((byte)(spd >> 8));Xfer((byte)(spd));

case

L6470_PARAM_ALARM_EN:

value = getALARM_EN();}

break;
void
L6470::commandStep_Clock(l6470_deirec

case L6470_PARAM_CONFIG:= getCONFIG();value

tion dir)break;{
Xfer((byte)L6470_COMMAND_STEP_CL

case L6470_PARAM_STATUS:= getSTATUS();value

OCK | dir);break;}
void

default:

value = -1;

L6470::commandMove(l6470_deirection

break;

dir, long n_step){}n_step44=

checkOverflow(n_step,0x3FFFFF);

Xfer((byte)(pos >> 16));

Xfer((byte)L6470_COMMAND_MOVE |Xfer((byte)(pos >> 8));dir);
Xfer((byte)(pos));
Xfer((byte)(n_step >> 16));}

Xfer((byte)(n_step >> 8));void
L6470::commandGoUntil(l6470_action

Xfer((byte)(n_step));

act, l6470_deirection dir, long spd)}{

void L6470::commandGoTo(long pos)

spd = checkOverflow(spd, 0x0200);{
Xfer((byte)L6470_COMMAND_GO_UNT
pos = checkOverflow(pos, 0x3FFFFF);

IL | act | dir);

Xfer((byte)L6470_COMMAND_GOTO);

Xfer((byte)(spd >> 16));

Xfer((byte)(pos >> 16));

Xfer((byte)(spd >> 8));Xfer((byte)(pos >> 8));Xfer((byte)(spd));}

Xfer((byte)(pos));}

void
L6470::commandReleaseSW(l6470_actio

void

n act, l6470_deirection dir)

L6470::commandGoTo_DIR(l6470_deirect{

ion dir, long pos){

Xfer((byte)L6470_COMMAND_RELEAS
E_SW | act | dir);pos = checkOverflow(pos, 0x3FFFFF);}

Xfer((byte)L6470_COMMAND_GOTO_D

void L6470::commandGoHome(void)

IR | dir);{45

Xfer((byte)L6470_COMMAND_GO_HOM

TOP);

E);

}

}
void L6470::commandSoftHiZ(void)
void L6470::commandGoMark(void){{
Xfer((byte)L6470_COMMAND_SOFT_HI
Xfer((byte)L6470_COMMAND_GO_MAR

Z);

K);

}

}
void L6470::commandHardHiZ(void)
void L6470::commandResetPos(void){{
Xfer((byte)L6470_COMMAND_HARD_H
Xfer((byte)L6470_COMMAND_RESET_P

IZ);

OS);

}

}
long L6470::commandGetStatus(void)
void L6470::commandResetDevice(void){{
long status = 0;
Xfer((byte)L6470_COMMAND_RESET_
DEVICE);}

Xfer((byte)L6470_COMMAND_GET_STA
TUS);

void L6470::commandSoftStop(void){

status |= Xfer(0) << 8;

Xfer((byte)L6470_COMMAND_SOFT_ST

status |= Xfer(0);OP);}
return status;
void L6470::commandHardStop(void)}{
Xfer((byte)L6470_COMMAND_HARD_S
46

}
long

L6470::calcRegValSPEED(float

stepsPerSec)

long

{

L6470::calcRegValMIN_SPEED(float
stepsPerSec)

long speed = stepsPerSec * 67.108864;{

return speed;

long min_speed = stepsPerSec * 4.194304;}
return min_speed;longL6470::calcRegValACC(float}

stepsPerSecPerSec){

long

L6470::calcRegValFS_SPD(float

stepsPerSec)
long acc = stepsPerSecPerSec * 0.068719;{

return acc;

long fs_spd = (stepsPerSec * 0.065536) -

}

0.5;

long

L6470::calcRegValDEC(float

return fs_spd;

stepsPerSecPerSec)}{
long L6470::calcRegValINT_SPEED(float
long dec = stepsPerSecPerSec * 0.068719;

stepsPerSec){

return dec;}long int_speed = stepsPerSec * 4.194304;

longreturn int_speed;

L6470::calcRegValMAX_SPEED(float}

stepsPerSec){

long

L6470::calcRegValOCD_TH(float

milliAmpere)long max_speed = stepsPerSec * 0.065536;{

return max_speed;

long ocd_th = ocd_th = ceil(milliAmpere /47375);
float stepsPerSecPerSec = dec * 14.552;
return ocd_th;}

return stepsPerSecPerSec;}

long

L6470::calcRegValSTALL_TH(float

milliAmpere)

float

L6470::calcUnitMAX_SPEED(long{max_speed){

long stall_th = ceil(milliAmpere / 31.25);
float stepsPerSec = max_speed * 15.259;
return stall_th;}

return stepsPerSec;}
float

L6470::calcUnitMIN_SPEED(longmin_speed){
float L6470::calcUnitSPEED(long speed)
{

float

stepsPerSec=(min_speed&

0x0FFF) * 0.238;
float stepsPerSec = speed * 0.015;
return stepsPerSec;
return stepsPerSec;

}

}
float

L6470::calcUnitFS_SPD(longfloat L6470::calcUnitACC(long acc)

fs_spd){{float stepsPerSecPerSec = acc * 14.552;

float stepsPerSec = (fs_spd + 0.5) * 15.259;

return stepsPerSecPerSec;

return stepsPerSec;}}

float L6470::calcUnitDEC(long dec)

float

{

int_speed)
48

L6470::calcUnitINT_SPEED(long{}

float stepsPerSec = int_speed * 0.238;

void L6470::setMARK(long mark){return stepsPerSec;}

mark = checkOverflow(mark, 0x3FFFFF,-0x3FFFFF);
Xfer((byte)L6470_PARAM_MARK);
Xfer((byte)(mark >> 16));

void L6470::setABS_POS(long abs_pos){
abs_pos

Xfer((byte)(mark >> 8));=checkOverflow(abs_pos,

Xfer((byte)(mark));

0x3FFFFF, -0x3FFFFF);}

Xfer((byte)L6470_PARAM_ABS_POS);

void L6470::setACC(long acc){

Xfer((byte)(abs_pos >> 16));
acc = checkOverflow(acc, 0x0FFF);
Xfer((byte)(abs_pos >> 8));Xfer((byte)L6470_PARAM_ABS_POS);
Xfer((byte)(abs_pos));}

Xfer((byte)(acc >> 8));void L6470::setEL_POS(long el_pos)

Xfer((byte)(acc));{}

el_pos = checkOverflow(el_pos, 0x01FF);

void L6470::setDEC(long dec){

Xfer((byte)L6470_PARAM_EL_POS);
dec = checkOverflow(dec, 0x0FFF);
Xfer((byte)(el_pos >> 8));Xfer((byte)L6470_PARAM_DEC);
Xfer((byte)(el_pos));49

Xfer((byte)(dec >> 8)););Xfer((byte)(dec));

Xfer((byte)(min_speed >> 8));}Xfer((byte)(min_speed));void

L6470::setMAX_SPEED(long}max_speed){

void L6470::setFS_SPD(long fs_spd){

max_speed = checkOverflow(max_speed,
0x03FF);fs_spd = checkOverflow(fs_spd, 0x03FF);

Xfer(L6470_PARAM_MAX_SPEED);

Xfer((byte)L6470_PARAM_FS_SPD);Xfer((byte)(max_speed >> 8));Xfer((byte)(fs_spd >> 8));Xfer((byte)(max_speed));Xfer((byte)(fs_spd));

}

}

void

L6470::setMIN_SPEED(longvoidmin_speed)kval_hold){{if (min_speed <= 0x0010)

kval_hold

L6470::setKVAL_HOLD(long=checkOverflow(kval_hold,0xFF);{
Xfer((byte)L6470_PARAM_KVAL_HOLD);
min_speed |= 0x1000;
Xfer((byte)kval_hold);}}

min_speed = checkOverflow(min_speed,

void

0x0FFF);

kval_run){

Xfer((byte)L6470_PARAM_MAX_SPEED
50

L6470::setKVAL_RUN(longkval_run=

checkOverflow(kval_run,

0x3FFF);

0xFF);
Xfer((byte)L6470_PARAM_INT_SPEED);
Xfer((byte)L6470_PARAM_KVAL_RUN);
Xfer((byte)(int_speed >> 8));Xfer((byte)kval_run);}

Xfer((byte)(int_speed));}void L6470::setKVAL_ACC(long kval_acc){

void L6470::setST_SLP(long st_slp){

kval_acc=

checkOverflow(kval_acc,0xFF);

st_slp = checkOverflow(st_slp, 0xFF);

Xfer((byte)L6470_PARAM_KVAL_ACC);

Xfer((byte)L6470_PARAM_ST_SLP);

Xfer((byte)kval_acc);

Xfer((byte)st_slp);

}

}

void

L6470::setKVAL_DEC(longvoidkval_dec)

fn_slp_acc){{kval_dec=

checkOverflow(kval_dec,

L6470::setFN_SLP_ACC(longfn_slp_acc = checkOverflow(fn_slp_acc,0xFF);

0xFF);

Xfer((byte)L6470_PARAM_KVAL_DEC);

Xfer((byte)L6470_PARAM_FN_SLP_ACC);

Xfer((byte)kval_dec);}

Xfer((byte)fn_slp_acc);}

void

L6470::setINT_SPEED(longint_speed)

void

{

fn_slp_dec){

int_speed=

checkOverflow(int_speed,
51

L6470::setFN_SLP_DEC(longfn_slp_dec = checkOverflow(fn_slp_dec,0xFF);

Xfer((byte)(stall_th));}Xfer((byte)L6470_PARAM_FN_SLP_DEC
);

void

L6470::setSTEP_MODE(longstep_mode)
Xfer((byte)fn_slp_dec);{}
step_mode = checkOverflow(step_mode,
void L6470::setK_THERM(long k_therm)

0xF7);{
Xfer((byte)L6470_PARAM_STEP_MODE
k_therm=

checkOverflow(k_therm,);

0x0F);
Xfer((byte)(step_mode));Xfer((byte)L6470_PARAM_K_THERM);}

Xfer((byte)(k_therm));void L6470::setALARM_EN(long alarm)}{

void L6470::setOCD_TH(long ocd_th)

alarm = checkOverflow(alarm, 0xFF);{
Xfer((byte)L6470_PARAM_ALARM_EN);
ocd_th = checkOverflow(ocd_th, 0x0F);
Xfer((byte)(alarm));
Xfer((byte)L6470_PARAM_OCD_TH);}

Xfer((byte)(ocd_th));void L6470::setCONFIG(long config)}{

void L6470::setSTALL_TH(long stall_th)

config = checkOverflow(config, 0xFFBF);{
Xfer((byte)L6470_PARAM_CONFIG);
stall_th = checkOverflow(stall_th, 0x7F);
Xfer((byte)(config >> 8));Xfer((byte)L6470_PARAM_STALL_TH);52

Xfer((byte)(config));}

long el_pos = 0;

Xfer((byte)L6470_PARAM_EL_POS);
el_pos |= Xfer(0);long L6470::getABS_POS(void){
return el_pos;long abs_pos = 0;}long L6470::getMARK(void)

Xfer((byte)L6470_PARAM_ABS_POS);{

abs_pos |= Xfer(0) << 16;long mark = 0;

abs_pos |= Xfer(0) << 8;
Xfer((byte)L6470_PARAM_MARK);
abs_pos |= Xfer(0);mark |= Xfer(0) << 16;
if (bitRead(abs_pos, 21))
mark |= Xfer(0) << 8;{mark |= Xfer(0);abs_pos = ~abs_pos;

if (bitRead(mark, 21))}{return abs_pos;

mark = ~mark;}}long L6470::getEL_POS(void){53

return mark;}long L6470::getDEC(void){

long L6470::getSPEED(void){

long dec = 0;long speed = 0;
Xfer((byte)L6470_PARAM_DEC);
Xfer((byte)L6470_PARAM_SPEED);

dec |= Xfer(0) << 8;

speed |= Xfer(0) << 16;

dec |= Xfer(0);speed |= Xfer(0) << 8;return dec;
speed |= Xfer(0);}long L6470::getMAX_SPEED(void)

return speed;{}
long max_speed = 0;long L6470::getACC(void){
Xfer((byte)L6470_PARAM_MAX_SPEED
long acc = 0;);
max_speed |= Xfer(0) << 8;

Xfer((byte)L6470_PARAM_ACC);
max_speed |= Xfer(0);acc |= Xfer(0) << 8;
acc |= Xfer(0);return max_speed;}

return acc;

long L6470::getMIN_SPEED(void)

}

{
54

long min_speed = 0;

Xfer((byte)L6470_PARAM_KVAL_HOLD);

Xfer((byte)L6470_PARAM_MIN_SPEED)

kval_hold |= Xfer(0);;min_speed |= Xfer(0) << 8;return kval_hold;}min_speed |= Xfer(0);long L6470::getKVAL_RUN(void){
return min_speed;}

long kval_run = 0;long L6470::getFS_SPD(void){

Xfer((byte)L6470_PARAM_KVAL_RUN);

long fs_spd = 0;

kval_run |= Xfer(0);Xfer((byte)L6470_PARAM_FS_SPD);return kval_run;}

fs_spd |= Xfer(0) << 8;long L6470::getKVAL_ACC(void)
fs_spd |= Xfer(0);{long kval_acc = 0;

return fs_spd;}
Xfer((byte)L6470_PARAM_KVAL_ACC);
long L6470::getKVAL_HOLD(void){

kval_acc |= Xfer(0);long kval_hold = 0;
return kval_acc;55

}long L6470::getKVAL_DEC(void)

Xfer((byte)L6470_PARAM_ST_SLP);{
st_slp |= Xfer(0);long kval_dec = 0;
return st_slp;
Xfer((byte)L6470_PARAM_KVAL_DEC);}kval_dec |= Xfer(0);long L6470::getFN_SLP_ACC(void){

return kval_dec;long fn_slp_acc = 0;}long L6470::getINT_SPEED(void)

Xfer((byte)L6470_PARAM_FN_SLP_ACC{);

long int_speed = 0;

fn_slp_acc |= Xfer(0);Xfer((byte)L6470_PARAM_INT_SPEED);

return fn_slp_acc;}

int_speed |= Xfer(0) << 8;long L6470::getFN_SLP_DEC(void)
int_speed |= Xfer(0);{long fn_slp_dec = 0;

return int_speed;}
Xfer((byte)L6470_PARAM_FN_SLP_DEC
long L6470::getST_SLP(void));{
fn_slp_dec |= Xfer(0);long st_slp = 0;56

return fn_slp_dec;}

Xfer((byte)L6470_PARAM_OCD_TH);

long L6470::getK_THERM(void)

ocd_th |= Xfer(0);{long k_therm = 0;

return ocd_th;}Xfer((byte)L6470_PARAM_K_THERM);

long L6470::getSTALL_TH(void){k_therm |= Xfer(0);long stall_th = 0;
return k_therm;}

Xfer((byte)L6470_PARAM_STALL_TH);

long L6470::getADC_OUT(void)

stall_th |= Xfer(0);{long adc_out = 0;

return stall_th;}

Xfer((byte)L6470_PARAM_ADC_OUT);

long L6470::getSTEP_MODE(void){

adc_out |= Xfer(0);long step_mode = 0;
return adc_out;}

Xfer((byte)L6470_PARAM_STEP_MODE);long L6470::getOCD_TH(void){

step_mode |= Xfer(0);long ocd_th = 0;57

return step_mode;

long status = 0;}long L6470::getALARM_EN(void)

Xfer((byte)L6470_PARAM_STATUS);{
status |= Xfer(0) << 8;long alarm_en = 0;
status |= Xfer(0);Xfer((byte)L6470_PARAM_ALARM_EN);
return status;
alarm_en |= Xfer(0);}return alarm_en;}
long L6470::getCONFIG(void)long

L6470::checkOverflow(long{long range)

data,

{
long config = 0;
if (range > 0)
Xfer((byte)L6470_PARAM_CONFIG);{

config |= Xfer(0) << 8;return checkOverflow(data, range, 0);
config |= Xfer(0);}return config;

else if (range < 0)}{long L6470::getSTATUS(void){
return checkOverflow(data, 0, range);58

return data;
}

}

else
{
byte L6470::Xfer(byte data)
return 0;{}

byte data_out;}
longL6470::checkOverflow(longdata,

digitalWrite(L6470_PIN_SS, LOW);

long max_range, long min_range){

data_out = SPI.transfer(data);

if (data > max_range)

digitalWrite(L6470_PIN_SS, HIGH);{
return data_out;}
data = max_range;}if (data < min_range){

data = min_range;}

59

気象観測機器スーちゃん

アイスのスーちゃんとお天気の物語

稲葉毬恵
金澤涼夏
鈴木万結子
中江雪乃
大阪教育大学附属高等学校天王寺校舎 地学部
2017年10月20日

要旨
この研究では、一目見て、気温と紫外線量、湿度を目に見える形で教えてくれる「スライム」を利用し、アイスク
リームを模したちょっと可愛い気象観測機器の作製を試みた。
本機器に最適な材料を実験により見出すことができたた
め、画像やデータを掲載した。しかし、機器としての実用性については調査が不足しており、課題も多く抱えている。

はじめに
スライムは暑くなるとドロドロに溶けてしまう。そんなスライムの溶け具合で温度が計測できるのではないかと考え、今回の気象観測機器を考案した。

気象観測機器：スーちゃん
特徴
特徴①

暑さでアイスが溶ける

特徴③ 湿度で巻紙が変色する

特徴② 紫外線量でアイスが変色する「スーちゃん」は
・気温
・紫外線量
・湿度
の三つの気象要素を簡単に視覚的に判断できる気象観測機器である。

構造

コーン部分
・紙粘土

アイス部分
・紫外線変色塗料を混ぜ込んだスライム

巻紙部分
・湿度で色変化する紙１

スーちゃん作製に伴う実験
実験１:スライムの硬度変化実験
目的
スーちゃんのアイス部分に最適な硬度のスライムを作製する。
方法
ホウ砂、水、洗濯のりの量を変化させ、適切な硬度のスライムを作製し(表2-1)、①を基準として、弾力、伸縮、実用性の３つの面で比較を行った。弾力とは机にスライムを落とした際の跳ね返り具合、伸縮とは手で上下に引っ張った際の伸び具合(図3-2)、
実用性とは手に乗せた際の形の崩れにくさ(図3-3)を示す。
(表2-1) スライム硬度変化実験 材料配分表

①

②

③

④

⑤

ホウ砂(g)

2.5

2.5

3.5

2.5

3.5

水(g)

75

75

75

95

75

洗濯のり(g)

50

70

50

50

70

実験２:紫外線変色スライム作成実験
目的
スライムを紫外線が照射されたときに視覚的な変化が起こるものにする。
方法
文献調査で得た紫外線で変色するものの一つ、紫外線増白剤を含む洗剤をスライムに混ぜ込む、塗るの2つの方法で実験を行った。

実験３:塩化コバルト紙の反応度実験
目的
通常の塩化コバルト紙は低湿度でも反応してしまい本研究には不向きのため、湿度の変化がよりわかりやすく、色変化の時間が短い、最適な紙を作製する。
方法
濾紙に含ませる塩化コバルトの量を変化させ、適切な塩化コバルト紙を作成し(表2-2）、高湿度の浴室で塩化コバルト紙が水に反応し、色が変化する速度と、色の彩度を目視で①と比較した。
(表2-２) コバルト紙の反応実験 材料配分表

①

②

③

④

塩化コバルト(g)

0.4

0.2

0.6

0.4

塩化カルシウム(g)

0.2

0.2

0.2

0.2

水(g)

3.4

3.4

3.4

1.7

２

実験結果１：スライム硬度変化実験
実験結果(図3-2) スライムの伸縮調査の様子(図3-1) 制作したスライム一覧(表3-1) スライム硬度変化実験 実験結果一覧

②

③

④

⑤

弾力性

◎

○

○

◎

伸縮性

△

◎

◎

△

固まりかた

○

△

×

◎

固まらない
(図3-３) スライム固まり具合調査の様子

実験結果(表3-1)は①と比較して、弾力はよく跳ねた方から、伸縮性はよく伸びた方から、固まり方はより形が崩れにくかったものから、◎、○、△、×と四段階で評価する。この結果から、弾力性、実力性の面で⑤（ホウ砂3.5g,水75g,のり70g）のスライムがスーちゃんに適していると判断した。よってこのスライムをスーちゃんに使用することとした。

考察・課題
結果②⑤より全体分量に対しのりが多いものほど固まりやすく、弾力性の強いものができているが、スライムは洗濯のりに含まれるポリビニルアルコール(PVA)がホウ砂イ
オンを介して水素結合してできているため、洗濯のりが多く全体量に対しホウ砂が少な
くなる②や⑤はより結合しにくくなるはずなので不思議な結果となった。
また前述を考慮すると、ホウ砂の割合の高い③において、スライムが固まりにくいという結果になっているため、これらの要因について、文献、実験による調査を深め、原因を調べていきたい。
３

実験結果２：紫外線変色スライム作成実験
実験結果
結果①
スライム作成時に、紫外線増白剤の入った洗剤を混ぜ込むと弾力性を失い、硬い個体になってしまった。
（図4-1）

結果②
作成済みのスライムの周りに洗剤をぬり、395nmのブラックライトを照射したところ、光る様子が確認された。この結果より、スーちゃんにはこの方法を使用することにした。
（図4-2）(図4-1) 硬化したスライム(図4-2) 紫外線を受けて発光するスライム

考察・課題
結果①でスライムが弾力性を失い硬くなった原因として、洗剤に含まれる塩化ナトリ
ウムが影響を与えたと考え、文献調査を行った。その結果、スライムと塩化ナトリウム
間で濃度の差異が生じ、高張液となっている塩化ナトリウムとの濃度の差を埋めるためにスライム内の水分が出てくることによって、構造が壊れてしまった可能性が考えられた。
結果②において、使用したブラックライトの波長は395nmであるが、日常生活で太陽から照射される紫外線の主な波長はUV-Aで、波長は310nm~380nmと、ブラックラ
イトに比べて短いため、実用的な面で正確なデータを得られなかったことが課題としてあげられる。
また、洗剤をスライムの周囲に塗ることでスライムにべたつきが生じるため対策を講じる必要がある。
また、蛍光増白剤は紫外線を受けると光るものであるが、白昼に光っていても周囲が明るいために光っていることが分からないのではないかという非常に重大な問題が考えられた。しかし、天候に恵まれず、雨天が続いたために野外実験を行うことができておらず、使用可能かも不明である。
今回は紫外線に反応し光るものを使用したが、実用性の低さも目立つため、今後は、
紫外線で日焼けをして変色するバナナの皮の性質や、紫外線変色ビーズなどの成分を調査し、応用することで、より視覚的かつ実用的な紫外線変色塗料を作成していきたいと考えている。
４

実験結果３：塩化コバルト紙の反応度実験
実験結果(表5-1) 塩化コバルト紙の反応実験 結果一覧

②

③

④

彩度

△

○

◎

色が変化する速度△〇○(図5-1) 青く変色する塩化コバルト紙(図5-2) 赤く変色する塩化コバルト紙

実験結果(表5-1)は①と比較し、彩度は色鮮やかな方から、色が変化する速度は変色速
度の速い方から、◎、○、△、×の四段階で評価する。この結果より、④の塩化コバル
ト紙が彩度、色が変化する速度の点でスーちゃんに適していると判断した。よって、この塩化コバルト紙をスーちゃんに使用することとした。

考察
結果①②③より、水の量に対し塩化コバルトの量を増加させるほど、紙が変色する速度が速くなった。この原因としては、全体量に対して、色変化を起こす塩化コバルトの量の割合が多いことが考えられた。
今回の実験では、湿度や気温管理が非常に曖昧な環境での調査となってしまったため、今後は厳密に湿度を管理し、変色時間なども測定し、精密なデータも収集したい。
④は水の量を基準となる①から半減させて制作した結果であるが、これも上記の考察
同様、全体量に対し、塩化コバルトの量が多く、変色速度が速くなっている。また彩度が高いのは、水の量が極端に少ないため、塩化コバルトの色が薄められなかったためだと考えられた。

５

結果：完成品
運用面
利点
・簡易的に使用できる。
・見た目が可愛い。
・視覚的に利用できるため、教材等にも使用できる。
課題点
・コーン部分に使用した粘土が重い・スライムが溶けたときにコーンからあふれてしまう。
・長期間スライムを置いていると乾燥で固化してしまう。

詳細
コーン部分
・紙粘土

巻紙部分
巻紙に作成した塩化コバルト紙を装飾として使用。
塩化コバルト紙

アイス部分
スライム
・ホウ砂3.5g
・水75g
・のり70g

紫外線で変色するよう
蛍光増白剤(洗剤)を塗装。

・塩化コバルト0.4g
・塩化カルシウム0.2g
・水1.7ｇ
・濾紙考察
私たちの生活に身近な気象を、簡易的かつ視覚的に表現するものが制作できたため、まだ数値を読めない小さな子供などにも理科の世界への興味を誘うようなものにもなると考える。
また、視覚的にも可愛いので、インテリアとしても使用しやすく、あらゆる層の人に使用されやすいと思う。さらに今後、ストラップなど携帯式のスーちゃんを作成するなど、より気象を身近に観測できるものにしたい。
６

終わりに
今後の課題等
今回の実験を経て残った課題である。
・蛍光増白剤が白昼に発光していても誰も気付かない。
・蛍光増白剤が、波長の長い太陽光の紫外線に反応するのかが不明。
・スライムが洗剤でべた付く。
・湿度変化による塩化コバルト紙の色変化のデータが無い。
・スーちゃんが重い。
・アイスが溶けて溢れ出す。
・アイスが固化するため長期間の使用ができない。
全体として実験の試行量が非常に少ないため、どの実験においてもあまり正確とは言えな
い結果になり、ありとあらゆる問題が浮上したが、上記の課題を参考に、研究を深め、さらに便利で精密なアイスクリームの気象観測機器を作っていきたいと思う。

感想研究開始が遅れたことに加え、学校行事やテストが重なり部員の確保が難しく思うように進めることができず、実験は、データ量及び試行回数が非常に少なくなり、満足の結果を得ることができなかった。
しかし、自分たちで観測機器を作るという点では、未知の経験で、またアイスクリームを模した簡易気象観測機器という実用性が高く、かわいく素敵な自慢の機器が製作できて非常に楽しい研究ができた。製作費用を頂いてありがとうございました。

謝辞
実験材料の準備や、実験の相談を度々受けて頂いた、地学部顧問の井村有里先生。ご協力ありがとうございました。

参考文献
・「スライムができる原理」http://slimeeee.com/about/principle.html(参照2017,10,4)
・「紫外線で浮かび上がる絵」https://site.ngk.co.jp/lab/no125/index.html(参照2017,10,10)
・山田真実,吉川廉「スライムの性質変化とその利用について」
・福島県立福島高等学校サイエンス探究クラス化学班スライムグループ「スライムの化学構造に関する一考察」
・朝日奈優衣,竹島亜実,東山つぼみ「スライム」

・「非電化湿度計『紫陽花』」http://www.hidenka.net/hidenkaseihin/ajisai/(参照2017,10,10)７