Mechanism
Design
The payload (water bottles) are stored in a revolving cylinder in order to minmize space occupied and reduce the number of required servos to release each individual payload. There are two servos, one responsible for rotating the cylinder to the correct payload, and the other for releasing it. An angle sensor is utilized to assign an angle to each payload, allowing the plane to differentiate between payloads 1-5. The system is controlled by an Arduino Nano, which is fed instructions from the Jetson.
Arduino Code
The main role of the code is to take in some signal from the Jetson, and be able to interpret that as which payload to rotate to and drop. Due to Jetson limitations, we could only send a high or low signal from 4 pins. Considering that we had to uniquely represent 5 payloads, we chose to assign 3 pins to provide a binary representation of which payload we wanted to rotate to. Payload 1 would be 000, payload 2 would be 001, and so forth until we reach payload 5. Our 4th pin would then be dedicated to providing the drop signal, releasing the payload when high, and returning to its intial position when the signal was low. In order to know which bottle we want to drop, we have this function:
byte whichBottleRotate(){
//Read from 4 GPI pins on the Jetson to determine which bottle and when to drop
//Pin 1 will be when to drop
//Pin 2-3 will be binary for bottle slot 1-5 i.e. bottle 4 will be 011
byte bi1 = digitalRead(BINARY_1); //GPIO 298 (LSB)
byte bi2 = digitalRead(BINARY_2); //GPIO 480
byte bi3 = digitalRead(BINARY_3); //GPIO 486 (MSB)
return bi1 | (bi2 << 1) | (bi3 << 2);
}
The returned byte can then be converted back into decimal form, indicating which payload we want to drop.
switch ((int)bottleIndex) {
case 1:
setPoint = BOTTLE_1_ANGLE;
break;
case 2:
setPoint = BOTTLE_2_ANGLE;
break;
case 3:
setPoint = BOTTLE_3_ANGLE;
break;
case 4:
setPoint = BOTTLE_4_ANGLE;
break;
case 5:
setPoint = BOTTLE_5_ANGLE;
break;
default:
Serial.println("ERROR: bottleIndex " + String((int)bottleIndex));
binarySignalPrint();
}
void controller(double setPoint) {
//controller gains
double pGain = 10;
//min and max meaningful pwm values for rotatingServo
int rotatingServo_max_pwm = 1600;
int rotatingServo_min_pwm = 1400;
double currAngle = angleSensor.readAngle();
double errorDegrees = (fmod(currAngle - setPoint + 540, 360) - 180);
double P = -errorDegrees*pGain;
double controllerOutput = P; //+I+D later if needed
double pwmOutput = constrain(1500 + controllerOutput, rotatingServo_min_pwm, rotatingServo_max_pwm);
rotatingServo.writeMicroseconds(pwmOutput);
Serial.print("setPoint: ");
Serial.print(setPoint,1);
Serial.print(" currAngle: ");
Serial.print(currAngle,1);
Serial.print(" pwm output: ");
Serial.println(pwmOutput,0);
}