Week 11 – Final(3) – Code

For fabrication works, please check it out HERE.

The code is logically divided into 3 parts and I test the code’s feasibility independently before putting it together.
The three sections are the connection between the gesture sensor and the 180-degree servos, the logic of the gesture sensor, the 360-degree servo, the limit switches, and the connection between the 16-servo driver and the Arduino.

Test 1 – Gesture sensor & 180-degree servos

#include “Adafruit_APDS9960.h”
#include<Servo.h>Servo myServo;Adafruit_APDS9960 apds;
int pos = -45;// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);if (!apds.begin()) {
Serial.println(“failed to initialize device! Please check your wiring.”);
}
else Serial.println(“Device initialized!”);//gesture mode will be entered once proximity mode senses something close
apds.enableProximity(true);
apds.enableGesture(true);
myServo.attach(3);
myServo.write(pos);
}// the loop function runs over and over again forever
void loop() {
//read a gesture from the device
uint8_t gesture = apds.readGesture();
if (gesture == APDS9960_DOWN) Serial.println(“v”);
if (gesture == APDS9960_UP) Serial.println(“^”);
if (gesture == APDS9960_LEFT) {
Serial.println(“<“);
for (pos = -45; pos < 132; pos += 1) {
myServo.write(pos);
delay(10);
}
}
if (gesture == APDS9960_RIGHT) {
Serial.println(“>”);
for (pos = 132; pos > -45; pos -= 1) {
myServo.write(pos);
delay(10);
}
}
}

Test 2 – Gesture sensor & 360-degree servo & limit switches

There are 2 factors to consider when triggering limit switches: 1) Torque depends on current, and 2) the mounting position of the limit switches and the speed (pulse, voltage-dependent) and torque (current-dependent) of the servo determine whether the trigger is successful.

#include “Adafruit_APDS9960.h”
#include<Servo.h>
#include <ezButton.h>ezButton limitSwitch1(6);
ezButton limitSwitch2(10);Servo myServo360;Adafruit_APDS9960 apds;//define the value of dif behaviors by 360c servo:
//int sc[] = {1500, 1800, 1200};
int sc[] = {92, 97, 88};
//stand for:STOP,CCW,CW// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);limitSwitch1.setDebounceTime(50);
limitSwitch2.setDebounceTime(50);if (!apds.begin()) {
Serial.println(“failed to initialize device! Please check your wiring.”);
}
else Serial.println(“Device initialized!”);

//gesture mode will be entered once proximity mode senses something close
apds.enableProximity(true);
apds.enableGesture(true);
myServo360.attach(3);
//myServo360.writeMicroseconds(sc[0]);
myServo360.write(sc[0]);
}

// the loop function runs over and over again forever
void loop() {
// MUST call the loop() function first
limitSwitch1.loop();
limitSwitch2.loop();

int state1 = limitSwitch1.getState();
int state2 = limitSwitch2.getState();

//read a gesture from the device
uint8_t gesture = apds.readGesture();
if (gesture == APDS9960_DOWN) Serial.println(“v”);
if (gesture == APDS9960_UP) Serial.println(“^”);
if (gesture == APDS9960_LEFT) {
Serial.println(“<“);
//myServo360.writeMicroseconds(sc[1]);
myServo360.write(sc[1]);
delay(10);
}

if (gesture == APDS9960_RIGHT) {
Serial.println(“>”);
//myServo360.writeMicroseconds(sc[2]);
myServo360.write(sc[2]);
delay(10);
}

// set 2 limit switches:
if (state1 == LOW) {
//myServo360.writeMicroseconds(sc[0]);
myServo360.write(sc[0]);
Serial.println(“The limit switch1: TOUCHED”);
}

if (state2 == LOW) {
//myServo360.writeMicroseconds(sc[0]);
myServo360.write(sc[0]);
Serial.println(“The limit switch2: TOUCHED”);
}
}

Test 3 – 16-servo driver & Arduino

Due to the torque and the number of 5 servos currently set, I chose to use a servo driver. It is possible to drive 16 servos at the same time and even add multiple drivers (unique addresses need to be assigned) so that the servos can be powered by an external power supply and the Arduino by a USB cable.

th-18Adafruit 16-Channel 12-bit PWM/Servo Driver – I2C interface – PCA9685

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();#define servoMIN 150
#define servoMAX 600
#define servoFREQ 60byte servoNum = 0;void setup() {
Serial.begin(9600);
pwm.begin();
pwm.setPWMFreq(servoFREQ);
}void loop() {for (int pulse = servoMIN; pulse < servoMAX; pulse++) {
pwm.setPWM(servoNum, 0, pulse);
Serial.println(servoNum);
}
delay(100);for (int pulse = servoMAX; pulse > servoMIN; pulse–) {
pwm.setPWM(servoNum, 0, pulse);
Serial.println(servoNum);
}
delay(100);

servoNum++;
if (servoNum > 3) {
servoNum = 0;
}
}

Current version:

The servo’s speed and direction are controlled by adjusting the pulse value. I’ve done a lot of testing and adjusting here, including the value of the pulse and the position of the limit switches and fans. Especially for the 360-degree servo, the forward trigger switch is considerably quicker than the reverse trigger switch.

🤔️ Question: I guess it was due to the position of the mechanical installation. This issue might be resolved with more precise position calculations or a higher-power servo machine. 

#include “Adafruit_APDS9960.h”
#include <ezButton.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();ezButton limitSwitch1(2);
ezButton limitSwitch2(5);#define servoMIN 150
#define servoMAX 600
#define MIN 600
#define MAX 1900
#define servoFREQ 50byte servoNum = 0;
int Num[] = {0, 1, 2, 3};
int sc[] = {1450, 1400, 1550};
//stand for:STOP,CCW,CWAdafruit_APDS9960 apds;
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);
Serial.println(“4 channel Servo test!”);
limitSwitch1.setDebounceTime(50);
limitSwitch2.setDebounceTime(50);

if (!apds.begin()) {
Serial.println(“failed to initialize device! Please check your wiring.”);
}
else Serial.println(“Device initialized!”);

//gesture mode will be entered once proximity mode senses something close
apds.enableProximity(true);
apds.enableGesture(true);

pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(servoFREQ);
delay(10);

for (int i = 0; i < 4; i++) {
pwm.writeMicroseconds(Num[i], MIN);
}
for (int i = 4; i < 7; i++) {
pwm.writeMicroseconds(i, 0);
}
}

// set the pulse length in second:
void setServoPulse(uint8_t n, float pulse) {
float pulselength;

pulselength = 1000000; // 1,000,000 us per second
pulselength /= servoFREQ; // Analog servos run at ~60 Hz updates
//Serial.print(pulselength); Serial.println(” us per period”);
pulselength /= 4096; // 12 bits of resolution
//Serial.print(pulselength); Serial.println(” us per bit”);
pulse *= 1000000; // convert input seconds to us
pulse /= pulselength;
//Serial.println(pulse);
pwm.setPWM(n, 0, pulse);
}

// the loop function runs over and over again forever
void loop() {
// CALL the loop() function first
limitSwitch1.loop();
limitSwitch2.loop();

int state1 = limitSwitch1.getState();
int state2 = limitSwitch2.getState();

//read a gesture from the device
uint8_t gesture = apds.readGesture();
if (gesture == APDS9960_DOWN) {
Serial.println(“v”);
//pwm.writeMicroseconds(6, 0);
}
if (gesture == APDS9960_UP) {
Serial.println(“^”);
//pwm.writeMicroseconds(6, 1300);
}

if (gesture == APDS9960_LEFT) {
Serial.println(“<“);
for (int servoNum = 0; servoNum < 4; servoNum++) {
for (uint16_t microsec = MIN; microsec <= MAX; microsec ++) {
pwm.writeMicroseconds(servoNum, microsec);
}
}

pwm.writeMicroseconds(4, 1325);
//pwm.writeMicroseconds(4, 1310);
}

if (gesture == APDS9960_RIGHT) {
Serial.println(“>”);
for (int servoNum = 3; servoNum >= 0; servoNum–) {
for (uint16_t microsec = MAX; microsec >= MIN; microsec –) {
pwm.writeMicroseconds(servoNum, microsec);
}
}

pwm.writeMicroseconds(4, 1225);
//pwm.writeMicroseconds(4, 1235);

}

//set 2 limit switch:
if (state1 == LOW) {
pwm.writeMicroseconds(4, 0);
//pwm.writeMicroseconds(5, 0);
Serial.println(“The limit switch1: TOUCHED”);
}

if (state2 == LOW) {
pwm.writeMicroseconds(4, 0);
//pwm.writeMicroseconds(5, 0);
Serial.println(“The limit switch2: TOUCHED”);
}
}

One thought on “Week 11 – Final(3) – Code

  1. Pingback: SHAN_Documentation | ITP Blog

Leave a Reply

Your email address will not be published. Required fields are marked *