#include <Arduino.h>
#include <zirconLib.h>
#define LINE_THRESHOLD 650
#define MOTOR_POWER 140
#define BALL_CALIBRATION_X 0
#define BALL_CALIBRATION_Y 0
// utils
struct Vector2D {
float x;
float y;
// Default constructor
Vector2D() : x(0), y(0) {}
// Parameterized constructor
Vector2D(float x, float y) : x(x), y(y) {}
// Method to convert the vector to a string
String toString() const {
return "(" + String(x) + ", " + String(y) + ")";
}
// Method to print the vector
void print() const {
Serial.println(toString());
}
};
// Directions for sensors arranged clockwise from front
const float angles[8] = {
M_PI / 2, M_PI / 4, 0, -M_PI / 4,
-M_PI / 2, -3 * M_PI / 4, -M_PI, 3 * M_PI / 4
};
// Function to read ball sensors and compute the resulting direction vector
Vector2D readBallSensors() {
float sensorValues[8];
// Read sensor values
for (int i = 0; i < 8; i++) {
sensorValues[i] = readBall(i + 1); // Assuming readBall takes sensor ID 1 to 8
}
Vector2D result;
// Sum the directions weighted by sensor values
for (int i = 0; i < 8; i++) {
result.x += sensorValues[i] * cos(angles[i]);
result.y += sensorValues[i] * sin(angles[i]);
}
return result;
}
void moveMotors(const Vector2D& direction, float rotationFactor) {
float angle = atan2(direction.y, direction.x);
// Serial.println("angle " + String(180*angle/M_PI));
// Calculate motor powers (assuming 3 omni-directional wheels)
float motor1Power = MOTOR_POWER*max(min(sin(angle - 5*M_PI/6) + rotationFactor, 1), -1);
float motor2Power = MOTOR_POWER*max(min(sin(angle - 1*M_PI/6) + rotationFactor, 1), -1);
float motor3Power = MOTOR_POWER*max(min(sin(angle - 9*M_PI/6) + rotationFactor, 1), -1);
// Convert the powers to suitable PWM values and set motor directions
motor1(abs(motor1Power), motor1Power < 0 ? 1 : 0);
motor2(abs(motor2Power), motor2Power < 0 ? 1 : 0);
motor3(abs(motor3Power), motor3Power < 0 ? 1 : 0);
}
int goalAngle = 0;
void setup(void)
{
Serial.begin(115200);
InitializeZircon();
motor1(50, 0);
delay(500);
motor1(0,0);
while (readButton(1) == 0) {
goalAngle = readCompass();
}
}
float move_angle_from_default;
Vector2D moveVector = Vector2D(0, 0);
Vector2D ballVector;
void loop(void)
{
// read ball sensors
ballVector = readBallSensors();
Serial.println("ball vector: " + ballVector.toString());
// adjust ball detection for calibration
ballVector.x += BALL_CALIBRATION_X;
ballVector.y += BALL_CALIBRATION_Y;
int compassDiff = readCompass() - goalAngle;
if (compassDiff > 180) {
compassDiff -= 360;
} else if (compassDiff < -180) {
compassDiff += 360;
}
Serial.println("ball vector: " + ballVector.toString()
+ " line sensor 1: " + String(readLine(1))
+ " line sensor 2: " + String(readLine(2))
+ " line sensor 3: " + String(readLine(3))
);
if (readLine(1) > LINE_THRESHOLD) {
motor1(MOTOR_POWER, 0);
motor2(MOTOR_POWER, 1);
motor3(0, 0);
} else if (readLine(2) > LINE_THRESHOLD) {
motor1(0, 0);
motor2(MOTOR_POWER, 0);
motor3(MOTOR_POWER, 1);
} else if (readLine(3) > LINE_THRESHOLD) {
motor1(MOTOR_POWER, 1);
motor2(0, 0);
motor3(MOTOR_POWER, 0);
} else {
// orbit
float angle = atan2(ballVector.y, ballVector.x);
if (angle > M_PI) {
angle -= M_PI;
} else if (angle < -M_PI) {
angle += M_PI;
}
float angle_from_front = angle - M_PI/2;
float orbit_addition = min(M_PI/2, M_PI*(0.04f * pow(M_E, 0.12f * abs(180*angle_from_front/M_PI)))/180);
float ball_vec_magnitude = sqrt(ballVector.x * ballVector.x + ballVector.y * ballVector.y);
float dampened_orbit_addition = orbit_addition * max(1.0, 0.04f * pow(M_E, 0.002f * (ball_vec_magnitude - 100)));
if (angle_from_front < 0) {
dampened_orbit_addition *= -1;
}
move_angle_from_default = angle_from_front + dampened_orbit_addition + M_PI/2;
moveVector.x = 0.01 * cos(move_angle_from_default) + 0.9 * moveVector.x;
moveVector.y = 0.01 * sin(move_angle_from_default) + 0.99 * moveVector.x;
if (ball_vec_magnitude < 300) {
motor1(0,0);
motor2(0,0);
motor3(0,0);
} else {
moveMotors(moveVector, compassDiff/180.0);
}
}
}