Team 26 - Appendix
Bill of Materials:
MATLAB code:
Main code:
clc; clear; format compact; clf; close all;
set(0,'defaultTextInterpreter','latex');
set(0, 'defaultAxesTickLabelInterpreter','latex');
set(0, 'defaultLegendInterpreter','latex');
set(0,'defaultAxesFontSize',18);
set(0, 'DefaultLineLineWidth', 2);
set(groot, 'defaultFigureUnits', 'pixels', 'defaultFigurePosition', [440 278 560 420]);
d = 46.47;
d_dot = 10;
[ta, tb, wa, wb] = mechanism1(d, d_dot);
tb = ta + 75 * pi/180;
wb = wa;
[a, ta, a_dot, wa] = mechanism2(tb, wb);
% Calculating input slider position and velocity
d = linspace(30.25, 111, 100);
pitch = 2; % mm/rev
w_motor = 200 * 2*pi / 60; % rad/s (200 RPM)
d_dot = w_motor * pitch / (2 * pi); % mm/s
tb_bank = zeros(1, length(d));
wb_bank = zeros(1, length(d));
ta_bank = zeros(1, length(d));
wa_bank = zeros(1, length(d));
for i = 1:length(d)
[ta, tb, wa, wb] = mechanism1(d(i), d_dot);
tb = ta + 75 * pi/180;
wb = wa;
[a, ta, a_dot, wa] = mechanism2(tb, wb);
tb_bank(i) = tb;
wb_bank(i) = wb;
ta_bank(i) = ta;
wa_bank(i) = wa;
end
figure
hold on
box on
plot(d - 30, ta_bank, '-r')
plot(d - 30, tb_bank, '-b')
xlabel('Input Slider Actuation, $x$ [mm]')
ylabel('$\theta$ [rad]')
legend('Distal Finger Angle, $\theta_{a}$', 'Proximal Finger Angle, $\theta_{b}$')
legend('location', 'best')
title('Finger Angular Positions vs. Slider Input')
xlim([0, 80])
figure
hold on
box on
plot(d - 30, wa_bank, '-r')
plot(d - 30, wb_bank, '-b')
xlabel('Input Slider Actuation, $x$ [mm]')
ylabel('$\dot{\theta}$ [rad/s]')
legend('Distal Finger Velocity, $\dot{\theta_{a}}$', 'Proximal Finger Velocity, $\dot{\theta_{b}}$')
legend('location', 'best')
title('Finger Angular Velocities vs. Slider Input')
xlim([0, 80])
Function for mechanism #1:
function [ta, tb, wa, wb] = mechanism1(d, d_dot, is_symbolic)
if nargin < 3
is_symbolic = false;
end
if is_symbolic == true
syms a b c d ta tb tc td d_dot wa wb;
% Position
eqn1 = a*cos(ta) + c + b*cos(tb) == 0;
eqn2 = a*sin(ta) - d + b*sin(tb) == 0;
eqns = [eqn1, eqn2];
vars = [ta, tb];
[solv, solu] = solve(eqns, vars);
ta = simplify(solv(2));
tb = simplify(solu(2));
% Velocity
eqn1 = -a*wa*sin(ta) - b*wb*sin(tb) == 0;
eqn2 = a*wa*cos(ta) - d_dot + b*wb*cos(tb) == 0;
eqns = [eqn1, eqn2];
vars = [wa, wb];
[solv, solu] = solve(eqns, vars);
wa = simplify(solv);
wb = simplify(solu);
else
syms ta tb wa wb;
% Position
a = 54.45;
b = 80;
c = 1.72;
eqn1 = a*cos(ta) + c + b*cos(tb) == 0;
eqn2 = a*sin(ta) - d + b*sin(tb) == 0;
eqns = [eqn1, eqn2];
vars = [ta, tb];
[solv, solu] = solve(eqns, vars);
ta_set = eval(solv);
tb_set = eval(solu);
ta = ta_set(2);
tb = tb_set(2);
% Velocity
eqn1 = -a*wa*sin(ta) - b*wb*sin(tb) == 0;
eqn2 = a*wa*cos(ta) - d_dot + b*wb*cos(tb) == 0;
eqns = [eqn1, eqn2];
vars = [wa, wb];
[solv, solu] = solve(eqns, vars);
wa = eval(solv);
wb = eval(solu);
end
end
Function for mechanism #2:
function [a, ta, a_dot, wa] = mechanism2(tb, wb, is_symbolic)
if nargin < 3
is_symbolic = false;
end
if is_symbolic == true
syms a b c d ta tb tc td a_dot wa wb wc wd;
% Position
eqn1 = a*cos(ta) - b*cos(tb) + c*cos(tc) + d*sin(ta) == 0;
eqn2 = a*sin(ta) - b*sin(tb) + c*sin(tc) - d*cos(ta) == 0;
eqns = [eqn1, eqn2];
vars = [a, ta];
[solv, solu] = solve(eqns, vars);
a = simplify(solv(1));
b = simplify(solu(1));
% Velocity
eqn1 = a_dot * cos(ta) - a * wa * sin(ta) + b * wb * sin(tb) + d * wa * cos(ta);
eqn2 = a_dot * sin(ta) + a * wa * cos(ta) - b * wb * cos(tb) + d * wa * sin(ta);
eqns = [eqn1, eqn2];
vars = [a_dot, wa];
[solv, solu] = solve(eqns, vars);
a_dot = simplify(solv);
wa = simplify(solu);
else
syms a ta a_dot wa;
% Position
b = 120;
c = 90;
d = 26.42;
tc = 3*pi/4;
eqn1 = a*cos(ta) - b*cos(tb) + c*cos(tc) + d*sin(ta) == 0;
eqn2 = a*sin(ta) - b*sin(tb) + c*sin(tc) - d*cos(ta) == 0;
eqns = [eqn1, eqn2];
vars = [a, ta];
[solv, solu] = solve(eqns, vars);
a_set = eval(solv);
ta_set = eval(solu);
a = a_set(1);
ta = ta_set(1);
% Velocity
eqn1 = a_dot * cos(ta) - a * wa * sin(ta) + b * wb * sin(tb) + d * wa * cos(ta);
eqn2 = a_dot * sin(ta) + a * wa * cos(ta) - b * wb * cos(tb) + d * wa * sin(ta);
eqns = [eqn1, eqn2];
vars = [a_dot, wa];
[solv, solu] = solve(eqns, vars);
a_dot = eval(solv);
wa = eval(solu);
end
end
Arduino code:
#include <Arduino.h>
#include <Stepper.h>
// Define FSR pin:
#define fsrpin1 A0
#define fsrpin2 A1
#define potpin1 A2
#define potpin2 A3
const int dirPin = 2;
const int stepPin = 3;
int potMax {660};
int potMin {0};
int LEDState=0;
int LEDPinBlue=7;
int LEDPinRed=8;
int buttonPin=12;
int buttonNew;
int buttonOld=1;
int dt=20;
// Define number of steps per revolution:
const int stepsPerRevolution = 200;
// Initialize the stepper library on pins 8 through 11:
Stepper myStepper = Stepper(stepsPerRevolution, 3, 4, 5, 6);
//-------------------------------------------------------------
// Settings
int target_force {12}; // N
float conversion_factor {0.02}; // N/bit(/8)
int prop_gain {1};
float tolerance_window {0.3};
float pot_tol {0.8};
int min_step_size {5};
int max_step_size {200};
int speedMax {250};
bool activeFeedback {0};
signed long currentRotation {0};
bool dir {};
//-------------------------------------------------------------
// Function prototypes
bool setControlMode ();
int adjustSpeed ();
float readForce ();
int calculateStep (float current_force);
int potentiometerControl ();
int adjustDirection ();
void stepMotor (int steps);
//-------------------------------------------------------------
void setup () {
pinMode(LEDPinBlue, OUTPUT);
pinMode(LEDPinRed, OUTPUT);
pinMode(buttonPin, INPUT);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
Serial.begin(9600);
}
void loop () {
// - Check button to determine whether should be using remote control or autonomous
bool activeFeedback {setControlMode()};
// * If closed-loop control should be active
if (activeFeedback == true) {
// - read in force
float current_force {readForce()};
// - use it to determine update in motor step
int step_size {calculateStep(current_force)};
// - execute update
stepMotor(step_size);
// * If remote control should be active
} else {
// - determine direction from user control
signed int direction {adjustDirection()};
// - execute update
stepMotor(direction * 10);
}
delay(10);
}
//-------------------------------------------------------------
void stepMotor(int steps)
{
Serial.println(steps);
if (steps > 0) {
digitalWrite(dirPin, HIGH);
} else if (steps < 0) {
digitalWrite(dirPin, LOW);
}
if (steps != 0) {
for(int x = 0; x < stepsPerRevolution; x++)
{
digitalWrite(stepPin, LOW);
delayMicroseconds(2000);
digitalWrite(stepPin, HIGH);
delayMicroseconds(2000);
}
}
}
int adjustSpeed () {
int potVal = analogRead(potpin2);
int speed = (map(potVal, potMin, potMax, 1, speedMax));
return speed;
}
int adjustDirection () {
int potVal = analogRead(potpin2);
int potMed {((potMin + potMax) / 2)};
Serial.println();
if (potVal > potMed && potVal > (1 + pot_tol) * potMed) {
return 1;
} else if ((potVal < potMed && potVal < (1 - pot_tol) * potMed)) {
return -1;
} else {
return 0;
}
}
bool setControlMode ()
{
buttonNew=digitalRead(buttonPin);
if(buttonOld==0 && buttonNew==1){
if (LEDState==0){
digitalWrite(LEDPinBlue,HIGH);
digitalWrite(LEDPinRed,LOW);
LEDState=1;
}
else{
digitalWrite(LEDPinBlue, LOW);
digitalWrite(LEDPinRed,HIGH);
LEDState=0;
}
}
buttonOld=buttonNew;
delay(dt);
return LEDState;
}
float readForce ()
{
int fsrreading1 = analogRead(fsrpin1);
int fsrreading2 = analogRead(fsrpin2);
float current_force = conversion_factor * ((fsrreading1 + fsrreading2) / 2);
Serial.print("Reading = ");
Serial.println(current_force);
return current_force;
}
int calculateStep (float current_force)
{
int step_size {};
if (((current_force < (1 - tolerance_window) * target_force) && (current_force < target_force)) || ((current_force > (1 + tolerance_window) * target_force) && (current_force > target_force))) {
// step_size = prop_gain * (target_force - current_force);
step_size = prop_gain * ((target_force / conversion_factor) - (current_force / conversion_factor - 0)) * (max_step_size - min_step_size) / (1023 - 0);
}
return step_size;
}