Skip to content

Commit 56fec5a

Browse files
committed
Integrated IK and logging
1 parent 2868400 commit 56fec5a

File tree

6 files changed

+131
-46
lines changed

6 files changed

+131
-46
lines changed

arduino_sketch/.vscode/arduino.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
22
"board": "arduino:avr:nano",
3-
"port": "/dev/ttyUSB0"
3+
"port": "/dev/ttyUSB0",
4+
"programmer": "avrispmkii",
5+
"sketch": "arduino_sketch.ino"
46
}

arduino_sketch/Config.h

+30-8
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
#define SERVO_SPEED_MIN 50
2323
#define SERVO_SPEED_MAX 100
2424

25-
// If DEBUG is set to true, the arduino will send back all the received messages
26-
#define DEBUG false
25+
#define DEBUG
2726

2827
#define MAX_EASING_SERVOS 9
2928

@@ -37,6 +36,12 @@
3736
#define S8_REST 90 // Neck tilt
3837
#define S9_REST 90 // Neck pan
3938

39+
#define LEG_IK_MIN 140
40+
#define LEG_IK_MAX 170
41+
42+
#define NOVAL 1000
43+
44+
4045
// Arrays to store servo min / max positions to avoid mechanical issues due
4146
// NOTE: attach() disregards this, set PosSleep to be within range of the servo's physical boundaries
4247
int PosMin[MAX_EASING_SERVOS] = {20, 5, 40, 20, 5, 15, 40, 60, 20};
@@ -49,12 +54,12 @@ int PrepSleepFromRest[MAX_EASING_SERVOS] = {S1_REST, S2_REST, S3_REST, S4_REST,
4954
int PosRest[MAX_EASING_SERVOS] = {S1_REST, S2_REST, S3_REST, S4_REST, S5_REST, S6_REST, S7_REST, S8_REST, S9_REST};
5055

5156
// Poses
52-
int PosStand[MAX_EASING_SERVOS] = {110, 110, 110, 70, 70, 70, S7_REST, S8_REST, S9_REST};
53-
int PosLookLeft[MAX_EASING_SERVOS] = {S1_REST, S2_REST, S3_REST, S4_REST, S5_REST, S6_REST, S7_REST, S8_REST, 180};
54-
int PosLookRight[MAX_EASING_SERVOS] = {S1_REST, S2_REST, S3_REST, S4_REST, S5_REST, S6_REST, S7_REST, S8_REST, 0};
55-
int PosLookRandom[MAX_EASING_SERVOS] = {S1_REST, S2_REST, S3_REST, S4_REST, S5_REST, S6_REST, S7_REST, -1, -1}; // Made random by calling the function moveRandom() if the value is -1
56-
int PosLookUp[MAX_EASING_SERVOS] = {S1_REST, S2_REST, S3_REST, S4_REST, S5_REST, S6_REST, S7_REST, 60, S9_REST};
57-
int PosLookDown[MAX_EASING_SERVOS] = {S1_REST, S2_REST, S3_REST, S4_REST, S5_REST, S6_REST, S7_REST, 120, S9_REST};
57+
int PosStand[MAX_EASING_SERVOS] = {110, 110, 110, 70, 70, 70, NOVAL, NOVAL, NOVAL};
58+
int PosLookLeft[MAX_EASING_SERVOS] = {NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, 180};
59+
int PosLookRight[MAX_EASING_SERVOS] = {NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, 0};
60+
int PosLookRandom[MAX_EASING_SERVOS] = {NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, -1, -1}; // Made random by calling the function moveRandom() if the value is -1
61+
int PosLookUp[MAX_EASING_SERVOS] = {NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, 60, S9_REST};
62+
int PosLookDown[MAX_EASING_SERVOS] = {NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, NOVAL, 120, S9_REST};
5863

5964
// Array of poses except PosRest and PosSleep (which are used for initialization and reset of position)
6065
int *Poses[] = {PosStand, PosLookLeft, PosLookRight, PosLookUp, PosLookDown, PosLookRandom};
@@ -67,4 +72,21 @@ void blinkLED()
6772
delay(100);
6873
}
6974

75+
/**
76+
* Custom logging function to avoid having to wrap every Serial.println() in #ifdef DEBUG
77+
*/
78+
void cLog(String message, boolean newline = true)
79+
{
80+
#ifdef DEBUG
81+
if (newline)
82+
{
83+
Serial.println(message);
84+
}
85+
else
86+
{
87+
Serial.print(message);
88+
}
89+
#endif
90+
}
91+
7092
#endif

arduino_sketch/InverseKinematics.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class InverseKinematics
1212
{
1313
// constructor
1414
public:
15-
InverseKinematics(float hipMinAngle, float hipMaxAngle, float kneeMinAngle, float kneeMaxAngle, float ankleMinAngle, float ankleMaxAngle, float thighLength, float shinLength, float footLength)
15+
void doInit(float hipMinAngle, float hipMaxAngle, float kneeMinAngle, float kneeMaxAngle, float ankleMinAngle, float ankleMaxAngle, float thighLength, float shinLength, float footLength)
1616
{
1717
this->hipMinAngle = hipMinAngle;
1818
this->hipMaxAngle = hipMaxAngle;

arduino_sketch/PiConnect.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,20 @@ class PiConnect
2525
}
2626
void setConnected(boolean connected)
2727
{
28-
Serial.print(F("Serial connected: "));
29-
Serial.println(connected);
28+
cLog(F("Serial connected: "), false);
29+
cLog((String) connected);
3030
this->serialConnected = connected;
3131
}
3232
static boolean checkForConnection()
3333
{
34-
Serial.print(F("Checking for connection:"));
34+
cLog(F("Checking for connection"));
3535
write_order(HELLO);
3636
wait_for_bytes(1, 1000);
3737
}
3838

3939
static Order read_order()
4040
{
41-
Serial.println("Reading order");
41+
cLog("Reading order");
4242
return (Order) Serial.read();
4343
}
4444

arduino_sketch/ServoManager.h

+38-10
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ ServoEasing Servo8;
2222
// Neck pan
2323
ServoEasing Servo9;
2424

25-
InverseKinematics ik(PosMin[3], PosMax[3], PosMin[4], PosMax[4], PosMin[5], PosMax[5], 94.0, 94.0, 28.0);
25+
InverseKinematics ik;
2626

2727

2828
class ServoManager
@@ -40,6 +40,8 @@ class ServoManager
4040
Servo8.attach(SERVO8_PIN, PosSleep[7]);
4141
Servo9.attach(SERVO9_PIN, PosSleep[8]);
4242

43+
ik.doInit(PosMin[3], PosMax[3], PosMin[4], PosMax[4], PosMin[5], PosMax[5], 94.0, 94.0, 28.0);
44+
4345
// Loop over ServoEasing::ServoEasingArray and attach each servo
4446
for (uint8_t tIndex = 0; tIndex < MAX_EASING_SERVOS; ++tIndex)
4547
{
@@ -49,38 +51,62 @@ class ServoManager
4951
}
5052
// Wait for servos to reach start position.
5153
delay(3000);
52-
Serial.println("Servos initialised");
54+
cLog("Servos initialised");
5355
}
5456

5557
void moveServos(int *Pos)
5658
{
5759
for (uint8_t tIndex = 0; tIndex < MAX_EASING_SERVOS; ++tIndex)
5860
{
61+
if (Pos[tIndex] == NOVAL) {
62+
//Serial.println("NOVAL FOUND");
63+
continue;
64+
}
5965
if (Pos[tIndex] != -1)
60-
ServoEasing::ServoEasingNextPositionArray[tIndex] = Pos[tIndex];
66+
moveSingleServo(tIndex, Pos[tIndex]);
6167
else
62-
ServoEasing::ServoEasingNextPositionArray[tIndex] = moveRandom(tIndex); // If scripted value is -1, generate random position based on range of currently indexed servo
68+
moveSingleServo(tIndex, moveRandom(tIndex)); // If scripted value is -1, generate random position based on range of currently indexed servo
6369
}
6470
//setEaseToForAllServosSynchronizeAndStartInterrupt(tSpeed);
6571
}
72+
73+
// @todo just make this pass an array in to moveServos.
6674
void moveSingleServo(uint8_t pServoIndex, int pPos)
6775
{
6876
ServoEasing::ServoEasingNextPositionArray[pServoIndex] = pPos;
6977
//setEaseToForAllServosSynchronizeAndStartInterrupt(tSpeed);
7078
}
7179

80+
void moveLegsAndStore(int x, int y, int *store)
81+
{
82+
moveLegs(x, y);
83+
for (uint8_t tIndex = 0; tIndex < MAX_EASING_SERVOS; ++tIndex)
84+
{
85+
store[tIndex] = ServoEasing::ServoEasingNextPositionArray[tIndex];
86+
}
87+
}
88+
89+
// function moveLegs that returns an int array
90+
void moveLegs(int x, int y)
91+
{
92+
float hipAngleL, kneeAngleL, ankleAngleL, hipAngleR, kneeAngleR, ankleAngleR;
93+
// solve left leg
94+
ik.inverseKinematics2D(x, y, hipAngleR, kneeAngleR, ankleAngleR);
95+
// solve other leg
96+
ik.calculateOtherLeg(hipAngleR, kneeAngleR, ankleAngleR, hipAngleL, kneeAngleL, ankleAngleL);
97+
// Assign angles and move servos
98+
int thisMove[MAX_EASING_SERVOS] = {hipAngleL, kneeAngleL, ankleAngleL, hipAngleR, kneeAngleR, ankleAngleR, NOVAL, NOVAL, NOVAL};
99+
moveServos(thisMove);
100+
}
101+
72102
void demoAll()
73103
{
74-
//Serial.println(F("Demo all poses at minimum speed"));
75104
setSpeed(SERVO_SPEED_MIN);
76105
// Cycle through all poses and move all servos to them
77106
for (uint8_t tPoseIndex = 0; tPoseIndex < sizeof(Poses) / sizeof(Poses[0]); ++tPoseIndex)
78107
{
79-
//Serial.print(F("Pose: "));
80-
//Serial.println(tPoseIndex);
81108
moveServos(Poses[tPoseIndex]);
82109
delay(1000);
83-
//Serial.println(F("Rest"));
84110
moveServos(PosRest);
85111
delay(2000);
86112
}
@@ -90,8 +116,8 @@ class ServoManager
90116
{
91117
tSpeed = pSpeed;
92118
setSpeedForAllServos(tSpeed);
93-
//Serial.print(F("Speed set: "));
94-
//Serial.println(tSpeed);
119+
// cLog(F("Speed set: "));
120+
// cLog((String) tSpeed);
95121
}
96122

97123
uint16_t getSpeed()
@@ -116,7 +142,9 @@ class ServoManager
116142
// Solve inverse kinematics for left leg
117143
if (!ik.inverseKinematics2D(x, 0, hipAngleL, kneeAngleL, ankleAngleL))
118144
{
145+
#ifdef IK_DEBUG
119146
Serial.println("No solution");
147+
#endif
120148
return;
121149
}
122150

arduino_sketch/arduino_sketch.ino

+55-22
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,42 @@ unsigned long sleepTime;
2525

2626
void setup()
2727
{
28+
// Init LED pin
2829
pinMode(LED_BUILTIN, OUTPUT);
2930
pinMode(11, OUTPUT); // sets the digital pin as output
3031
digitalWrite(11, LOW); // sets the digital pin on
32+
// Init boot time for sleep function
3133
bootTime = millis();
34+
// Init serial
3235
Serial.begin(115200);
33-
//delay(2000);
36+
// Init ServoManager
3437
servoManager.doInit();
3538
servoManager.setSpeed(SERVO_SPEED_MIN);
3639

3740
// Seed random number generator
3841
randomSeed(analogRead(0));
3942

40-
servoManager.moveServos(PrepRestFromSleep); // Move hips and head to try and balance
41-
doRest();
42-
43-
Serial.println(F("Start loop"));
43+
// Move from start position to rest position
44+
// servoManager.moveServos(PrepRestFromSleep); // Move hips and head to try and balance
45+
//doRest();
46+
47+
// Mid value between LEG_IK_MIN and LEG_IK_MAX
48+
float mid = LEG_IK_MIN + ((LEG_IK_MAX - LEG_IK_MIN) / 2);
49+
servoManager.moveLegsAndStore(mid, 0, PosRest); // Move legs and store as rest position
50+
// iterate over PosRest and output values:
51+
for (int i = 0; i < 9; i++)
52+
{
53+
Serial.print(PosRest[i]);
54+
Serial.print(", ");
55+
}
56+
Serial.println();
57+
58+
// Custom log message (enable DEBUG in Config.h to see this)
59+
cLog("Start loop");
4460
}
4561
void doRest()
4662
{
47-
Serial.println("Resting");
63+
cLog("Resting");
4864
isResting = true;
4965
// Reset to slow speed
5066
servoManager.setSpeed(SERVO_SPEED_MIN);
@@ -58,11 +74,8 @@ void loop()
5874
{
5975
blinkLED();
6076
}
61-
//Serial.println("Looping");
62-
// Check for serial connection and connect, or wait for orders if connected
63-
// if (pi.isConnected() == false)
64-
// PiConnect::checkForConnection(); // Say hello and wait for response
65-
77+
78+
// Check for orders from pi
6679
getOrdersFromPi();
6780

6881
// if not sleeping, animate randomly
@@ -89,33 +102,53 @@ void setSleep(unsigned long length)
89102

90103
boolean isSleeping()
91104
{
92-
//Serial.println(".");
93105
return millis() - bootTime < sleepTime;
94106
}
95107

96108
void animateRandomly()
97109
{
98-
Serial.println("Animating");
110+
cLog("Animating");
99111
isResting = false;
100-
// Set tSpeed to between SERVO_SPEED_MIN and SERVO_SPEED_MAX
101112
servoManager.setSpeed(random(SERVO_SPEED_MIN, SERVO_SPEED_MAX));
102-
// Radomly select a pose and move to it (not stand)
103-
// uint8_t tPoseIndex = random(1, sizeof(Poses) / sizeof(Poses[0]));
113+
// Look around randomly or move legs randomly
114+
switch (random(0, 4))
115+
{
116+
case 0:
117+
servoManager.moveServos(PosLookRandom);
104118

105-
//Serial.print(F("Pose: "));
106-
//Serial.println(tPoseIndex);
107-
//moveServos(Poses[tPoseIndex]);
108-
servoManager.moveServos(PosLookRandom);
119+
// If head looks down, move legs up, and vice versa
120+
float headTiltOffset = ServoEasing::ServoEasingNextPositionArray[7] - 90;
121+
// Scale headTiltOffset value between 0 and 180 to scale of LEG_IK_MIN and LEG_IK_MAX
122+
float legHeight = map(headTiltOffset, -90, 90, LEG_IK_MIN, LEG_IK_MAX);
123+
// Move legs to that height
124+
servoManager.moveLegs(legHeight, 0);
125+
Serial.print("Moving legs ");
126+
Serial.print(legHeight);
127+
Serial.print(" as head tilt was ");
128+
Serial.println(headTiltOffset);
129+
break;
130+
case 1:
131+
servoManager.moveLegs(random(LEG_IK_MIN, LEG_IK_MAX), 0);
132+
break;
133+
case 2:
134+
servoManager.moveServos(PosLookRandom);
135+
break;
136+
case 3:
137+
// do both
138+
servoManager.moveServos(PosLookRandom);
139+
servoManager.moveLegs(random(LEG_IK_MIN, LEG_IK_MAX), 0);
140+
break;
141+
}
109142
}
110143

111144
void getOrdersFromPi()
112145
{
113146
if(Serial.available() == 0) return;
114-
Serial.print("Order received: ");
147+
cLog("Order received: ", false);
115148

116149
// The first byte received is the instruction
117150
Order order_received = PiConnect::read_order();
118-
Serial.println(order_received);
151+
cLog((String) order_received);
119152
if(order_received == HELLO)
120153
{
121154
// If the cards haven't say hello, check the connection

0 commit comments

Comments
 (0)