Ejemplo n.º 1
0
arma::mat TaskOrientation::getJacobianForTask(const KinematicTree &kinematicTree, arma::mat &jacobianWithoutRemovedDOFs, bool normalizeJacobian) const
{
	UNUSED(normalizeJacobian); // the jacobian must be normalized within its calculation!
	arma::mat jacobian = arma::zeros(getDimensionCnt(), kinematicTree.getMotorCnt());

	arma::mat33 forward = arma::eye(3, 3);
	arma::mat33 intermediateTransition = arma::eye(3, 3);

	for (uint32_t pathIndex = 0; pathIndex < m_invPath.size(); ++pathIndex)
	{
		const KinematicNode *node = m_invPath[pathIndex].m_node;
		arma::colvec3 orientationOfNode = forward.col(m_axis);

		if ((false == node->isFixedNode()) &&
			(KinematicPathNode::Direction::LINK != m_invPath[pathIndex].m_direction) &&
			(pathIndex < m_invPath.size() - 1))
		{
			kinematics::JacobianValues partialDerivatives = node->getPartialDerivativeOfOrientationToEffector(orientationOfNode);
			double sign = 1;
			if (KinematicPathNode::Direction::FROM_PARENT == m_invPath[pathIndex].m_direction)
			{
				/* in this case the rotation axis of the joint is inverted... */
				sign = -1;
			}

			for (kinematics::JacobianValue value : partialDerivatives) {
				jacobian.col(value.first) = value.second * sign;
			}
		}

		if (pathIndex < m_invPath.size() - 1)
		{
			const KinematicNode *nextNode = m_invPath[pathIndex + 1].m_node;
			intermediateTransition = node->getInvMatrixToRelative(nextNode).submat(0, 0, 2, 2);
			forward = intermediateTransition * forward;

			/* update the previously calculated entries in the jacobian according to our current orientation */
			jacobian = intermediateTransition * jacobian;
		}
	}

	/* transform the jacobian into the reference coordinate system */
	arma::mat33 transformToReferenceSystem = kinematicTree.getTransitionMatrixFromTo(m_referenceCoordinateSystem, m_baseNode).submat(0, 0, 2, 2);

	jacobian = transformToReferenceSystem * jacobian;

	jacobianWithoutRemovedDOFs = jacobian;
	removeDOFfromJacobian(jacobian, kinematicTree);

	return jacobian;
}
arma::mat InverseKinematicJacobian::getJacobianForTasks(KinematicTree const& tree, std::vector<const Task*> const& tasks, arma::mat &jacobianRAW, bool normalize) const
{
	const uint32_t numTasks = tasks.size();
	uint numCols = tree.getMotorCnt();

	arma::mat jacobian = arma::zeros(1, numCols);
	if ((0 < numTasks) &&
		(0 < numCols)) /* at least one task and at least one motor */
	{
		/* calculate the size of the jacobian and the task vector */
		uint32_t numRows = 0;
		for (const Task* const &task : tasks)
		{
			if (task->hasTarget()) {
				numRows += task->getDimensionCnt();
			}
		}

		/* build the "big" jacobian */
		jacobian = arma::zeros(numRows, numCols);
		jacobianRAW = arma::zeros(numRows, numCols);

		uint32_t beginRow = 0;
		for (const Task *const &task : tasks)
		{
			if (task->hasTarget())
			{
				const uint32_t endRow = beginRow + task->getDimensionCnt() - 1;
				arma::mat jacobianRawSub;
				jacobian.submat(beginRow, 0, endRow, numCols - 1) = task->getJacobianForTask(tree, jacobianRawSub, normalize);
				jacobianRAW.submat(beginRow, 0, endRow, numCols - 1) = jacobianRawSub;

				beginRow = endRow + 1;
			}
		}
	}

	return jacobian;
}
double InverseKinematicJacobian::iterationStep(
		KinematicTree const& tree
		, MotorValuesMap& o_values
		, TasksContainer const& alltasks
		, Constraints const& constraints
		, const TaskDefaultPosition* idleTask
	) const
{
    std::cout << "\x1B[2J\x1B[H";
	double totalError = 0;
	const uint motorCnt = tree.getMotorCnt();

	arma::colvec motorValuesVec = arma::zeros(motorCnt);
	std::map<NodeID, KinematicNode*> const& nodes = tree.getNodes();

	for (std::pair<NodeID, KinematicNode*> const& node : nodes) {
		if (node.second->isServo())
		{
			kinematics::Motor2IntMap const& motor2Int = node.second->getMotor2IntMap();
			MotorValuesMap const& values = node.second->getValues();

			for (std::pair<MotorID, double> const& value : values) {
				motorValuesVec(motor2Int.at(value.first)) = value.second;
			}
		}
	}

	arma::colvec summedJointAngleDiffs = arma::zeros(motorCnt);
	arma::mat nullspaceEyeMat = arma::eye(motorCnt, motorCnt);
	arma::mat nullspaceMat = nullspaceEyeMat;

	arma::mat bigJacobian;
	for (std::pair<uint, std::vector<const Task*>> const& group : alltasks) {
		std::vector<const Task*> const& tasks = group.second;

		if (tasks.size() > 0) {
			arma::mat jacobianRAW;
			const arma::mat jacobian = getJacobianForTasks(tree, tasks, jacobianRAW, false);

			const arma::colvec errorVec = getErrorForTasks(tree, tasks);

			const arma::mat pseudoInverseJacobian = buildPseudoInverse(jacobian, m_speedEpsilon);

			const arma::colvec jointDiffs = pseudoInverseJacobian * errorVec;
			const arma::colvec jointDiffsDecorr = nullspaceMat * jointDiffs;

			const arma::colvec preliminaryJointAngles = motorValuesVec + summedJointAngleDiffs + jointDiffsDecorr;
			arma::colvec jointDiffConstraintError = arma::zeros(motorCnt);
			arma::colvec correctedJointAngleDiffs = jointDiffsDecorr;

			for (const Constraint* constraint : constraints) {
				jointDiffConstraintError += constraint->getAngleErrorForConstraint(tree, preliminaryJointAngles);
			}

			// correct the constraint error
			for (uint i(0); i < motorCnt; ++i) {
				const double factor = nullspaceMat(i, i);
				if (factor > m_nullspaceEpsilon) {
					jointDiffConstraintError(i) = jointDiffConstraintError(i) / factor;
				} else {
					jointDiffConstraintError(i) = 0;
				}
			}

			correctedJointAngleDiffs += nullspaceMat * jointDiffConstraintError;

			summedJointAngleDiffs += correctedJointAngleDiffs;

			bigJacobian = arma::join_cols(bigJacobian, jacobianRAW);
			nullspaceMat = nullspaceEyeMat - buildPseudoInverse(bigJacobian, m_nullspaceEpsilon) * bigJacobian;

			totalError += arma::dot(errorVec, errorVec);

//			std::cout << "level " << group.first << std::endl;
//			std::cout.precision(7);
//			std::cout << std::fixed << std::setw(12);
//			bigJacobian.raw_print(std::cout, "bigJacobian = ["); printf("]\n");
//			jacobian.raw_print(std::cout, std::string("jacobian") + std::to_string(group.first) + " = ["); printf("]\n");
//			bigJacobian.raw_print(std::cout, std::string("bigJacobian") + std::to_string(group.first) + " = ["); printf("]\n");
//			jacobianDOF.raw_print(std::cout, "jacobianDOF = ["); printf("]\n");
//			arma::mat(jacobian * dofMat).raw_print(std::cout, "jacobianDOF2 = ["); printf("]\n");
//			jointDiffs.t().raw_print(std::cout, std::string("jointDiffs") + std::to_string(group.first) + " = ["); printf("]\n");
//			jointDiffsDecorr.t().raw_print(std::cout, std::string("jointDiffsDecorr") + std::to_string(group.first) + " = ["); printf("]\n");
//			summedJointAngleDiffs.t().raw_print(std::cout, "summedJointAngleDiffs = ["); printf("]\n");
//			jointDiffConstraintError.t().raw_print(std::cout, "jointDiffConstraintError = ["); printf("]\n");
//			correctedJointAngleDiffs.t().raw_print(std::cout, "correctedJointAngleDiffs = ["); printf("]\n");
//			errorVec.t().raw_print(std::cout, std::string("errorVec") + std::to_string(group.first) + " = ["); printf("]'\n");
//			nullspaceMat.raw_print(std::cout, "nullspaceMat = ["); printf("]\n");
//			std::cout << arma::norm(errorVec, 2) << std::endl;
//			printf("\n");
		}
	}

	if (nullptr != idleTask) {
		arma::mat helper = arma::mat(nullspaceEyeMat - nullspaceMat);
		arma::colvec errorVec = idleTask->getErrors(tree);
		arma::colvec angleDiffVec = ((nullspaceEyeMat - nullspaceMat) * errorVec);
		summedJointAngleDiffs += angleDiffVec;
	}

	for (uint32_t i = 0; i < summedJointAngleDiffs.n_rows; ++i)
	{
		summedJointAngleDiffs(i) = utils::limited(summedJointAngleDiffs(i), -m_maxValueChange, m_maxValueChange);
	}

	motorValuesVec += summedJointAngleDiffs;

	for (std::pair<NodeID, KinematicNode*> const& node : nodes) {
		if (node.second->isServo())
		{
			kinematics::Int2MotorMap const& int2MotorMap = node.second->getInt2MotorMap();
			kinematics::MotorIDs const& motors = node.second->getMotors();
			MotorValuesMap newValues;

			for (kinematics::Int2Motor const& i2m : int2MotorMap) {
				newValues[i2m.second] = motorValuesVec(i2m.first);
			}

			/* clip values */
			newValues = node.second->clipValues(newValues);

			/* export */
			for (MotorID const& motor : motors) {
				o_values[motor] = newValues[motor];
			}
		}
	}

	return totalError;
}
double InverseKinematicJacobian::calculateSpeeds(
		KinematicTree const& tree
		, MotorValuesMap& o_values
		, TasksContainer const& tasks
		, Constraints const& constraints
		, const TaskDefaultPosition* idleTask
	) const
{
	double totalError = 0;
	uint motorCnt = tree.getMotorCnt();

	arma::colvec motorSpeedsVec = arma::zeros(motorCnt);
	arma::colvec motorValuesVec = arma::zeros(motorCnt);

	std::map<NodeID, KinematicNode*> const& nodes = tree.getNodes();

	for (std::pair<NodeID, KinematicNode*> const& node : nodes) {
		if (node.second->isServo())
		{
			kinematics::Motor2IntMap const& motor2Int = node.second->getMotor2IntMap();
			MotorValuesMap const& values = node.second->getValues();
			MotorValuesMap const& valueDerivatives = node.second->getValueDerivatives();

			for (std::pair<MotorID, double> const& value : values) {
				motorValuesVec(motor2Int.at(value.first)) = value.second;
			}
			for (std::pair<MotorID, double> const& value : valueDerivatives) {
				motorSpeedsVec(motor2Int.at(value.first)) = value.second;
			}
		}
	}

	arma::colvec jointDiffConstraintError = arma::zeros(motorCnt);
	for (const Constraint* constraint : constraints) {
		jointDiffConstraintError += constraint->getAngleErrorForConstraint(tree, motorValuesVec);
	}

	arma::colvec summedJointSpeedDiffs = arma::zeros(motorCnt);
	arma::mat nullspaceEyeMat = arma::eye(motorCnt, motorCnt);
	arma::mat nullspaceMat = nullspaceEyeMat - jointDiffConstraintError * jointDiffConstraintError.t();

	arma::mat bigJacobian;
	for (std::pair<uint, std::vector<const Task*>> const& group : tasks) {
		std::vector<const Task*> const& _tasks = group.second;

		if (_tasks.size() > 0) {
			arma::mat jacobianRAW;
			arma::mat jacobian = getJacobianForTasks(tree, _tasks, jacobianRAW, false);

			const arma::mat pseudoInverseJacobian = buildPseudoInverse(jacobian, m_speedEpsilon);

			// how much "error" (mother function)
			arma::colvec speedTarget = getSpeedTargetForTasks(tree, _tasks);

			// how fast does the target move
			arma::colvec speedVec = jacobian * motorSpeedsVec;


			// the actual error
			arma::colvec speedError = speedTarget - speedVec;

			const arma::colvec jointDiffs = nullspaceMat * pseudoInverseJacobian * speedError;

			summedJointSpeedDiffs += jointDiffs;

			bigJacobian = arma::join_cols(bigJacobian, jacobianRAW);
//			nullspaceMat += dofMat * (buildPseudoInverse(jacobianRAW, m_nullspaceEpsilon) * jacobianRAW);
			nullspaceMat = nullspaceEyeMat - buildPseudoInverse(bigJacobian, m_nullspaceEpsilon) * bigJacobian;
			totalError += arma::dot(speedError, speedError);

//			printf("level %d\n", group.first);
//			std::cout.precision(3);
//			std::cout << std::fixed << std::setw(7);
//			jacobian.raw_print(std::cout, "jacobian"); printf("\n");
//			jacobianDOF.raw_print(std::cout, "jacobianDOF"); printf("\n");
//			pseudoInverseJacobian.raw_print(std::cout, "pseudoInverseJacobianDOF"); printf("\n");
//			buildPseudoInverse(jacobian, m_speedEpsilon).raw_print(std::cout, "pseudoInverseJacobian"); printf("\n");
//			jointDiffs.t().raw_print(std::cout, "jointDiffs"); printf("\n");
//			summedJointSpeedDiffs.t().raw_print(std::cout, "summedJointSpeedDiffs"); printf("\n");
//			speedError.t().raw_print(std::cout, "speedError"); printf("\n");
//			std::cout << arma::norm(speedError, 2) << std::endl;
//			printf("\n");
		}
	}

	if (nullptr != idleTask) {
		arma::mat helper = arma::mat(nullspaceEyeMat - nullspaceMat);
		arma::colvec errorVec = idleTask->getErrors(tree);
		summedJointSpeedDiffs += (helper * errorVec) * idleTask->getSpeed();
	}

	summedJointSpeedDiffs += motorSpeedsVec;

	for (std::pair<NodeID, KinematicNode*> const& node : nodes) {
		if (node.second->isServo())
		{
			kinematics::Int2MotorMap const& int2MotorMap = node.second->getInt2MotorMap();
			kinematics::MotorIDs const& motors = node.second->getMotors();
			MotorValuesMap newValues;

			for (kinematics::Int2Motor const& i2m : int2MotorMap) {
				newValues[i2m.second] = summedJointSpeedDiffs(i2m.first);
			}

			/* export */
			for (MotorID const& motor : motors) {
				o_values[motor] = newValues[motor];
			}
		}
	}

	return totalError;
}