function [ link_set, R_joints, R_links, link_set_local, link_vectors_in_world, links_in_world, link_end_set, link_end_set_with_base] = planar_robot_arm_links( link_vectors, joint_angles)
% Initialize the number of links
n = length( link_vectors) ;
% Initialize cell arrays for outputs
R_joints = cell( n, 1 ) ;
R_links = cell( n, 1 ) ;
link_set_local = cell( n, 1 ) ;
link_vectors_in_world = cell( n, 1 ) ;
links_in_world = cell( n, 1 ) ;
link_end_set = cell( n, 1 ) ;
% First step: Generate rotation matrices for the joints
for i = 1 : n
R_joints{ i} = planar_rotation_set( joint_angles( i) ) ;
end
% Second step: Generate cumulative product of joint rotation matrices
R_links{ 1 } = R_joints{ 1 } ; % The first link's orientation is just its rotation
for i = 2:n
R_links{i} = R_links{i-1} * R_joints{i}; % Cumulative product
end
% Third step: Generate local link endpoints
for i = 1:n
link_set_local{i} = [zeros(2, 1), link_vectors{i}]; % [0; 0] and link vector
end
% Fourth step: Rotate link vectors to world coordinates
for i = 1:n
link_vectors_in_world{i} = R_links{i} * link_vectors{i}; % Rotate link vectors
end
% Fifth step: Calculate the world positions of the links
for i = 1:n
if i == 1
links_in_world{i} = link_set_local{i}; % First link
else
% Previous link' s end position
prev_end_pos = link_end_set{ i- 1 } ( :, end) ;
links_in_world{ i} = prev_end_pos + link_vectors_in_world{ i} ; % Translate by previous end position
end
end
% Sixth step: Cumulative sum of link vectors to get endpoints
link_end_set{ 1 } = link_vectors_in_world{ 1 } ; % First link endpoint
for i = 2 : n
link_end_set{ i} = link_end_set{ i- 1 } + link_vectors_in_world{ i} ; % Cumulative sum
end
% Seventh step: Add the base point ( origin) to link_end_set
link_end_set_with_base = cell( n, 1 ) ;
link_end_set_with_base{ 1 } = [ zeros( 2 , 1 ) , link_end_set{ 1 } ] ; % Origin to first endpoint
for i = 2 : n
link_end_set_with_base{ i} = [ link_end_set_with_base{ i- 1 } ( :, end) , link_end_set{ i} ] ; % Append each endpoint
end
% Eighth step: Generate the final link set with the start and endpoints
link_set = cell( n, 1 ) ;
for i = 1 : n
link_set{ i} = links_in_world{ i} ; % Combine the basepoint and endpoints
end
end
link_vectors = { [ 1 ; 0 ] , [ 1 ; 0 ] } ;
joint_angles = [ pi/ 4 ; - pi/ 2 ] ;
link_set = planar_robot_arm_links( link_vectors, joint_angles) ;
disp( link_set{ : } ) ;
ZnVuY3Rpb24gW2xpbmtfc2V0LCBSX2pvaW50cywgUl9saW5rcywgbGlua19zZXRfbG9jYWwsIGxpbmtfdmVjdG9yc19pbl93b3JsZCwgbGlua3NfaW5fd29ybGQsIGxpbmtfZW5kX3NldCwgbGlua19lbmRfc2V0X3dpdGhfYmFzZV0gPSBwbGFuYXJfcm9ib3RfYXJtX2xpbmtzKGxpbmtfdmVjdG9ycywgam9pbnRfYW5nbGVzKQogICAgJSBJbml0aWFsaXplIHRoZSBudW1iZXIgb2YgbGlua3MKICAgIG4gPSBsZW5ndGgobGlua192ZWN0b3JzKTsKICAgIAogICAgJSBJbml0aWFsaXplIGNlbGwgYXJyYXlzIGZvciBvdXRwdXRzCiAgICBSX2pvaW50cyA9IGNlbGwobiwgMSk7CiAgICBSX2xpbmtzID0gY2VsbChuLCAxKTsKICAgIGxpbmtfc2V0X2xvY2FsID0gY2VsbChuLCAxKTsKICAgIGxpbmtfdmVjdG9yc19pbl93b3JsZCA9IGNlbGwobiwgMSk7CiAgICBsaW5rc19pbl93b3JsZCA9IGNlbGwobiwgMSk7CiAgICBsaW5rX2VuZF9zZXQgPSBjZWxsKG4sIDEpOwogICAgCiAgICAlIEZpcnN0IHN0ZXA6IEdlbmVyYXRlIHJvdGF0aW9uIG1hdHJpY2VzIGZvciB0aGUgam9pbnRzCiAgICBmb3IgaSA9IDE6bgogICAgICAgIFJfam9pbnRze2l9ID0gcGxhbmFyX3JvdGF0aW9uX3NldChqb2ludF9hbmdsZXMoaSkpOwogICAgZW5kCiAgICAKICAgICUgU2Vjb25kIHN0ZXA6IEdlbmVyYXRlIGN1bXVsYXRpdmUgcHJvZHVjdCBvZiBqb2ludCByb3RhdGlvbiBtYXRyaWNlcwogICAgUl9saW5rc3sxfSA9IFJfam9pbnRzezF9OyAlIFRoZSBmaXJzdCBsaW5rJ3Mgb3JpZW50YXRpb24gaXMganVzdCBpdHMgcm90YXRpb24KICAgIGZvciBpID0gMjpuCiAgICAgICAgUl9saW5rc3tpfSA9IFJfbGlua3N7aS0xfSAqIFJfam9pbnRze2l9OyAlIEN1bXVsYXRpdmUgcHJvZHVjdAogICAgZW5kCiAgICAKICAgICUgVGhpcmQgc3RlcDogR2VuZXJhdGUgbG9jYWwgbGluayBlbmRwb2ludHMKICAgIGZvciBpID0gMTpuCiAgICAgICAgbGlua19zZXRfbG9jYWx7aX0gPSBbemVyb3MoMiwgMSksIGxpbmtfdmVjdG9yc3tpfV07ICUgWzA7IDBdIGFuZCBsaW5rIHZlY3RvcgogICAgZW5kCiAgICAKICAgICUgRm91cnRoIHN0ZXA6IFJvdGF0ZSBsaW5rIHZlY3RvcnMgdG8gd29ybGQgY29vcmRpbmF0ZXMKICAgIGZvciBpID0gMTpuCiAgICAgICAgbGlua192ZWN0b3JzX2luX3dvcmxke2l9ID0gUl9saW5rc3tpfSAqIGxpbmtfdmVjdG9yc3tpfTsgJSBSb3RhdGUgbGluayB2ZWN0b3JzCiAgICBlbmQKICAgIAogICAgJSBGaWZ0aCBzdGVwOiBDYWxjdWxhdGUgdGhlIHdvcmxkIHBvc2l0aW9ucyBvZiB0aGUgbGlua3MKICAgIGZvciBpID0gMTpuCiAgICAgICAgaWYgaSA9PSAxCiAgICAgICAgICAgIGxpbmtzX2luX3dvcmxke2l9ID0gbGlua19zZXRfbG9jYWx7aX07ICUgRmlyc3QgbGluawogICAgICAgIGVsc2UKICAgICAgICAgICAgJSBQcmV2aW91cyBsaW5rJ3MgZW5kIHBvc2l0aW9uCiAgICAgICAgICAgIHByZXZfZW5kX3BvcyA9IGxpbmtfZW5kX3NldHtpLTF9KDosIGVuZCk7CiAgICAgICAgICAgIGxpbmtzX2luX3dvcmxke2l9ID0gcHJldl9lbmRfcG9zICsgbGlua192ZWN0b3JzX2luX3dvcmxke2l9OyAlIFRyYW5zbGF0ZSBieSBwcmV2aW91cyBlbmQgcG9zaXRpb24KICAgICAgICBlbmQKICAgIGVuZAogICAgCiAgICAlIFNpeHRoIHN0ZXA6IEN1bXVsYXRpdmUgc3VtIG9mIGxpbmsgdmVjdG9ycyB0byBnZXQgZW5kcG9pbnRzCiAgICBsaW5rX2VuZF9zZXR7MX0gPSBsaW5rX3ZlY3RvcnNfaW5fd29ybGR7MX07ICUgRmlyc3QgbGluayBlbmRwb2ludAogICAgZm9yIGkgPSAyOm4KICAgICAgICBsaW5rX2VuZF9zZXR7aX0gPSBsaW5rX2VuZF9zZXR7aS0xfSArIGxpbmtfdmVjdG9yc19pbl93b3JsZHtpfTsgJSBDdW11bGF0aXZlIHN1bQogICAgZW5kCiAgICAKICAgICUgU2V2ZW50aCBzdGVwOiBBZGQgdGhlIGJhc2UgcG9pbnQgKG9yaWdpbikgdG8gbGlua19lbmRfc2V0CiAgICBsaW5rX2VuZF9zZXRfd2l0aF9iYXNlID0gY2VsbChuLCAxKTsKICAgIGxpbmtfZW5kX3NldF93aXRoX2Jhc2V7MX0gPSBbemVyb3MoMiwgMSksIGxpbmtfZW5kX3NldHsxfV07ICUgT3JpZ2luIHRvIGZpcnN0IGVuZHBvaW50CiAgICBmb3IgaSA9IDI6bgogICAgICAgIGxpbmtfZW5kX3NldF93aXRoX2Jhc2V7aX0gPSBbbGlua19lbmRfc2V0X3dpdGhfYmFzZXtpLTF9KDosIGVuZCksIGxpbmtfZW5kX3NldHtpfV07ICUgQXBwZW5kIGVhY2ggZW5kcG9pbnQKICAgIGVuZAogICAgCiAgICAlIEVpZ2h0aCBzdGVwOiBHZW5lcmF0ZSB0aGUgZmluYWwgbGluayBzZXQgd2l0aCB0aGUgc3RhcnQgYW5kIGVuZHBvaW50cwogICAgbGlua19zZXQgPSBjZWxsKG4sIDEpOwogICAgZm9yIGkgPSAxOm4KICAgICAgICBsaW5rX3NldHtpfSA9IGxpbmtzX2luX3dvcmxke2l9OyAlIENvbWJpbmUgdGhlIGJhc2Vwb2ludCBhbmQgZW5kcG9pbnRzCiAgICBlbmQKZW5kCmxpbmtfdmVjdG9ycyA9IHtbMTsgMF0sIFsxOyAwXX07CmpvaW50X2FuZ2xlcyA9IFtwaS80OyAtcGkvMl07Cmxpbmtfc2V0ID0gcGxhbmFyX3JvYm90X2FybV9saW5rcyhsaW5rX3ZlY3RvcnMsIGpvaW50X2FuZ2xlcyk7CmRpc3AobGlua19zZXR7On0pOwo=