Show free variables in solution(s) instead of zeros

35 views (last 30 days)
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

Accepted Answer

Paul
Paul on 19 Oct 2021
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

More Answers (1)

the cyclist
the cyclist on 18 Oct 2021
Edited: the cyclist on 18 Oct 2021
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 Comments
Connor LeClaire
Connor LeClaire on 18 Oct 2021
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 on 18 Oct 2021
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.

Sign in to comment.

Categories

Find more on Linear Programming and Mixed-Integer Linear Programming in Help Center and File Exchange

Products


Release

R2021a

Community Treasure Hunt

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

Start Hunting!