% TOGAC28_AMBF_Matlab2AMBFControl_tests.m % This file will run basic control inputs on the galen robot for the ambf % simulation. This contects matlab with ambf using the galen_interface % class. Ensure ROS is running by running roscore in a terminal and then % open the ambf model in a separate terminal % Instructions on how to install the AMBF application and how to use the % robot with ambf are found in: % TOGAC25_AMBF_IN_AMBFforGalen.pdf % Instructions for using matalb with ambf are found in: % TOGAC29_AMBF_IN_ConnectMatlab2AMBF.pdf % 3 main control types are avaliable. Chirp, Linear Trajectory, Sine, and Step inputs can be % used. After the control loop sections, you can plot rv and cv, the output % results of the 3 carraige joints on the galen robot. The control here is % currently designed only to output the desired velocity for the 3 carriage % joints, lumping the galen robot as a single mass. The carriage joints should have % identical response. % Created by Brevin Banks % Modified March 29 2023 galen_robot = galen_interface(); % initiate the robot interface %% center_galen_robot(galen_robot) % Center the robot at 0.21m if necessary % the above command only works upon the AMBF environment creation. For some % unknown reason the AMBF simulation struggles with switching between % velocity and position control. To use this function again, restart the % AMBF application. It may also be necessary to turn of gravity to keep the % robot in the center after running the command. %% Assign Chirp Input galen_robot.set_control_type('Velocity'); % setup velocity control % Initialize the error for iteration error = 1; %Generate Chirp sim_time_window = (0:1/200:50); % 50 second window with 200Hz sampling f0 = 0.001; % Starting frequency 1000 Hz f1 = 1; % ending frequency 1 Hz Fs = 1/mean(diff(sim_time_window)); x = chirp(sim_time_window,f0,sim_time_window(end),f1,'linear',-90)*.05; % generate chirp magnitude 0.05 % Initialize iteratior count, cv - output data of robot, rv - desired input % for robot i=1; cv = []; rv = []; % Initialize a vector to capture the change in time time_vec = []; r = rosrate(200);% rate control object will hold the loop at 200Hz current_sim_time =0; % initialize time at 0 reset(r) % clear any previously stored rate statistics while(current_sim_time<51) % for ~50 seconds run the loop %Grab the current sampling point in time relative to total time current_sim_time = r.TotalElapsedTime; % find the closest point to time in the chirp function [ d, ix ] = min( abs( sim_time_window-current_sim_time) ); if ix <2 ix =2; % can't interpolate starter position without more than 2 samples elseif ix>10000 ix = 10000; % can't interpolate end position without if more than 10000 samples end %interpolate to get the value of the chirp function Cinput = x(ix-1)+(current_sim_time-sim_time_window(ix-1))*(((x(ix+1) - x(ix-1))/(sim_time_window(ix+1) - sim_time_window(ix-1)))); if current_sim_time>50 % can't interpolate at the end conditions. Just assign 0 Cinput = 0; end % Assign the desired velocity for 3 carriage joints ref_velocity = single([Cinput,Cinput,Cinput,0,0,0]); % Move the galen robot galen_robot.move_galen(ref_velocity); % Retrieve the current robot joints current_velocity = galen_robot.get_current_joints(); % Find the error between desired and output error = norm(current_velocity-ref_velocity); %Store input and output history cv(1:3,i) = current_velocity(1:3); rv(1:3,i) = ref_velocity(1:3); % Increase iterator and record current time i = i+1; time_vec(i) = current_sim_time; % Hold the loop if the sampling time is under 200Hz waitfor(r); end % Output the resulting total loop time and quality of the sampling rate stats = statistics(r) disp(r) time_elapsed = r.TotalElapsedTime; % Plot the shape of the Velocity input response figure(2) plot(sim_time_window,x) title('Chirp Input on all 3 carriage joints') xlabel('Time (s)') ylabel('Velocity input (m/s)') %% Assign Trajectory Input galen_robot.set_control_type('Velocity'); % setup velocity control % Trajectory Input current_velocity = galen_robot.get_current_joints(); % Create a trajectory rather than applying a specifc reference ref_velocity = [.05,.05,.05,0,0,0]'; % desired velocity des_traj = lin_trajectory(current_velocity,ref_velocity); % Initialize iteratior count, cv - output data of robot, rv - desired input % for robot i=1; cv = []; rv = []; % Initialize a vector to capture the change in time time_vec = []; r = rosrate(200);% rate control object will hold the loop at 200Hz current_sim_time = 0; % initialize time at 0 reset(r) % clear any previously stored rate statistics for k = 1:length(des_traj) % Move the galen robot according to the desired trajectory galen_robot.move_galen(des_traj(:,k)); % Store the the current velocity cv(1:3,i) = current_velocity(1:3); % Grab the current velocity current_velocity = galen_robot.get_current_joints(); % Find the error between desired and output error = norm(current_velocity-ref_velocity); %Store input velocity history rv(1:3,i) = ref_velocity(1:3); % Increase iterator and record current time i = i+1; time_vec(i) = current_sim_time; % Hold the loop if the sampling time is under 200Hz waitfor(r); end % Output the resulting total loop time and quality of the sampling rate stats = statistics(r) disp(r) time_elapsed = r.TotalElapsedTime; %% Assign A Step Input galen_robot.set_control_type('Velocity'); % setup velocity control % Step Input current_velocity = galen_robot.get_current_joints(); % Initialize iteratior count, cv - output data of robot, rv - desired input % for robot i=1; cv = []; rv = []; % Initialize a vector to capture the change in time time_vec = []; ref_velocity = single([.05,.05,.05,0,0,0]'); % Step input reference 0.05 magnitude r = rosrate(200);% rate control object will hold the loop at 200Hz current_sim_time = 0; % initialize time at 0 reset(r) % clear any previously stored rate statistics % Initialize iteratior count, cv - output data of robot, rv - desired input % for robot i=1; cv = []; rv = []; % Initialize a vector to capture the change in time time_vec = []; ref_velocity = single([.05,.05,.05,0,0,0]'); % Step input reference 0.05 magnitude r = rosrate(200);% rate control object will hold the loop at 200Hz current_sim_time = 0; % initialize time at 0 reset(r) % clear any previously stored rate statistics while(current_sim_time<51) %Grab the current sampling point in time relative to total time current_sim_time = r.TotalElapsedTime; % Move the galen robot galen_robot.move_galen(ref_velocity); % Retrieve the current robot joints current_velocity = galen_robot.get_current_joints(); % Find the error between desired and output error = norm(current_velocity-ref_velocity); %Store input and output history cv(1:3,i) = current_velocity(1:3); rv(1:3,i) = ref_velocity(1:3); % Increase iterator and record current time i = i+1; time_vec(i) = current_sim_time; % Hold the loop if the sampling time is under 200Hz waitfor(r); end % Output the resulting total loop time and quality of the sampling rate stats = statistics(r) disp(r) time_elapsed = r.TotalElapsedTime; %% Apply Sine input on the robot galen_robot.set_control_type('Velocity'); % setup velocity control t = 0:pi/36:2*pi;%discretized input to have a period over 2pi separated by 36 parts timer = 1;% Initialize starter time variable r = rosrate(200); current_sim_time =0; reset(r) while(current_sim_time<51) if timer>length(t)-1 timer = 1; end upsign = 0.01*sin(t(timer)); timer = 1 + timer; ref_velocity = single([upsign,upsign,upsign,0,0,0]'); % Move the galen robot galen_robot.move_galen(ref_velocity); % Retrieve the current robot joints current_velocity = galen_robot.get_current_joints(); % Find the error between desired and output error = norm(current_velocity-ref_velocity); %Store input and output history cv(1:3,i) = current_velocity(1:3); rv(1:3,i) = ref_velocity(1:3); % Increase iterator and record current time i = i+1; time_vec(i) = current_sim_time; % Hold the loop if the sampling time is under 200Hz waitfor(r); end % Output the resulting total loop time and quality of the sampling rate stats = statistics(r) disp(r) time_elapsed = r.TotalElapsedTime; %% % Plot the current values store in cv and rv. This should theoretically be % the 3 different carriage joint values, and they should all be nearly % identical if not for noise between sampling times and robot model % innacuracies t = 1:length(cv); % not true seconds, Just a count for every existing sample. % Update t above to be the true total loop time for the collected sample to % get an accurate figure for the repsonse time close all figure(1) subplot(3,1,1) hold on plot(t,rv(1,:)) plot(t,cv(1,:)) legend('Car1 Vref','Car1 Vout') subplot(3,1,2) hold on plot(t,rv(2,:)) plot(t,cv(2,:)) legend('Car2 Vref','Car2 Vout') subplot(3,1,3) hold on plot(t,rv(3,:)) plot(t,cv(3,:)) legend('Car3 Vref','Car3 Vout') %% % Generate a trajectory from a given initial joint angle set to the goal % joint angle set. The trajectory is a straight line between the 2 points % in joint space. This function takes the two joint sets and creates the % joint trajectory by parameterizing a line between the two points and % discreteizes the distance between them by steps of 1/200. % Input: % q_init - a 6x1 vector of desired joint states % q_goal - a 6x1 vector of desired joint states % Output: % traj - a vector of joint values to give the robot for each time step 1/200 function traj = lin_trajectory(q_init,q_goal) T = 1/200; q_goal = reshape(q_goal,size(q_init)); lambda = round(norm(q_goal-q_init)/(2*T)); if lambda < 10 lambda = 10; end if lambda > 200 lambda = 200; end m = (q_goal - q_init)./lambda; traj = zeros(length(q_init),lambda); for t=1:lambda traj(:,t) = m.*t + q_init; end traj = [q_init, traj, q_goal]; end % Center the robot % This command only works upon the AMBF environment creation. For some % unknown reason the AMBF simulation struggles with switching between % velocity and position control. To use this function again, restart the % AMBF application. It may also be necessary to turn of gravity to keep the % robot in the center after running the command. % Input: % galen_robot - the robot object from galen_interface() function center_galen_robot(galen_robot) galen_robot.set_control_type('Position'); % set up position control error = 1; % initialize error variable steadier = 0; % observe if the change in position is small const_err = 0; % Observe if the error is not changing error_prev = 0; % capture error history start_pose = single([0.21, 0.21, 0.21, 0 ,0 ,0]); % home position current_pose = galen_robot.get_current_joints(); d_pose = 1; while(error>0.07 || steadier< 5) % Check that the robot has achieved the desired pose prev_pose = current_pose; galen_robot.move_galen(start_pose); pause(1/200); % keep sampling frequency below 200Hz current_pose = galen_robot.get_current_joints(); error = norm(start_pose(1:3) - current_pose(1:3)); %calculate error d_pose = mean(current_pose(1:3)-prev_pose(1:3)); % check that the pose is changing if abs(d_pose) < 0.0001 % if the robot stops moving over time, iterate to kill the process steadier = steadier+1; else steadier = 0; end if abs(mean(error-error_prev))<0.001% if the error stops changin over time, iterate to kill the process const_err = const_err+1; else const_err = 0; end if const_err>10 break; end error_prev = error; end end