-
Notifications
You must be signed in to change notification settings - Fork 0
/
Kinematics.cpp
160 lines (133 loc) · 5.7 KB
/
Kinematics.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
Copyright (c) 2016, Juan Jimeno
Source: http://research.ijcaonline.org/volume113/number3/pxc3901586.pdf
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORTPPIPI (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "Arduino.h"
#include "Kinematics.h"
Kinematics::Kinematics(base robot_base, int motor_max_rpm, float wheel_diameter,
float wheels_x_distance, float wheels_y_distance):
base_platform(robot_base),
max_rpm_(motor_max_rpm),
wheels_x_distance_(base_platform == DIFFERENTIAL_DRIVE ? 0 : wheels_x_distance),
wheels_y_distance_(wheels_y_distance),
wheel_circumference_(PI * wheel_diameter),
total_wheels_(getTotalWheels(robot_base))
{
}
Kinematics::rpm Kinematics::calculateRPM(float linear_x, float linear_y, float angular_z)
{
float linear_vel_x_mins;
float linear_vel_y_mins;
float angular_vel_z_mins;
float tangential_vel;
float x_rpm;
float y_rpm;
float tan_rpm;
//convert m/s to m/min
linear_vel_x_mins = linear_x * 60;
linear_vel_y_mins = linear_y * 60;
//convert rad/s to rad/min
angular_vel_z_mins = angular_z * 60;
tangential_vel = angular_vel_z_mins * ((wheels_x_distance_ / 2) + (wheels_y_distance_ / 2));
x_rpm = linear_vel_x_mins / wheel_circumference_;
y_rpm = linear_vel_y_mins / wheel_circumference_;
tan_rpm = tangential_vel / wheel_circumference_;
Kinematics::rpm rpm;
//calculate for the target motor RPM and direction
//front-left motor
rpm.motor1 = x_rpm - y_rpm - tan_rpm;
rpm.motor1 = constrain(rpm.motor1, -max_rpm_, max_rpm_);
//front-right motor
rpm.motor2 = x_rpm + y_rpm + tan_rpm;
rpm.motor2 = constrain(rpm.motor2, -max_rpm_, max_rpm_);
//rear-left motor
rpm.motor3 = x_rpm + y_rpm - tan_rpm;
rpm.motor3 = constrain(rpm.motor3, -max_rpm_, max_rpm_);
//rear-right motor
rpm.motor4 = x_rpm - y_rpm + tan_rpm;
rpm.motor4 = constrain(rpm.motor4, -max_rpm_, max_rpm_);
return rpm;
}
Kinematics::rpm Kinematics::getRPM(float linear_x, float linear_y, float angular_z)
{
Kinematics::rpm rpm;
if(base_platform == DIFFERENTIAL_DRIVE || base_platform == SKID_STEER)
{
rpm = calculateRPM(linear_x, 0.0 , angular_z);
}
else if(base_platform == ACKERMANN || base_platform == ACKERMANN1)
{
rpm = calculateRPM(linear_x, 0.0, 0.0);
}
else if(base_platform == MECANUM)
{
rpm = calculateRPM(linear_x, linear_y, angular_z);
}
return rpm;
}
Kinematics::velocities Kinematics::getVelocities(float steering_angle, int rpm1, int rpm2)
{
Kinematics::velocities vel;
float average_rps_x;
//convert average revolutions per minute to revolutions per second
average_rps_x = ((float)(rpm1 + rpm2) / total_wheels_) / 60; // RPM
vel.linear_x = average_rps_x * wheel_circumference_; // m/s
vel.linear_y = 0.0;
//http://wiki.ros.org/teb_local_planner/Tutorials/Planning%20for%20car-like%20robots
vel.angular_z = (vel.linear_x * tan(steering_angle)) / wheels_x_distance_;
return vel;
}
Kinematics::velocities Kinematics::getVelocities(int rpm1, int rpm2, int rpm3, int rpm4)
{
Kinematics::velocities vel;
float average_rps_x;
float average_rps_y;
float average_rps_a;
//convert average revolutions per minute to revolutions per second
average_rps_x = ((float)(rpm1 + rpm2 + rpm3 + rpm4) / total_wheels_) / 60; // RPM
vel.linear_x = average_rps_x * wheel_circumference_; // m/s
//convert average revolutions per minute in y axis to revolutions per second
average_rps_y = ((float)(-rpm1 + rpm2 + rpm3 - rpm4) / total_wheels_) / 60; // RPM
if(base_platform == MECANUM)
vel.linear_y = average_rps_y * wheel_circumference_; // m/s
else
vel.linear_y = 0;
//convert average revolutions per minute to revolutions per second
average_rps_a = ((float)(-rpm1 + rpm2 - rpm3 + rpm4) / total_wheels_) / 60;
vel.angular_z = (average_rps_a * wheel_circumference_) / ((wheels_x_distance_ / 2) + (wheels_y_distance_ / 2)); // rad/s
return vel;
}
int Kinematics::getTotalWheels(base robot_base)
{
switch(robot_base)
{
case DIFFERENTIAL_DRIVE: return 2;
case ACKERMANN: return 2;
case ACKERMANN1: return 1;
case SKID_STEER: return 4;
case MECANUM: return 4;
default: return 2;
}
}