Pose.cpp
#include "StdAfx.h"
#include "Pose.h"
#include "Model.h"
#include "Link.h"
#include "Joint.h"
#include "Torque.h"
#include "SupportPolygon.h"
#include "ForwardKinematics.h"
using namespace Core;
using namespace Robotics;
using namespace System;
using namespace System::Diagnostics;
/// モデルから属性を取得して生成する [ Constructor ]
Pose::Pose( double time, Model^ model ) :
m_time( time )
{
m_standardLink = Link::Standard; // 基準リンク
m_positionOfStandardLink = gcnew PositionVector( m_standardLink->AbsolutePosition ); // 基準リンクの位置
m_postureOfStandardLink = gcnew RotationMatrix( m_standardLink->Posture ); // 基準リンクの姿勢
// リンクの数だけ 属性を生成する
CreateAttribute( model->Links->Length );
// ... モデルの状態を設定する
SetModelState( model );
}
/// ポーズをコピーして生成する [ Constructor ]
Pose::Pose( double time, Pose^ original ) :
m_time( time )
{
m_standardLink = original->m_standardLink; // 基準リンク
m_positionOfStandardLink = gcnew PositionVector( original->m_positionOfStandardLink ); // 基準リンクの位置
m_postureOfStandardLink = gcnew RotationMatrix( original->m_postureOfStandardLink ); // 基準リンクの姿勢
m_electricPower = original->m_electricPower; // 電力
m_centerOfGravity = gcnew PositionVector( original->m_centerOfGravity ); // 重心
m_supportPolygon = gcnew Core::SupportPolygon( original->m_supportPolygon );// 支持多角形
// リンクの数(角度の数で代用している)だけ 属性を生成する
CreateAttribute( original->m_angleOfJoints->Length );
// ... 全ての要素をコピーする
original->m_positionOfLinks->CopyTo( m_positionOfLinks, 0 );// リンクの位置
original->m_postureOfLinks->CopyTo( m_postureOfLinks, 0 ); // リンクの姿勢
original->m_angleOfJoints->CopyTo( m_angleOfJoints, 0 ); // 関節の角度
original->m_torqueOfJoints->CopyTo( m_torqueOfJoints, 0 ); // 関節のトルク
}
/// XMLから生成する [ Constructor ]
Pose::Pose( System::Xml::XmlElement^ element, Model^ model )
{
// 時間を属性から取得する
m_time = Double::Parse( element->GetAttribute( "time" ) );
Xml::XmlElement^ linkElement = element[ "standardLink" ]; // 基準リンクの要素
// 名称から 基準リンクを設定する
m_standardLink = model->Link[ linkElement->GetAttribute( "name" ) ];
m_positionOfStandardLink = gcnew PositionVector( linkElement ); // 基準リンクの位置
m_postureOfStandardLink = gcnew RotationMatrix( linkElement ); // 基準リンクの姿勢
// リンクの数だけ 属性を生成する
CreateAttribute( model->Links->Length );
// 全ての関節の要素に設定する
for each( Xml::XmlElement^ node in element[ "joint" ]->ChildNodes )
{
Debug::Assert( node != nullptr, "有効な要素である" );
// 属性からインデックスを取得する
int index = int::Parse( node->GetAttribute( "index" ) );
m_angleOfJoints[ index ] = Angle( Double::Parse( node->InnerText ) ); // 角度
}
// リンクの位置と姿勢を求める
ForwardKinematics::CalculatePositionAndPostureOfLinks( model->Links, m_angleOfJoints );
// ... モデルの状態を設定する
SetModelState( model );
}
/// 属性を生成する
void Pose::CreateAttribute( int numberOfLinks )
{
m_positionOfLinks = gcnew Positions( numberOfLinks );
m_postureOfLinks = gcnew Postures( numberOfLinks );
m_angleOfJoints = gcnew Angles( numberOfLinks );
m_torqueOfJoints = gcnew array< double >( numberOfLinks );
}
/// 基準リンクを設定する [ Property ]
void Pose::StandardLink::set( Link^ value )
{
Debug::Assert( value != nullptr, "基準リンクは定義されている" );
Debug::Assert( value->IsSupportingPhase(), "基準リンクは支持相である" );
m_standardLink = value; // 基準リンク
}
/// モデルの状態を設定する
void Pose::SetModelState( Model^ model )
{
m_centerOfGravity = gcnew PositionVector( model->CenterOfGravity ); // 重心
m_supportPolygon = gcnew Core::SupportPolygon( model->SupportPolygon ); // 支持多角形
Torque^ torque = gcnew Torque( model ); // トルク
double totalCurrent = 0.0; // 電流の合計
int index = 0;
for each( Link^ link in model->Links )
{
m_positionOfLinks[ index ] = gcnew PositionVector( link->AbsolutePosition ); // リンクの位置
m_postureOfLinks[ index ] = gcnew RotationMatrix( link->Posture ); // リンクの姿勢
double torqueValue = torque[ link ]; // トルク
m_angleOfJoints[ index ] = link->Joint->Angle; // 関節の角度
m_torqueOfJoints[ index ] = torqueValue; // 関節のトルク
// トルクにトルク定数を積算して 電流の合計に加算する
totalCurrent += Math::Abs( torqueValue * link->Joint->TorqueConstant );
index++;
}
// 電流の合計にモデルの電圧を積算して 電力を求める
m_electricPower = totalCurrent * model->Voltage;
}
/// モデルにポーズをとらせる
void Pose::PosedModel( Model^ model )
{
if( !m_standardLink->IsStandard() )
{
// 現在の基準リンクでなければ、それの位置と姿勢を強制的に設定する
m_standardLink->SetPositionAndPostureForcibly(
gcnew PositionVector( m_positionOfStandardLink ),
gcnew RotationMatrix( m_postureOfStandardLink )
);
/// @note
/// ハンドルを渡すと変更される恐れがあるため、
/// インスタンスを生成して渡している。
Debug::Assert( m_standardLink->IsStandard(), "基準リンクに設定される" );
}
// リンクの位置と姿勢を求める
ForwardKinematics::CalculatePositionAndPostureOfLinks( model->Links, m_angleOfJoints );
}
/// 関節の角度を補完する
void Pose::ComplementAngleOfJoints( Pose^ before, Pose^ after )
{
Debug::Assert(
( this->Time > before->Time ) &&
( this->Time < after->Time ),
"前後のポーズの時間関係は正しい"
);
double interval = ( after->Time - before->Time ); // 時間の差[ sec ]
double supplementaryValue = ( this->Time - before->Time ) / interval; // 補正値
for( int i = 0; i < m_angleOfJoints->Length; i++ )
{
// 前後のポーズ間の角度差に補正値をかけて、角速度を求める
double angularVelocity
= ( after->m_angleOfJoints[ i ] - before->m_angleOfJoints[ i ] ) * supplementaryValue;
// ... 前のポーズの角度に 角速度を加算した値を設定する
m_angleOfJoints[ i ] = before->m_angleOfJoints[ i ] + angularVelocity;
}
}
/// 設定を書き込む
System::Xml::XmlElement^ Pose::SaveSettings( System::Xml::XmlDocument^ document )
{
// ルートを生成する
Xml::XmlElement^ root = document->CreateElement( "pose" );
// ... 時間を属性として設定する
root->SetAttribute( "time", m_time.ToString() );
// 基準リンクの要素を生成する
Xml::XmlElement^ standardLink = document->CreateElement( "standardLink" );
// ... 基準リンクの名称を 属性として設定する
standardLink->SetAttribute( "name", m_standardLink->Name );
standardLink->AppendChild( m_positionOfStandardLink->ToXml( document ) ); // 基準リンクの位置
standardLink->AppendChild( m_postureOfStandardLink->ToXml( document ) ); // 基準リンクの姿勢
// ... 基準リンクの要素をルートに追加する
root->AppendChild( standardLink );
// 関節の要素を生成する
Xml::XmlElement^ jointElement = document->CreateElement( "joint" );
for( int index = 0; index < m_angleOfJoints->Length; index++ )
{
// 角度の要素を生成する
Xml::XmlElement^ angleElement = document->CreateElement( "angle" );
// ... インデックスを属性として設定する
angleElement->SetAttribute( "index", index.ToString() );
// ... テキストを追加する
angleElement->InnerText = safe_cast< double >( m_angleOfJoints[ index ] ).ToString();
/// @note
/// 角度クラスの ToString()を使用すると精度が失われるため、
/// doubleの ToString()を用いている。
// ... 関節の要素に追加する
jointElement->AppendChild( angleElement );
}
// ... 関節の要素をルートに追加する
root->AppendChild( jointElement );
return root;
}
/// 安定余裕を取得する
double Pose::StabilityMargin::get()
{
// 安定余裕を求めて返す
return m_supportPolygon->CalculateStabilityMargin( m_centerOfGravity );
}