Show free variables in solution(s) instead of zeros

조회 수: 29 (최근 30일)
Connor LeClaire
Connor LeClaire 2021년 10월 18일
답변: Paul 2021년 10월 19일
When using the solve function for an equation, there are some solutions that need only one or two variables at specific values, when others can be freely chosen.
Is it possible to have matlab replace the solution answer with, for example, x instead of a number, when a variable can be chosen freely?
In my code, the equation to be solved is: -12340.0*cos(theta_3)*sin(theta_5)*(197.0*sin(theta_2 + theta_3) + 290.0*cos(theta_2)) == 0
theta_1, theta_4, and theta_6 (all variables used in the calculation of the equation) are not included (which is expected) and thus can be freely chosen without affecting the actual solution however the solution matrix looks like:
[0, 0, 90.0, 0, 0, 0]
[0, -55.81, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0]
[0, 124.2, 0, 0, 0, 0]
I am hoping to replace the zeros of free variables with an X or - or some character to denote that the variables do not have to be at a specific value.
My code is given below:
clear all;
clc;
%% DH Parameters
a = sym([0 174.0 0 0 0 0]');
d = sym([116.3 0 0 118.2 0 130]');
alpha = sym([pi/2 0 pi/2 -pi/2 pi/2 0]');
syms theta_1 theta_2 theta_3 theta_4 theta_5 theta_6 real;
theta = [theta_1 theta_2 theta_3 theta_4 theta_5 theta_6]';
%% Calculate Transforms
T_0_1 = robot_transform(a(1), alpha(1), d(1), theta(1));
T_1_2 = robot_transform(a(2), alpha(2), d(2), theta(2));
T_2_3 = robot_transform(a(3), alpha(3), d(3), theta(3));
T_3_4 = robot_transform(a(4), alpha(4), d(4), theta(4));
T_4_5 = robot_transform(a(5), alpha(5), d(5), theta(5));
T_5_6 = robot_transform(a(6), alpha(6), d(6), theta(6));
T_0_6 = T_0_1 * T_1_2 * T_2_3 * T_3_4 * T_4_5 * T_5_6;
%% Calculate Jacobian Components
Z0 = [0 0 1]';
O0 = [0 0 0]';
inputT = T_0_1;
Z1 = inputT(1:3,3);
O1 = inputT(1:3,4);
inputT = inputT*T_1_2;
Z2 = inputT(1:3,3);
O2 = inputT(1:3,4);
inputT = inputT*T_2_3;
Z3 = inputT(1:3,3);
O3 = inputT(1:3,4);
inputT = inputT*T_3_4;
Z4 = inputT(1:3,3);
O4 = inputT(1:3,4);
inputT = inputT*T_4_5;
Z5 = inputT(1:3,3);
O5 = inputT(1:3,4);
inputT = inputT*T_5_6;
Z6 = inputT(1:3,3);
O6 = inputT(1:3,4);
%% Generating Jacobian
jacobianT = [cross(Z0,(O6-O0)) cross(Z1,(O6-O1)) cross(Z2,(O6-O2)) cross(Z3,(O6-O3)) cross(Z4,(O6-O4)) cross(Z5,(O6-O5))];
jacobianW = [Z0 Z1 Z2 Z3 Z4 Z5];
jacob = [jacobianT; jacobianW];
disp('Calculating determinate...');
determinant = vpa(simplify(det(jacob)),4)
%% Calculating Solutions
disp('Calculating solutions...');
sol = getSolution(determinant, [theta_1 theta_2 theta_3 theta_4 theta_5 theta_6]);
disp('Solutions complete');
disp(" ");
disp(sol);
%% Verifying solutions
for i=1:size(sol,1)
if vpa(subs(determinant,[theta_2,theta_3,theta_5],sol(i,[2,3,5])))==0
disp("Solution " + num2str(i) + " is verified");
else
disp("Solution " + num2str(i) + " is false");
end
end
%% Function getSolution
function [M] = getSolution(eqn,vars)
%This function solves an equation (eqn) for the variables (vars)
%The output is modified to return as a matrix instead of a struct
%eqn should only be one side of the equation (not == 0)
solution = solve(eqn==0, vars ,'Real',true);
M = vpa(rad2deg([solution.theta_1,solution.theta_2,solution.theta_3,solution.theta_4,solution.theta_5,solution.theta_6]),4);
end
%% Function robotTransform
function T = robot_transform(a, alpha, d, theta)
%Calculates the transformation matrix
%Using SDH parameters, inputs must be in the order of a-alpha-d-theta
T = [ cos(theta) -sin(theta)*cos(alpha) sin(theta)*sin(alpha) a*cos(theta);
sin(theta) cos(theta)*cos(alpha) -cos(theta)*sin(alpha) a*sin(theta);
0 sin(alpha) cos(alpha) d;
0 0 0 1];
end

채택된 답변

Paul
Paul 2021년 10월 19일
The way to parameterize the solutions returned from solve() is to use the ReturnConditions flag. Here is the code
clear all;
clc;
%% DH Parameters
a = sym([0 174.0 0 0 0 0]');
d = sym([116.3 0 0 118.2 0 130]');
% alpha = sym([pi/2 0 pi/2 -pi/2 pi/2 0]'); % this works, but it might be
% clearer to use
alpha = [sym(pi)/2 0 sym(pi)/2 -sym(pi)/2 sym(pi)/2 0]';
syms theta_1 theta_2 theta_3 theta_4 theta_5 theta_6 real;
theta = [theta_1 theta_2 theta_3 theta_4 theta_5 theta_6]';
%% Calculate Transforms
T_0_1 = robot_transform(a(1), alpha(1), d(1), theta(1));
T_1_2 = robot_transform(a(2), alpha(2), d(2), theta(2));
T_2_3 = robot_transform(a(3), alpha(3), d(3), theta(3));
T_3_4 = robot_transform(a(4), alpha(4), d(4), theta(4));
T_4_5 = robot_transform(a(5), alpha(5), d(5), theta(5));
T_5_6 = robot_transform(a(6), alpha(6), d(6), theta(6));
T_0_6 = T_0_1 * T_1_2 * T_2_3 * T_3_4 * T_4_5 * T_5_6;
%% Calculate Jacobian Components
Z0 = [0 0 1]';
O0 = [0 0 0]';
inputT = T_0_1;
Z1 = inputT(1:3,3);
O1 = inputT(1:3,4);
inputT = inputT*T_1_2;
Z2 = inputT(1:3,3);
O2 = inputT(1:3,4);
inputT = inputT*T_2_3;
Z3 = inputT(1:3,3);
O3 = inputT(1:3,4);
inputT = inputT*T_3_4;
Z4 = inputT(1:3,3);
O4 = inputT(1:3,4);
inputT = inputT*T_4_5;
Z5 = inputT(1:3,3);
O5 = inputT(1:3,4);
inputT = inputT*T_5_6;
Z6 = inputT(1:3,3);
O6 = inputT(1:3,4);
%% Generating Jacobian
jacobianT = [cross(Z0,(O6-O0)) cross(Z1,(O6-O1)) cross(Z2,(O6-O2)) cross(Z3,(O6-O3)) cross(Z4,(O6-O4)) cross(Z5,(O6-O5))];
jacobianW = [Z0 Z1 Z2 Z3 Z4 Z5];
jacob = [jacobianT; jacobianW];
disp('Calculating determinate...');
Calculating determinate...
% let's keep everything symbolic
% determinant = vpa(simplify(det(jacob)),4)
determinant = simplify(det(jacob))
determinant = 
%% Calculating Solutions
disp('Calculating solutions...');
Calculating solutions...
sol = solve(determinant == 0,[theta_1 theta_2 theta_3 theta_4 theta_5 theta_6],'Real',true,'ReturnConditions',true)
sol = struct with fields:
theta_1: [4×1 sym] theta_2: [4×1 sym] theta_3: [4×1 sym] theta_4: [4×1 sym] theta_5: [4×1 sym] theta_6: [4×1 sym] parameters: [k u v w x y z z1 z2 z3 z4] conditions: [4×1 sym]
sol.conditions
ans = 
Now combine all the solutions
solutions = [sol.theta_1 sol.theta_2 sol.theta_3 sol.theta_4 sol.theta_5 sol.theta_6]
solutions = 
Now we have the full solution set parameterized by several parameters that have to satisfy the above conditions, which is that k is an integer and all of the other parameters are real.
%sol = getSolution(determinant, [theta_1 theta_2 theta_3 theta_4 theta_5 theta_6]);
disp('Solutions complete');
Solutions complete
%disp(" ");
%disp(solutions);
%% Verifying solutions
for i=1:size(solutions,1)
% if vpa(subs(determinant,[theta_2,theta_3,theta_5],sol(i,[2,3,5])))==0
assume(sol.conditions(i));
if simplify(subs(determinant,[theta_1,theta_2,theta_3,theta_4,theta_5,theta_6],solutions(i,:))) == 0
disp("Solution " + num2str(i) + " is verified");
else
disp("Solution " + num2str(i) + " is false");
end
end
Solution 1 is false
Solution 2 is verified
Solution 3 is false
Solution 4 is verified
I'm not sure why solution 1 and solution 3 are showing as false. I assume it has something to do with the simplification just not getting al the way down to zero. Maybe could get there with further work. But if we sub in some random values for the parameters, we see that the solutions actually hold:
d = subs(determinant,[theta_1,theta_2,theta_3,theta_4,theta_5,theta_6],solutions(1,:))
d = 
syms z1 z3 k
d = subs(d,[z1 z3 k],[0.1 0.9 3])
d = 
d = vpa(d)
d = 
4.5223738143010938080157939062213e-34
d = subs(determinant,[theta_1,theta_2,theta_3,theta_4,theta_5,theta_6],solutions(3,:))
d = 
d = subs(determinant,[theta_1,theta_2,theta_3,theta_4,theta_5,theta_6],solutions(3,:))
d = 
d = subs(d,[z1 z3 k],[0.1 0.9 3])
d = 
d = vpa(d)
d = 
0.0
%% Function getSolution
function [M] = getSolution(eqn,vars)
%This function solves an equation (eqn) for the variables (vars)
%The output is modified to return as a matrix instead of a struct
%eqn should only be one side of the equation (not == 0)
solution = solve(eqn==0, vars ,'Real',true);
M = vpa(rad2deg([solution.theta_1,solution.theta_2,solution.theta_3,solution.theta_4,solution.theta_5,solution.theta_6]),4);
end
%% Function robotTransform
function T = robot_transform(a, alpha, d, theta)
%Calculates the transformation matrix
%Using SDH parameters, inputs must be in the order of a-alpha-d-theta
T = [ cos(theta) -sin(theta)*cos(alpha) sin(theta)*sin(alpha) a*cos(theta);
sin(theta) cos(theta)*cos(alpha) -cos(theta)*sin(alpha) a*sin(theta);
0 sin(alpha) cos(alpha) d;
0 0 0 1];
end

추가 답변 (1개)

the cyclist
the cyclist 2021년 10월 18일
편집: the cyclist 2021년 10월 18일
A numeric matrix in MATLAB cannot hold an "x". You could change them to NaN:
% Your solution
M = [0, 0, 90.0, 0, 0, 0;
0, -55.81, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0;
0, 124.2, 0, 0, 0, 0];
% Change 0 to NaN
M(M==0) = NaN
M = 4×6
NaN NaN 90.0000 NaN NaN NaN NaN -55.8100 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 124.2000 NaN NaN NaN NaN
If that doesn't work well for you, then you could instead convert M to a cell array (which can hold a mixture of numeric and character data), and convert the zeros to x's.
The best solution for you will depend on what you want to do with this array as a next step.
  댓글 수: 2
Connor LeClaire
Connor LeClaire 2021년 10월 18일
I am hesitant to replace all zero's with NaN as in some solutions a variable may actually have to be zero.
Is there a way to distinguish what variables must be zero and what variables are free?
the cyclist
the cyclist 2021년 10월 18일
Caveat: I don't have much experience with the Symbolic Math Toolbox.
I don't see from the documentation for solve() that you can change the output for "structural" zeros (absent due to lack of term) vs. calculated zeros.
One possibility that might work would be to use the symvar function, which will identify which variables occur in your expression. For example,
symvar(determinant)
will report that theta2, theta3, and theta5 appear. I'm not knowledgeable enough to see exactly how you can modify your solution to take advantage of that info, though.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Linear Programming and Mixed-Integer Linear Programming에 대해 자세히 알아보기

제품


릴리스

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by