u/Appropriate_Party514

E2 Cyrene worth it?

I’m currently planning on getting e2 Phainon whenever he comes and am wondering if e2 Cyrene will also be worth it. Especially since she’d work in both my e2 castorice and e2 Phainon teams as well as be able to fit into some others. Do you think she worth investing into more?

u/Appropriate_Party514 — 5 days ago

Hello! I don’t have much experience with these things but I’m currently tasked with making an autonomous car that can navigate a maze. I’m using an arduino uno r3. The current idea is to have ultrasonic distance sensors on the front, left, and right side. With the two back wheels powered by sg90 continuous servos. And the turning would be done by making one wheel forwards and back. It works perfect in tinkercad but when I actually wire it up, the servos just spin 0.5 seconds back and forth randomly, not even above 10 degrees. I don’t know how to fix it and I’d love if someone who knew more than me helped out!

Here is my code:

/*
 * Autonomous Maze Navigation Car
 * Hardware: Arduino Uno R3, MG90 Continuous Rotation Servos, HC-SR04 Ultrasonic Sensors
 * Steering Method: Differential wheel speed (fixed front axle)
 * 
 * Pin Layout:
 *  - Left Servo:         Pin 9
 *  - Right Servo:        Pin 10
 *  - Front Sensor TRIG:  Pin 2  | ECHO: Pin 3
 *  - Left  Sensor TRIG:  Pin 4  | ECHO: Pin 5
 *  - Right Sensor TRIG:  Pin 6  | ECHO: Pin 7
 */

#include <Servo.h>

// ── Servo objects ───────────────────────────────────────────────────────────
Servo leftServo;
Servo rightServo;

// ── Pin Definitions ─────────────────────────────────────────────────────────
const int LEFT_SERVO_PIN  = 9;
const int RIGHT_SERVO_PIN = 10;

const int FRONT_TRIG = 2,  FRONT_ECHO = 3;
const int LEFT_TRIG  = 4,  LEFT_ECHO  = 5;
const int RIGHT_TRIG = 6,  RIGHT_ECHO = 7;

// ── Servo Speed Values (MG90 Continuous) ────────────────────────────────────
// writeMicroseconds: 1500 = stop | 1000 = full CW | 2000 = full CCW
// Because servos are mounted mirrored, "forward" is opposite for each side.
const int STOP        = 1500;
const int L_FORWARD   = 1700;   // Left servo forward
const int L_BACKWARD  = 1300;   // Left servo backward
const int R_FORWARD   = 1300;   // Right servo forward (mirrored mount)
const int R_BACKWARD  = 1700;   // Right servo backward

// ── Distance Thresholds (cm) ─────────────────────────────────────────────────
const int WALL_FRONT  = 15;   // Stop & turn if front wall is this close
const int WALL_SIDE   = 12;   // Side wall detected threshold
const int IDEAL_SIDE  = 8;    // Ideal distance from side wall (for centering)

// ── Timing ───────────────────────────────────────────────────────────────────
const int TURN_90_MS  = 650;   // Milliseconds to spin ~90°. TUNE THIS per surface.
const int TURN_180_MS = 1300;  // Milliseconds for 180° U-turn

// ============================================================================
void setup() {
  Serial.begin(9600);

  leftServo.attach(LEFT_SERVO_PIN);
  rightServo.attach(RIGHT_SERVO_PIN);
  stopMotors();

  pinMode(FRONT_TRIG, OUTPUT); pinMode(FRONT_ECHO, INPUT);
  pinMode(LEFT_TRIG,  OUTPUT); pinMode(LEFT_ECHO,  INPUT);
  pinMode(RIGHT_TRIG, OUTPUT); pinMode(RIGHT_ECHO, INPUT);

  delay(2000); // Brief pause before starting
  Serial.println("Maze navigation started.");
}

// ============================================================================
/*
 * LEFT-HAND WALL FOLLOWING MAZE SOLVER
 * Rule: Always prioritize turning left. If left is blocked,
 *       go straight. If straight is blocked, turn right.
 *       If all blocked, U-turn. (Priority: Left > Straight > Right > U-turn)
 */

void loop() {
  int distFront = getDistance(FRONT_TRIG, FRONT_ECHO);
  int distLeft  = getDistance(LEFT_TRIG,  LEFT_ECHO);
  int distRight = getDistance(RIGHT_TRIG, RIGHT_ECHO);

  Serial.print("F:"); Serial.print(distFront);
  Serial.print(" L:"); Serial.print(distLeft);
  Serial.print(" R:"); Serial.println(distRight);

  bool frontOpen = (distFront > WALL_FRONT);
  bool leftOpen  = (distLeft  > WALL_SIDE);

  // ── Left-Hand Rule Priority: Left > Straight > Right > U-turn ──────────
  if (leftOpen) {
// Left is open — we MUST follow it (left hand lost the wall)
stopMotors();
delay(100);
turnLeft90();
// Drive forward a bit to clear the junction before sensing again
driveForward();
delay(300);

  } else if (frontOpen) {
// Left is wall, front is open — hug the left wall and go straight
driveWithCorrection(distLeft, distRight);

  } else {
// Left and front are both blocked
stopMotors();
delay(100);
int distRightNow = getDistance(RIGHT_TRIG, RIGHT_ECHO);
if (distRightNow > WALL_SIDE) {
turnRight90();        // Dead end on left+front, open right
} else {
turnAround();         // Full dead end — U-turn
}
  }

  delay(50);
}

// ============================================================================
//  MOVEMENT FUNCTIONS
// ============================================================================

void driveForward() {
  leftServo.writeMicroseconds(L_FORWARD);
  rightServo.writeMicroseconds(R_FORWARD);
}

void stopMotors() {
  leftServo.writeMicroseconds(STOP);
  rightServo.writeMicroseconds(STOP);
}

// ── Gentle correction to keep the car centered between walls ─────────────────
void driveWithCorrection(int distLeft, int distRight) {
  bool hasLeftWall  = (distLeft  < WALL_SIDE);
  bool hasRightWall = (distRight < WALL_SIDE);

  if (hasLeftWall && hasRightWall) {
// Corridor: center between both walls
int error = distLeft - distRight; // Positive = drifting right, negative = left

if (error > 3) {
// Too close to right wall — nudge left (slow right motor slightly)
leftServo.writeMicroseconds(L_FORWARD);
rightServo.writeMicroseconds(R_FORWARD - 80);
} else if (error < -3) {
// Too close to left wall — nudge right (slow left motor slightly)
leftServo.writeMicroseconds(L_FORWARD - 80);
rightServo.writeMicroseconds(R_FORWARD);
} else {
driveForward();
}

  } else if (hasRightWall) {
// Only right wall — maintain ideal gap from it
int error = distRight - IDEAL_SIDE;
if (error < -2) {
// Too close to right — nudge left
leftServo.writeMicroseconds(L_FORWARD);
rightServo.writeMicroseconds(R_FORWARD - 80);
} else if (error > 2) {
// Drifting away from right — nudge right
leftServo.writeMicroseconds(L_FORWARD - 80);
rightServo.writeMicroseconds(R_FORWARD);
} else {
driveForward();
}

  } else if (hasLeftWall) {
// Only left wall — maintain ideal gap from it
int error = distLeft - IDEAL_SIDE;
if (error < -2) {
// Too close to left — nudge right
leftServo.writeMicroseconds(L_FORWARD - 80);
rightServo.writeMicroseconds(R_FORWARD);
} else if (error > 2) {
// Drifting away from left — nudge left
leftServo.writeMicroseconds(L_FORWARD);
rightServo.writeMicroseconds(R_FORWARD - 80);
} else {
driveForward();
}

  } else {
// No walls detected — drive straight
driveForward();
  }
}

// ── Sharp 90° turns using pivot (one wheel forward, one backward) ─────────────
void turnLeft90() {
  Serial.println(">> Turning LEFT 90");
  // Pivot: right wheel forward, left wheel backward
  leftServo.writeMicroseconds(L_BACKWARD);
  rightServo.writeMicroseconds(R_FORWARD);
  delay(TURN_90_MS);
  stopMotors();
  delay(150);
}

void turnRight90() {
  Serial.println(">> Turning RIGHT 90");
  // Pivot: left wheel forward, right wheel backward
  leftServo.writeMicroseconds(L_FORWARD);
  rightServo.writeMicroseconds(R_BACKWARD);
  delay(TURN_90_MS);
  stopMotors();
  delay(150);
}

void turnAround() {
  Serial.println(">> U-Turn 180");
  // Pivot in same direction as a right turn, doubled time
  leftServo.writeMicroseconds(L_FORWARD);
  rightServo.writeMicroseconds(R_BACKWARD);
  delay(TURN_180_MS);
  stopMotors();
  delay(150);
}

// ============================================================================
//  ULTRASONIC SENSOR — Returns distance in cm. Returns 999 if out of range.
// ============================================================================
int getDistance(int trigPin, int echoPin) {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH, 30000); // 30ms timeout (~500cm max)

  if (duration == 0) return 999; // No echo = open space

  int distance = duration * 0.034 / 2;
  return distance;
}

reddit.com
u/Appropriate_Party514 — 6 days ago
▲ 6 r/HonkaiStarRailTips+1 crossposts

I tried a couple things but nothings really working for me this time around. My castorice team is clearing either side fine but my phainons failing me. Any tips or opinions are much appreciated!

u/Appropriate_Party514 — 17 days ago