ソフトウエア

Servomotor driver( コード )

サーボモータそのものを制御します。電子回路と接点になる部分です。サーボモータ制御の最下位層になります。

◀ この記事の前に: Servomotor driver( 操作説明 )
▶ この記事の次に: サーボモータの制御( コード詳説 )

概 要

サーボモータの制御は時間経過に伴う処理です。時間経過による処理は専用のタイマ割り込みにより直接行います。

モジュールの構造

サーボモータ制御は経時的な分散制御で、個々のサーボモータは順番に処理と出力を行います。
制御時間は専用のタイマ割り込みを使用します。タイマ割り込み回数の低減と処理時間の均一化を行うため、可変割り込み方式を使用しています。詳細は以下をご覧ください。

関数の概要

関数は以下のとおりです。

外部関数

他のジュールやファイルの外部からアクセス可能な関数です。


引 数:

・int svNo: 対象とするサーボモータ
・int position: ポジション( 角度 )

分 類:

API( 対象は Motion sequencer、他 )

機 能:

指定したサーボモータを指示した角度まで動かします。

関係する関数:

上位関数: Motion sequencer、アプリケーション
下位関数: なし
この関数のコードはこちらです。


引 数:

・int switchPower: サーボモータの電源 ON / OFF
 SV_POWER_ON : サーボモータの電源 ON
 SV_POWER_OFF: サーボモータの電源 OFF

分 類:

API( 対象は Servomotor Interpreter、他 )

機 能:

サーボモータの電源を ON / OFF する。

関係する関数:

上位関数: Servomotor interpreter、アプリケーション
下位関数: なし


引 数:

・int speed : 設定する速度

分 類:

API( 対象は Motion sequencer、他 )

機 能:

サーボモータを制御する基底速度を設定します。

関係する関数:

上位関数: Motion sequencer、アプリケーション
下位関数: なし
この関数のコードはこちらです。


内部関数

外部から直接アクセスできずモジュール( 特定のスコープ内 )で使用する関数です。


引 数:

・int svNo: 対象とするサーボモータ
・int position: ポジション( 角度 )

分 類:

初期化( setup() / setupSV() )

機 能:

サーボモータ制御の初期値を設定して、既定の位置にします。

関係する関数:

上位関数: setupSV()
下位関数: なし
この関数のコードはこちらです。


引 数:

なし

分 類:

内部関数( 初期化 ) 

機 能:

初期化を行います。

関係する関数:

上位関数: setup()
下位関数: setSVwidthFoaced()
この関数のコードはこちらです。


引 数:

なし

分 類:

内部関数( 初期化 ) 

機 能:

サーボモータ制御の専用タイマの初期化を行います。内部で割り込み処理の関数 intSVtimer()を結び付けます。

関係する関数:

上位関数: setup()
下位関数: ( なし )/ タイマ割り込み( TIM1 )
この関数のコードはこちらです。


引 数:

なし

分 類:

内部関数( タイマ割り込み / TIM2 ) 

機 能:

サーボモータ制御の処理本体。タイマ割り込みにより自律的に制御を行います。制御はサーボモータ制御定数に設定した内容に基づき行います。( サーボモータ制御定数が実質的な指示となります。 )

関係する関数:

上位関数: ( なし )/ タイマ割り込み( TIM1 )
下位関数: ( なし )
この関数のコードはこちらです。


引 数:

・int svNo: 対象とするサーボモータ
・int position: ポジション( 角度 )

戻り値:

・int : ポジションに対応するサーボモータの角度

分 類:

内部関数 

機 能:

Qumcum Lab. の頭部と四肢の位置は、Qumcum Lab. としての位置( 角度 )として表現して扱っています。この場合の位置を「ポジション」と呼びます。( 例:腕を上に上げるは左右の腕どちらも「上に上げる」という表現になります。)実際はサーボモータの取付方向などで、サーボモータとしての角度とポジションは異なります。( 腕は左右で取り付け位置が反転するため左右逆になります )
この関数はポジションとサーボモータの実際の角度を換算します。

関係する関数:

上位関数: setSVposition(), setSVwidthFoaced()
下位関数: ( なし )
この関数のコードはこちらです。


データの構造

データの構造は以下のとおりです。

グローバル定義

Servomotor driver のグローバル定義は以下のとおりです。

定 義

サーボモータの仕様に基づく基本的な定義
//******** Servomotors ********

//.... Moter specification ....
// PWM width : 50Hz ( 20msec. )
// Range of movement : 0 - 180 deg. / 0.5 - 2.4msec

const int		SV_ON		= HIGH;		// Output
const int 		SV_OFF		= LOW;
const int 		SV_TON_MIN	= 55;		//  50 X 10usec = 0.5msec.
const int 		SV_TON_MAX	= 240;		// 240 X 10usec = 2.4msec.
// Pulse count per degree
const	float 	SV_1DEG 	= ( (float)SV_TON_MAX - (float)SV_TON_MIN ) / 180;

//.... Number of motors ....
const int		SVN_MAX 	= 8;		// include dummy

//.... Timer Interruppt for PWM ....
// Clock : 80MHz
// Prescaler : 1/800 100kHz ( Timer clock )
//
const uint32_t	SV_INIT_INTERVAL	= 2000;	// 1000us = 1ms <<<<<<<<<<<<<<<<<<<<未使用
const int 		SV_PRESCALER		= 800;	// prescalor
const int 		SV_TM				= 2000;	// period motor control
const int 		SV_TMDIV			= SV_TM / SVN_MAX;
// divied on each motor

//.... Error code ....
const int SV_ERR_OVERANGLE = 999;

サーボモータ制御は Body MCUで行います。サーボモータの省電力制御のみ Peripheral MCU で行います。

//.... Power saving control of servo motors ....
#define SV_POWER_ON       1
#define SV_POWER_OFF      0
名 称説 明
SV_ONintHIGHON時のサーボモータの出力( 正論理 )
SV_OFFintLOWOFF時のサーボモータの出力( 正論理 )
SV_TON_MINint55ONデューティの最小幅時のカウント値
( タイマクロックが 10μsの場合 )
● クロックを変更した場合、ここも変更する。
SV_TON_MAXint240ONデューティの最大幅時のカウント値
( タイマクロックが 10μsの場合 )
● クロックを変更した場合、ここも変更する。
SV_1DEGfloat計算値1°あたりの ONデューティのカウント値
( (float)SV_TON_MAX – (float)SV_TON_MIN ) / 180
SVN_MAXint8サーボモータの搭載数( 軸数 )
ダミーひとつを含む
SV_POWER_ONdefine1サーボモータの電源 ON
SV_POWER_OFFdefine0サーボモータの電源 OFF
タイマ割り込みに関係する定義
名 称説 明
TM_SV_INIT_INTERVALuint32_t2000
TM_SV_PRESCALERint800タイマのプリスケーラ値
システムクロック周波数 80MHzに対して、1/800で 10μsのクロックを作る
SV_TMint2000サーボモータの1サイクル分の周期(カウント)
● 10μsの場合、( 2000 × 10μs ) / 1000 = 20 ms
SV_TMDIVint計算値サーボモータひとつあたりの分割時間
SV_TM / SVN_MAX = 2.5 ms

サーボモータの部位に関する定義

ここで定義する番号は、Qumcum Lab. の四肢と頭部のサーボモータの位置に対応づけられています。
Qumcum Lab. を組み立てるときに、四肢と頭部の番号を指定してコネクタと対応づけます。そのときの番号になります。なお Qumcum Lab. ではサーボモータが動かす部位を部位の名称としています。( 例:右脚の付け根にあるサーボモータは右足の方向を左右に動かしますので「右足」です。)
詳しくはこちらをご覧ください。

//.... Definitions Extremities ....
// Perspective on Robot
const int SV_DM = 0;	// dummy
const int SV_HD = 4;	// Head
const int SV_AR = 1;	// Arm Right
const int SV_AL = 7;	// Arm Left
const int SV_FR = 2;	// Foot Right
const int SV_FL = 6;	// Foot Left
const int SV_LR = 3;	// Leg Right
const int SV_LL = 5;	// Leg Left
名 称説 明
SV_DMint0( ダミー )
SV_HDint4Head / 頭部
SV_ARint1Arm Right / 右腕
SV_ALint7Arm Left / 左腕
SV_FRint2Foot Right / 右足
SV_FLint6Foot Left / 左足
SV_LRint3Leg Right / 右脚
SV_LLint5Leg Left / 左脚
サーボモータの制御定数( ピン割り当てを含む )

struct SV_PHYSICS svConverts[]

各サーボモータの制御に必要な基礎的な定数です。構造体 SV_PHYSICS( 後記 )の1次元配列です。
この並び( 添字 )が前記のサーボモータとなるため、各サーボモータの制御定数は配列要素の指定で参照できます。
ピンの割り当ては Body MCUの Leafony Busのポートです。
例)svConverts[SV_HD].svMaxPos: 頭部の角度の既定値

struct SV_PHYSICS svConverts[]={
	{ 0,     0, 180,  1,   0, 0,  +10, -10 },	// 0:SV_DM, Mdummy
	{ PB12,  0, 180,  1,   0, 0, +180,   0 },	// 1:SV_AR, Arm Right
	{ PA9,  50, 130,  1,  90, 0,  +40, -40 },	// 2:SV_LR, Leg Right
//	{ PA10, 60, 120,  1,  90, 0,  +30, -30 },	// 3:SV_FR, Foot Right	//<<<< !!! actually PC0 for SMPLE
	{ PC1,  60, 120,  1,  90, 0,  +30, -30 },	// 3:SV_FR, Foot Right	//<<<< !!! actually PC0 for EXTEND
	{ PC0,   0, 180,  1,  90, 0,  +90, -90 },	// 4:SV_HD, Head
	{ PC7,  60, 120, -1,  90, 0,  +30, -30 },	// 5:SV_FL, Foot Left
	{ PB5,  50, 130, -1,  90, 0,  +40, -40 },	// 6:SV_LL, Leg Left
	{ PB4,   0, 180, -1, 180, 0, +180,   0 } 	// 7:SV_AL, Arm Left
};
svPinsvLowestDegsvHightestDegsvFactorAsvFactorBsvDefaultPossvMaxPossvMinPos
SV_DM00180100+10-10
SV_ARPB120180100+1800
SV_FRPA9501301900+40-40
SV_LRPC0601201900+30-30
SV_HDPC101801900+90-90
SV_LLPC760120-1900+30-30
SV_FLPB350130-1900+40-40
SV_ALPB40180-11800+1800
省電力制御用のピン

省電力制御は Body MCUで行います。

//.... Power saving control of servo motors ....
#define PIN_PS_SV       PB0
名 称STM32 – Pin.用 途
PIN_PS_SVPB0サーボモータの省電力制御( 電源の ON / OFF )

構造体

各サーボモータの制御定数
struct SV_PHYSICS {
	uint8_t	svPin;		// Outout port
	int	svLowestDeg;	// Lowest degrees
	int	svHightestDeg;	// Hightest degrees
	int	svFactorA;		// Convert factor A
	int	svFactorB;		// Convert factor B
	int	svDefaultPos;	// Default position
	int svMaxPos;		// Maximun position
	int svMinPos;		// Minimum position
};
要素名単 位説 明
svPinuint8_tモータ角度サーボモータの接続ポート(ピン)
svLowestDegintモータ角度サーボモータの最小動作角度
svHightestDegintモータ角度サーボモータの最大動作角度
svFactorAintモータ角度ポジションと角度の換算用係数 A
svFactorBintモータ角度ポジションと角度の換算用係数 B
svDefaultPosintポジション既定の角度
svMaxPosintポジション角度の最大値 * 現在未使用
svMinPosintポジション角度の最小値 * 現在未使用

モータ角度: サーボモータとしての実際の角度です。

グローバル変数

各サーボモータの制御変数
//.... Current control parameters ....
struct SV_CURRENT {
	int svPos;				// Current Position
	int	svTon;				// Current ON width
	int	svToff;				// Current OFF width

	float svDegStart;		// Start angle
	float svDegCurrent;		// Current angle
	float svDegTarget;		// Target angle
};
要素名説 明
svPosint現在の角度( ポジション )
svTonint現在の ONデューティ
svToffint現在の OFFデューティ
svDegStartfloat変更前( 操作開始時 )の角度
svDegCurrentfloat現在( 操作中 )の角度
svDegTarget;float変更後( 目標 )の角度
サーボモータの補正値
//.... Current control parameters ....
struct SV_PARAMETER {
	int svOffset;		// Current Position
};
要素名説 明
svOffsetint補正値
サーボモータの制御変数( 共通 )
/*============================================================================*/
// Motion driver / MD

//.... Control Variable ....
// Servomotor 
int		ggSVno		= 0;		// cyclic control
int		ggSVout		= SV_OFF;	// output control

float	gSVspeedDev	= 1.0; 		// angular velocity
変数名初期値説 明
gSVnoint0現在の制御対象となっているサーボモータ intSVtimer()内
gSVoutintSV_OFF現在の制御対象となっているサーボモータの出力状態 intSVtimer()内
gSVspeedDevfloat1.0サーボモータの角速度
サーボモータ制御の1サイクルあたりの増減分 intSVtimer()内
詳細はこちらをご覧ください。

gSVspeedDev のアクセス箇所
参照:  intSVtimer() タイマ割り込みによるサーボモータのリアルタイム制御の実体
設定: setSpeedSV()
setSpeedSV() は、Motion sequencer の procElementSq()、Motion interpreter の procMIsetSpeedSV() で設定します。( サンプルプログラムでは )

サーボモータの制御変数( 各サーボモータ )

struct SV_CURRENT svCurrents[]

各サーボモータの制御に必要な基礎的な定数です。構造体 SV_CURRENT( 前記 )の1次元配列です。
この並び( 添字 )が前記のサーボモータとなるため、各サーボモータの制御定数は配列要素の指定で参照できます。
例)svConverts[SV_HD].svMaxPos: 頭部の角度の既定値

svConverts[] の初期値

struct SV_CURRENT svCurrents[]={
	{ 0, 0, 0, 0, 0, 0 },		// 0:SV_DM, Mdummy
	{ 0, 0, 0, 0, 0, 0 },		// 1:SV_AR, Arm Right
	{ 0, 0, 0, 0, 0, 0 },		// 2:SV_LR, Leg Right
	{ 0, 0, 0, 0, 0, 0 },		// 3:SV_FR, Foot Right
	{ 0, 0, 0, 0, 0, 0 },		// 4:SV_HD, Head
	{ 0, 0, 0, 0, 0, 0 },		// 5:SV_FL, Foot Left
	{ 0, 0, 0, 0, 0, 0 },		// 6:SV_LL, Leg Left
	{ 0, 0, 0, 0, 0, 0 }		// 7:SV_AL, Arm Left
};
svPossvTonsvToffsvDegStartsvDegCurrentsvDegTarget
SV_DM000000
SV_AR000000
SV_FR000000
SV_LR000000
SV_HD000000
SV_LL000000
SV_FL000000
SV_AL000000

サーボモータの補正値

struct SV_PARAMETER svParameters[]

各サーボモータに物理的に固有なズレを補正するためのパラメータ( 補正値 )です。
サーボモータは個々の部品や、取り付けにばらつきがあります。このばらつきを調整することが目的です。そのため個々の Qumcum Lab.によりこの値は異なります。

この値は個々の により異なるため、サンプルプログラムではスマートフォン( リモコン )から設定できます。また、補正値は MCUのフラッシュメモリに保存して電源 OFF時にも補正値は保存します。

例)svParameters[SV_LR].svOffset: 右脚の角度補正値

svParameters[] の初期値( 値は例です。個々の Qumcum Lab.により異なります。 )
角度はポジションの表記です。● サーボモータの実角度に変更の予定あり。

struct SV_PARAMETER svParameters[]={
	{  0 },	// 0:SV_DM, Mdummy
	{  4 },	// 1:SV_AR, Arm Right
	{ -4 },	// 2:SV_FR, Foot Right	
	{ -4 },	// 3:SV_LR, Leg Right	
	{ -4 },	// 4:SV_HD, Head
	{ -4 },	// 5:SV_LL, Leg Left	
	{ -4 },	// 6:SV_FL, Foot Left	
	{  0 }	// 7:SV_AL, Arm Left
};
サーボモータsvOffset
SV_DM0
SV_AR4
SV_FR-4
SV_LR-4
SV_HD-4
SV_LL-4
SV_FL-4
SV_AL0

制御変数と関数の関係

主要な制御変数( 定数を含む )と関数の関係は以下のとおりです。制御定数はおもに仕様に関係するデータ、制御変数は個々のサーボモータの制御に関係するデータです。

コード

コードは以下のとおりです。

オブジェクト

ハードウエアタイマを使用します。STM32L4 は用途別に10本を超えるタイマを搭載しています。そのうち汎用タイマであるTIM1( タイマ1 )を使用します。


//---------------------------------------------------------------------
// object
//---------------------------------------------------------------------

//------------------------------
// Timer
//------------------------------
HardwareTimer *SVtimer = new HardwareTimer( TIM1 );

関数間の関係

関数の関係は以下のとおりです。
割り込みに関しては以下もご覧ください。
可変タイマ割り込み


サーボモータの電源を ON / OFF する。

setSVpowerControl( int switchPower )  {

	digitalWrite( PIN_PS_SV, switchPower );

}	

指定したサーボモータを指示した角度まで動かします。

/*----------------------------------------------------------------------------*/
// Set position servomoter / Servomotor
//
// - convert from position to angle.
// - check range of movement.
//
// param     : int svNo :
//						 int position :
// return    : angle / Error code
//
// reference : svCnverts / Physical parameters
//
// param     : non
// return    : non
/*----------------------------------------------------------------------------*/
int setSVposition( int svNo, int position )
{
	position += svParameters[svNo].svOffset;			// debug 補正は本来、angleで行いたい

	int	angle = convertSVangle( svNo, position );

	if( angle != SV_ERR_OVERANGLE ){
		svCurrents[svNo].svDegTarget = angle;
	}

	return angle;
}

サーボモータの制御はバックグラウンド処理で自律的に行っています。

Motion sequencer やアプリケーションなどからサーボモータの角度を変更する場合に setSVposition() を使用します。この関数は変更したい角度( 目標角度 )をサーボモータの制御変数 svCurrents[] に書き込みます。

サーボモータ制御の実体は、専用のタイマ割り込みで連続的に処理を行っています。その中でサーボモータの制御変数 svCurrents[] を参照して、目標角度が現在の角度と異なる場合に、目標角度になるように intSVtimer() が自律的にサーボモータのリアルタイム制御処理を行います。

要点が二つあります。ひとつはデータを介した制御を行うデータ駆動型であることです。もうひとつはバックグラウンド処理とフォアグランド処理の連携方法です。このしくみによりアプリケーション側とサーボモータがそれぞれ独立して動作することができます。また、プログラミングで相互依存しないため作りやすくなることと、バグの発生を抑えることができます。

サーボモータを制御する基底速度を設定します。

/*----------------------------------------------------------------------------*/
/* Core processing MS
/* param     : non
/* return    : non
/*----------------------------------------------------------------------------*/
void setSpeedSV( int speed )
{
	//---- update PWM width ----
	// caution
	// Pause Interrupt
	noInterrupts();		// pause
	gSVspeedDev = speed;
	interrupts();		// resume
}

サーボモータ制御の初期値を設定して、既定の位置にします。

/*----------------------------------------------------------------------------*/
/* Core processing MS
/* param     : non
/* return    : non
/*----------------------------------------------------------------------------*/
int setSVwidthFoaced( int svNo, int position )
{
	position += svParameters[svNo].svOffset;			// debug 補正は本来、angleで行いたい
	int	angle = convertSVangle( svNo, position );

	if( angle != SV_ERR_OVERANGLE ){
		svCurrents[svNo].svDegTarget	=	angle ;
		int	Ton = (int)(SV_1DEG * angle + SV_TON_MIN);
		int	Toff = SV_TMDIV - Ton;

	//---- update PWM width ----
	// caution
	// Pause Interrupt
	noInterrupts();					// pause
		svCurrents[svNo].svPos  = position;
		svCurrents[svNo].svTon  = Ton;
		svCurrents[svNo].svToff = Toff;
	
		svCurrents[svNo].svDegStart		=	angle;
		svCurrents[svNo].svDegCurrent	=	angle;
		svCurrents[svNo].svDegTarget	=	angle;
	interrupts();					 // resume
	}

	return angle;
}

初期化を行います。

/*----------------------------------------------------------------------------*/
/* Initialize Servomotors
/* param     : -
/* return    : -
/*----------------------------------------------------------------------------*/
void setupSV()
{
	int		pin;
	int		position;

	// * caution *
	// SV_DM(1) is dummy
	for (int i=1; i < SVN_MAX; i++){

		//.... Initialize Ports ....
		pin = svConverts[i].svPin;
		pinMode( pin, OUTPUT );			// need to "OUTPUT" <<< next is OUTPUT_OPEN_DRAIN
		digitalWrite( pin, SV_OFF );

		//.... Initialize Servomotor Position ...
		position = svConverts[i].svDefaultPos;
		setSVwidthFoaced( i, position );

	}
		//.... Dummy ...
		position = svConverts[0].svDefaultPos;
		setSVwidthFoaced( 0, position );
}

Servomotor driver の初期化は二つあります。setupSV() と setupSVtimerInt()です。
setupSV() 内では、ハードウエアに関係するポートの設定と、初期角度の設定です。

サーボモータ制御の専用タイマの初期化を行う。内部で割り込み処理の関数 intSVtimer()を結び付けます。

/*----------------------------------------------------------------------------*/
/* Initialize control servomotors timer
/* param     : -
/* return    : -
/*----------------------------------------------------------------------------*/
void setupSVtimerInt()
{
	//.... Initialize Timer and Interrupt ....
	SVtimer->pause();
	SVtimer->setPrescaleFactor( TM_SV_PRESCALER );
	SVtimer->setOverflow( 50 );
	SVtimer->attachInterrupt( intSVtimer );
	SVtimer->refresh();
	SVtimer->resume();
}

サーボモータはリアルタイム制御です。専用のタイマ割り込みを使用します。( TIM1 )
この中でタイマ割り込み処理 intSVtimer() をタイマ割り込みに対応づけます。

サーボモータ制御の処理本体。タイマ割り込みにより自律的に制御を行います。制御はサーボモータ制御定数に設定した内容に基づき行います。( サーボモータ制御定数が実質的な指示となります。 )

/*----------------------------------------------------------------------------*/
// Timer interrupt / Control Servomoters
// param     : -
// return    : void
/*----------------------------------------------------------------------------*/
void intSVtimer()
{
	int	width;
	int pin;

	//---- Pause Interrupt ----
	SVtimer->pause();

		//******** Detect edge and Set next timing ********

		//........ Edge of ON -> OFF ........
		if( gSVout == SV_ON ){
			gSVout = SV_OFF;
			width  = svCurrents[gSVno].svToff;

		//........ Edge of OFF -> ON ........
		} else {

			// Next Servomotor
			gSVno++;
			if( gSVno >= SVN_MAX ) gSVno = 0;

			float svDegStart	= svCurrents[gSVno].svDegStart;		// Start angle
			float svDegCurrent	= svCurrents[gSVno].svDegCurrent;	// Current angle
			float svDegTarget	= svCurrents[gSVno].svDegTarget;	// Target angle
		
			if ( svDegStart == svDegTarget ) {			//	stop
				svDegStart			= svDegTarget;
				svDegCurrent		= svDegTarget;

			} else if ( svDegStart < svDegTarget ) {	// increse angle
					svDegCurrent += gSVspeedDev;
					if ( svDegCurrent > svDegTarget ) {	//	stop
						svDegStart		= svDegTarget;
						svDegCurrent	= svDegTarget;
					}
			
			} else if ( svDegStart > svDegTarget ) {	// decrese angle
					svDegCurrent -= gSVspeedDev;
					if ( svDegCurrent < svDegTarget ) {	//	stop
						svDegStart		= svDegTarget;
						svDegCurrent	= svDegTarget;
					}
			}

			svCurrents[gSVno].svDegStart	= svDegStart;		// Start angle
			svCurrents[gSVno].svDegCurrent	= svDegCurrent;		// Current angle
			svCurrents[gSVno].svDegTarget	= svDegTarget;		// Target angle
			svCurrents[gSVno].svTon			= (int)(SV_1DEG * svDegCurrent + SV_TON_MIN);
			svCurrents[gSVno].svToff		= SV_TMDIV - svCurrents[gSVno].svTon;

			gSVout = SV_ON;
			width = svCurrents[gSVno].svTon;
		}	

		//******** Output to Servomotor ********

		//........ Output ........
		if( gSVno != SV_DM ){
			pin = svConverts[gSVno].svPin;
			digitalWrite( pin, gSVout );

		//........ Dummy / no output ........
		}else{
		}

		//******** Restart Timer ********
		SVtimer->setOverflow( width );
		SVtimer->refresh();

	//---- Resume Interrupt ----
	SVtimer->resume();

}

サーボモータ制御は分散処理でサーボモータを制御します。タイマ割り込みがあるたびに順番に各サーボモータの処理を行い出力をおこないます。また、可変割り込み方式なので割り込みのたびに次の割り込みまでの間隔をタイマにオーバフロー値として設定します。

処理の最初にタイマのカウントを停止して、処理が終了したときにタイマのカウントを再開します。
制御はサーボモータの信号線の1サイクルがひとつの処理になっており、出力が OFFから ONになるとき( ONデューティの始め )に各設定値を計算します。出力が ONから OFFになるとき( OFFデューティ )には信号線の変更のみを行います。

処理は現在の角度と目標角度を比較して、その大小により角速度に応じた増減を行います。現在の角度は実測値でなくプログラムが認識している値です。角度はサーボモータとしての実際の角度です。( ポジションではありません。)

  • 現在の角度 = 目標角度: 何もしない
  • 現在の角度 < 目標角度: 増分を現在の角度に加算する
  • 現在の角度 > 目標角度: 減分を現在の角度に減算する

増分と減分は角速度に応じた増減値 gSVspeedDevです。
現在の角度と目標角度が異なる場合、この処理を行うごとに現在の角度は目標角度に近づきます。同じ角度になった時点で増減がなくなり角度が一定となりこれが目標角度です。角度の算出後はサーボモータを制御するための ONデューティの時間に変換します。計算式は以下のとおりです。

ONデューティ = SV_1DEG × svDegCurrent + SV_TON_MIN
OFFデューティ = SV_TMDIV – svCurrents[gSVno].svTon

・SV_1DEG : 1°あたりの ONデューティ時間
・svDegCurrent: 現在の角度( °(度) )
・SV_TON_MIN: ONデューティの最小値( 0.5 ms )
・SV_TMDIV: サーボモータ1つあたりの制御幅( 20 ms )
・svCurrents[gSVno].svTon: ONデューティ時間

以下を設定してタイマ割り込み処理から戻ります。

  • 出力: ポート、ON / OFF
  • タイマ割り込み: 次の割り込みまでの間隔
  • 制御変数: 現在の角度の更新( 開始角度、目標角度の更新 / 目標角度になった場合 )

ポジションとして表現した角度から、サーボモータの実際の角度に換算します。

/*----------------------------------------------------------------------------*/
// Convert from Position to Angle / Servomotor
//
// - convert from position to angle.
// - check range of movement.
//
// param     : int svNo :
//						 int position :
// return    : angle / Error code
//
// reference : svCnverts / Physical parameters
//
/*----------------------------------------------------------------------------*/
int convertSVangle( int svNo, int position )
{
	int		fA 	 = svConverts[svNo].svFactorA;
	int		fB 	 = svConverts[svNo].svFactorB;
	int		posL = svConverts[svNo].svLowestDeg;
	int		posH = svConverts[svNo].svHightestDeg;
	
	int		angle = fB + fA * position;

	if ( posL > angle ) angle = SV_ERR_OVERANGLE;
	if ( posH < angle ) angle = SV_ERR_OVERANGLE;

	return angle;
}

アプリケーションなどはサーボモータの角度を「ポジション」という角度の表現で扱います。実際のサーボモータの角度とは異なります。この関数はポジションをサーボモータの実際の角度に変換します。同時に可動範囲を超えないように角度を制限します。

角度の変換

頭部はポジションの表現で、正面を向いている時が 0°、右を向いているときが -90°、左を向いているときが +90°になります。これをサーボモータの実際の角度にすると、右を向いているときが 0°、正面を向いているときが 90°、左を向いているときが180°になります。
ポジションにオフセット値を加算すると変換できます。

回転方向の変換

左または右腕が下向きのときはポジションの表現で 0°、前向き(前へならえの位置)で 90°、上向き(万歳の向き)で 180°です。これをサーボモータの実際の角度にすると、左腕と右腕のサーボモータの取付方向は正反対です。そのため、右腕のサーボモータの実際の動作方向は左腕と正反対になります。
ポジションに -1を掛けると変換できます。

変換式

前記より変換式は以下のとおりです。

θa = fa × θp + fb

・θp: ポジション表記の角度 
・θa: サーボモータの実際の角度
・fa: 回転方向の変換
・fb: 角度のオフセット値

回転角度の制限値

サーボモータを設置する部位により回転できる範囲( 可動範囲 )が決まっています。その範囲を越えると破損や故障につながります。そのため、各サーボモータに制限値を設定しています。ポジションから角度に変換した後で、角度が制限内に入っていることの確認を行います。制限内に入っていない場合はエラーコード( SV_ERR_OVERANGLE )を戻り値として返します。

係数と制限値の参照

角度の変更と制限値はサーボモータの制御定数 avConverts[]にあります。

  • 回転方向の変換を行うための係数 fa: svConverts[svNo].svFactorA
  • 角度の変更のためのオフセット値 fb: svConverts[svNo].svFactorB
  • 回転角度の制限値( 下限 ): svConverts[svNo].svLowestDeg
  • 回転角度の制限値( 上限 ): svConverts[svNo].svHightestDeg

SvNo は対象とするサーボモータです。( SV_HD, SV_AL, SV_AR, ・・・ )

参考情報

サイトで参考になる情報は以下のとおりです。

このホームページ内

他のWebサイト

カテゴリー
最近の記事 おすすめ記事

記事一覧を表示するには、カスタム投稿「ブログ」にて、4つ以上記事を作成してください。

記事一覧を表示するには、カスタム投稿「ブログ」にて、4つ以上記事を作成してください。

TOP