Skip to content

Commit 88c41b9

Browse files
committed
lab robot with CPG, done sigle leg test
1 parent 2445d8f commit 88c41b9

File tree

4 files changed

+204
-71
lines changed

4 files changed

+204
-71
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
.DS_Store
2-
.idea
2+
.idea
3+
4+
.vscode

hardware_test/LabRobot/DogRobot/DogRobot.ino

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,47 @@ void setup() {
1717
PTL(" 0. switch off");
1818
}
1919

20-
String inString = "";
20+
int inp = "";
21+
int code = 999;
2122
void loop() {
22-
if (Serial.available() > 0) {
23+
if (Serial.available() > 0) {
2324
if (Serial.peek() != '\n') {
24-
inString += (char)Serial.read();
25+
inp = Serial.parseInt();
2526
} else {
2627
Serial.read();
2728
Serial.print("Instruction received: ");
28-
29-
int code = inString.toInt();
30-
Serial.println(code);
31-
switch(code) {
32-
case 1:
33-
Robot.switch_on();
34-
break;
35-
case 2:
36-
Robot.bot_stand();
37-
break;
38-
case 0:
39-
Robot.switch_off();
40-
break;
41-
default:
42-
PTL("wrong code");
43-
}
29+
Serial.println(inp);
4430

45-
inString = "";
31+
code = inp;
32+
Robot.lock = false; // unlock the robot
33+
inp = "";
4634
}
4735
}
4836

37+
switch(code) {
38+
case 1:
39+
Robot.switch_on();
40+
// lock the robot, unless the periodic motion code
41+
Robot.lock = true;
42+
break;
43+
case 2:
44+
Robot.bot_stand();
45+
Robot.lock = true;
46+
break;
47+
case 3:
48+
Robot.bot_walk();
49+
// Robot.lock = true; // for test
50+
break;
51+
case 0:
52+
Robot.switch_off();
53+
Robot.lock = true;
54+
break;
55+
case 999:
56+
// waiting for input ...
57+
break;
58+
default:
59+
PTL("wrong code");
60+
code = 999;
61+
}
62+
4963
}
Lines changed: 115 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,158 @@
1+
2+
#include <Arduino.h>
13
#include "QuadrupedRobot.h"
2-
#include "Arduino.h"
34

45

5-
void QuadrupedRobot::setup_servos() {
6+
void QuadrupedRobot::setup_servos()
7+
{
68
PTL("Setup Servos");
7-
for (size_t i = 0; i < DOF; i++) {
8-
if(servos[i] == nullptr) servos[i] = new Servo();
9+
for (size_t i = 0; i < DOF; i++)
10+
{
11+
if (servos[i] == nullptr)
12+
servos[i] = new Servo();
913
servos[i]->attach(pins[i], SERVOMIN, SERVOMAX);
1014
}
1115
}
1216

13-
void QuadrupedRobot::shut_servos() {
14-
for (size_t i = 0; i < DOF; i++) {
15-
if (servos[i] != nullptr) {
17+
void QuadrupedRobot::shut_servos()
18+
{
19+
for (size_t i = 0; i < DOF; i++)
20+
{
21+
if (servos[i] != nullptr)
22+
{
1623
servos[i]->detach();
1724
}
1825
}
1926
}
2027

21-
void QuadrupedRobot::servo_write_angs(double angs[DOF]) {
22-
PTL("Servo Write Angles");
23-
double real_ang {};
24-
double pulsewidth {};
25-
for (size_t i = 0; i < DOF; i++) {
28+
void QuadrupedRobot::servo_write_angs(double angs[DOF], bool angs_in_rad=false)
29+
{
30+
// PTL("Servo Write Angles");
31+
double real_ang{};
32+
double pulsewidth{};
33+
for (size_t i = 0; i < DOF; i++)
34+
{
35+
if (angs_in_rad) {
36+
angs[i] = angs[i] * 180 / M_PI;
37+
}
2638
real_ang = init_angs[i] + dir[i] * angs[i];
2739
pulsewidth = 500 + real_ang / 90.0 * 1000;
28-
if (!servos[i]->attached()) {
40+
if (!servos[i]->attached())
41+
{
2942
servos[i]->attach(pins[i], SERVOMIN, SERVOMAX);
3043
}
3144
servos[i]->writeMicroseconds(pulsewidth);
3245
}
33-
delayMicroseconds(3000);
46+
delay(5);
3447
}
3548

36-
QuadrupedRobot::QuadrupedRobot() {
37-
49+
QuadrupedRobot::QuadrupedRobot()
50+
{
51+
// init data for CPG
52+
omega_st = omega_sw * (1 - beta) / beta;
53+
mu = Ah * Ah;
54+
for (int i = 0; i < 4; i++) {
55+
for (int j = 0; j < 4; j++) {
56+
theta[i][j] = 2 * M_PI * (phi[i] - phi[j]);
57+
}
58+
}
3859
}
3960

40-
QuadrupedRobot::~QuadrupedRobot() {
41-
61+
QuadrupedRobot::~QuadrupedRobot()
62+
{
4263
}
4364

44-
void QuadrupedRobot::switch_on() {
65+
void QuadrupedRobot::switch_on()
66+
{
67+
if(lock) return;
4568
PTL("Robot Switch On");
4669
setup_servos();
4770
bot_rest();
4871
delay(1000);
4972
shut_servos();
5073
}
5174

52-
void QuadrupedRobot::switch_off() {
75+
void QuadrupedRobot::switch_off()
76+
{
77+
if(lock) return;
5378
PTL("Robot Switch Off");
5479
shut_servos();
5580
}
5681

57-
void QuadrupedRobot::bot_rest() {
82+
void QuadrupedRobot::bot_rest()
83+
{
84+
if(lock) return;
5885
PTL("Robot Rest");
59-
double rest_angs[12] {0, -55, 130, 0, -55, 130, 0, 55, -130, 0, 55, -130};
86+
double rest_angs[12]{0, -55, 130, 0, -55, 130, 0, 55, -130, 0, 55, -130};
6087
servo_write_angs(rest_angs);
6188
}
6289

63-
void QuadrupedRobot::bot_stand() {
90+
void QuadrupedRobot::bot_stand()
91+
{
92+
if(lock) return;
6493
PTL("Robot Stand");
65-
double stand_angs[12] {0, -30, 60, 0, -30, 60, 0, 30, -60, 0, 30, -60};
94+
double stand_angs[12]{0, -30, 60, 0, -30, 60, 0, 30, -60, 0, 30, -60};
6695
servo_write_angs(stand_angs);
6796
}
97+
98+
void QuadrupedRobot::bot_walk()
99+
{
100+
if(lock) return;
101+
double angs[12] {};
102+
double stand_angs[12]{0, -30, 60, 0, -30, 60, 0, 30, -60, 0, 30, -60};
103+
// dt = 0.0001s, dt * 100 = 0.01s
104+
for (size_t itr = 0; itr < 100; itr++) {
105+
for (int i = 0; i < 1; i++) {
106+
r_square[i] = x[i] * x[i] + y[i] * y[i]; // 1
107+
108+
// Frequency of the oscillator
109+
omega[i] = omega_st / (exp(- a * y[i]) + 1) + omega_sw / (exp(a * y[i]) + 1); // 9.42
110+
111+
// HOPF Oscillator
112+
x_dot[i] = alpha * (mu - r_square[i]) * x[i] - omega[i] * y[i];
113+
y_dot[i] = alpha * (mu - r_square[i]) * y[i] + omega[i] * x[i];
114+
115+
/**
116+
* coupling terms
117+
* [
118+
* R11 R21 R31 R41
119+
* R12 R22 R32 R42
120+
* R13 R23 R33 R43
121+
* R14 R24 R34 R44
122+
* ]
123+
*/
124+
// x_dot[i] += cos(theta[0][i]) * x[0] - sin(theta[0][i]) * y[0];
125+
// y_dot[i] += sin(theta[0][i]) * x[0] + cos(theta[0][i]) * y[0];
126+
// x_dot[i] += cos(theta[1][i]) * x[1] - sin(theta[1][i]) * y[1];
127+
// y_dot[i] += sin(theta[1][i]) * x[1] + cos(theta[1][i]) * y[1];
128+
// x_dot[i] += cos(theta[2][i]) * x[2] - sin(theta[2][i]) * y[2];
129+
// y_dot[i] += sin(theta[2][i]) * x[2] + cos(theta[2][i]) * y[2];
130+
// x_dot[i] += cos(theta[3][i]) * x[3] - sin(theta[3][i]) * y[3];
131+
// y_dot[i] += sin(theta[3][i]) * x[3] + cos(theta[3][i]) * y[3];
132+
133+
// update the signal values
134+
x[i] += x_dot[i] * dt;
135+
y[i] += y_dot[i] * dt;
136+
137+
// Hip Joint Angels
138+
angs[i] = 0 + stand_angs[i];
139+
angs[i + 1] = x[i] * 180 / M_PI + stand_angs[i + 1];
140+
141+
// Knee Joint Angel
142+
if (y[i] > 0) {
143+
angs[i + 2] = stand_angs[i + 2];
144+
} else {
145+
angs[i + 2] = - y[i] * Ak * 180 / (M_PI * Ah) + stand_angs[i + 2];
146+
}
147+
}
148+
}
149+
150+
// PTL("signals: ");
151+
// PTL(x[0]);
152+
// PTL(y[0]);
153+
// PTL("Angles: ");
154+
// PTL(angs[1]);
155+
// PTL(angs[2]);
156+
157+
servo_write_angs(angs);
158+
}
Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#ifndef QUADRUPED_ROBOT_H
22
#define QUADRUPED_ROBOT_H
33

4-
#include"Arduino.h"
4+
#include "Arduino.h"
55
#include <Servo.h>
66

7-
#define PT(s) Serial.print(s)
7+
#define PT(s) Serial.print(s)
88
#define PTL(s) Serial.println(s)
9-
#define PTF(s) Serial.print(F(s)) //trade flash memory for dynamic memory with F() function
9+
#define PTF(s) Serial.print(F(s)) //trade flash memory for dynamic memory with F() function
1010
#define PTLF(s) Serial.println(F(s))
1111

1212
// Servo Pin configs
@@ -26,45 +26,71 @@
2626
//servo constants
2727
#define SERVOMIN 500
2828
#define SERVOMAX 2500
29-
#define PWM_RANGE (SERVOMAX - SERVOMIN)
3029

3130
#define DOF 12
3231

33-
3432
class QuadrupedRobot
3533
{
36-
private:
37-
Servo *servos[DOF] = {
34+
private:
35+
Servo *servos[DOF] = {
3836
nullptr, nullptr, nullptr,
3937
nullptr, nullptr, nullptr,
4038
nullptr, nullptr, nullptr,
41-
nullptr, nullptr, nullptr
42-
};
43-
byte pins[DOF] = {
39+
nullptr, nullptr, nullptr};
40+
byte pins[DOF]{
4441
rFL_PIN, sFL_PIN, kFL_PIN,
4542
rFR_PIN, sFR_PIN, kFR_PIN,
4643
rHR_PIN, sHR_PIN, kHR_PIN,
47-
rHL_PIN, sHL_PIN, kHL_PIN
48-
};
44+
rHL_PIN, sHL_PIN, kHL_PIN};
45+
46+
// Servo rotation configs
47+
uint8_t init_angs[12]{45, 90, 180, 130, 83, 0, 45, 90, 180, 130, 83, 0};
48+
int8_t dir[12]{1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1};
49+
50+
/**
51+
* CPG Gait Configs
52+
*/
53+
uint8_t alpha{1000};
54+
double beta{0.5};
55+
double Ah{0.2};
56+
double Ak{0.5};
57+
uint8_t a{10};
58+
// LF, RF, LH, RH
59+
double phi[4]{0, 0.5, 0.5, 0};
60+
double omega_sw{5*M_PI};
61+
62+
// oscillator signals
63+
double x[4] {1, 0, 0, 0};
64+
double y[4] {0, 0, 0, 0};
65+
// x_dot = dx / dt
66+
double x_dot[4] {};
67+
double y_dot[4] {};
68+
// r_square = x^2 + y^2
69+
double r_square[4] {};
4970

50-
char* duty_angles = NULL;
71+
double omega_st {};
72+
double mu {};
73+
double omega[4] {};
74+
double theta[4][4] {};
75+
double dt {0.0001};
5176

52-
// Servo rotation configs
53-
uint8_t init_angs[12] = {45, 90, 180, 130, 83, 0, 45, 90, 180, 130, 83, 0};
54-
int8_t dir[12] = {1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1};
77+
double rad2deg(double rad);
78+
void setup_servos();
79+
void shut_servos();
80+
void servo_write_angs(double angs[12], bool angs_in_rad=false);
5581

56-
void setup_servos();
57-
void shut_servos();
58-
void servo_write_angs(double angs[12]);
82+
public:
83+
QuadrupedRobot();
84+
~QuadrupedRobot();
5985

60-
public:
61-
QuadrupedRobot();
62-
~QuadrupedRobot();
86+
// lock any robot motion
87+
bool lock{false};
6388

64-
void switch_on();
65-
void switch_off();
66-
void bot_rest();
67-
void bot_stand();
89+
void switch_on();
90+
void switch_off();
91+
void bot_rest();
92+
void bot_stand();
93+
void bot_walk();
6894
};
6995

7096
#endif

0 commit comments

Comments
 (0)