Debug: Database connection successful Robotics Education Root Topic (Page 3) / Science, Technology, and Astronomy / New Mars Forums

Announcement

Announcement: This forum is accepting new registrations via email. Please see Recruiting Topic for additional information. Write newmarsmember[at_symbol]gmail.com.

#51 2026-08-25 15:17:02

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 25,696

Re: Robotics Education Root Topic

This post will hold V69 of Cokoino sketch ...

This version includes a new blinking red LED alert.

In working on the planning for a coordinated robot arm movement, we realized the arm may be in an unsuitable position when the request for forward movement is issued.  In that event, we are planning to run calculations to see if the requested movement is feasible given the starting coordinates of the arms. If the movement is not feasible, our current thinking is to stop the run and set the Cokoino board to blinking red. We will then require the operator to reset the Cokoino with the start button, and re-position the robot arm.

// CokoinoV69.ino Prepared by Gemini Supervised by Tom Hanson
// Version 69: Added non-blocking ERROR:OUT_OF_BOUNDS blinking red LED state.
// Version 68: Updated START token version string to V68.
// Version 62: No change except version number Note Ready: version
// Version 59: Updated version strings for V59 integration with Gated Telemetry handshake.
// Version 58: Introduced Gated Telemetry to completely eliminate analog line chatter.

#include <PS2X_lib.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN A1
#define LED_COUNT 4
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

PS2X ps2x;
int error = 0;
bool runtimeActive = false;

// --- GATED TELEMETRY STATE ---
bool analogEnabled = false; // Muted by default to keep the transmission pipe silent

// --- ERROR / ALARM STATE ---
bool isBlinkingError = false;
unsigned long lastBlinkTime = 0;
bool errorLedState = false;
const unsigned long BLINK_INTERVAL = 250; // 250ms toggle rate (4Hz blink)

void setLEDs(uint32_t c) {
  for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, c);
  strip.show();
}

void transmitToken(String token) {
  // Clearing error state on explicit user action/reset tokens
  if (token == "START Sketch Version V69" || token == "TRIANGLE" || token == "CIRCLE") {
    isBlinkingError = false;
  }

  if (!runtimeActive) {
    setLEDs(strip.Color(255, 150, 0)); // Yellow signal on key test
  }
  
  Serial.println(token);
  
  if (!runtimeActive) {
    delay(60); 
    setLEDs(strip.Color(0, 255, 0));   // Green = Standby
  }
}

void setup(){
  Serial.begin(9600);
  strip.begin();
  strip.setBrightness(40);
  strip.show(); 

  error = ps2x.config_gamepad(10, 12, 11, 13);
  if(error == 0) Serial.println("V69 Ready: Pass-Through Mode Enabled.");
}

void loop(){
  if(error != 0) return;
  
  ps2x.read_gamepad(false, 0);

  // ZONE 1: ANALOG STREAMING ENGINE (GATED PASS-THROUGH)
  if (analogEnabled) {
    int lx = ps2x.Analog(PSS_LX);
    int ly = ps2x.Analog(PSS_LY);
    int rx = ps2x.Analog(PSS_RX);
    int ry = ps2x.Analog(PSS_RY);
    
    // Smooth 0-255 pass-through active ONLY when steering mode is live
    if (abs(lx - 128) > 15) { Serial.print("ANALOG:LX:"); Serial.println(lx); }
    if (abs(ly - 128) > 15) { Serial.print("ANALOG:LY:"); Serial.println(ly); }
    if (abs(rx - 128) > 15) { Serial.print("ANALOG:RX:"); Serial.println(rx); }
    if (abs(ry - 128) > 15) { Serial.print("ANALOG:RY:"); Serial.println(ry); }
  }

  // ZONE 2: DIGITAL TRANSMISSION PIPE
  if(ps2x.ButtonPressed(PSB_TRIANGLE))  transmitToken("TRIANGLE");
  if(ps2x.ButtonReleased(PSB_TRIANGLE)) transmitToken("TRIANGLE RELEASED");
  if(ps2x.ButtonPressed(PSB_CIRCLE))    transmitToken("CIRCLE");
  if(ps2x.ButtonReleased(PSB_CIRCLE))   transmitToken("CIRCLE RELEASED");
  if(ps2x.ButtonPressed(PSB_CROSS))     transmitToken("CROSS");
  if(ps2x.ButtonReleased(PSB_CROSS))    transmitToken("CROSS RELEASED");
  if(ps2x.ButtonPressed(PSB_SQUARE))    transmitToken("SQUARE");
  if(ps2x.ButtonReleased(PSB_SQUARE))   transmitToken("SQUARE RELEASED");

  if(ps2x.ButtonPressed(PSB_START)) {
    runtimeActive = true; 
    transmitToken("START Sketch Version V69");
  }
  if(ps2x.ButtonPressed(PSB_SELECT))    transmitToken("SELECT");
  if(ps2x.ButtonReleased(PSB_SELECT))   transmitToken("SELECT RELEASED");

  if(ps2x.ButtonPressed(PSB_PAD_UP))     transmitToken("PAD UP");
  if(ps2x.ButtonReleased(PSB_PAD_UP))    transmitToken("PAD UP RELEASED");
  if(ps2x.ButtonPressed(PSB_PAD_DOWN))   transmitToken("PAD DOWN");
  if(ps2x.ButtonReleased(PSB_PAD_DOWN))  transmitToken("PAD DOWN RELEASED");
  if(ps2x.ButtonPressed(PSB_PAD_LEFT))   transmitToken("PAD LEFT");
  if(ps2x.ButtonReleased(PSB_PAD_LEFT))  transmitToken("PAD LEFT RELEASED");
  if(ps2x.ButtonPressed(PSB_PAD_RIGHT))  transmitToken("PAD RIGHT");
  if(ps2x.ButtonReleased(PSB_PAD_RIGHT)) transmitToken("PAD RIGHT RELEASED");

  if(ps2x.ButtonPressed(PSB_L1))        transmitToken("TOOL ADVANCE");
  if(ps2x.ButtonReleased(PSB_L1))       transmitToken("TOOL ADVANCE RELEASED");
  if(ps2x.ButtonPressed(PSB_L2))        transmitToken("TOOL RETRACT");
  if(ps2x.ButtonReleased(PSB_L2))       transmitToken("TOOL RETRACT RELEASED");
  if(ps2x.ButtonPressed(PSB_R1))        transmitToken("READY POSITION");
  if(ps2x.ButtonReleased(PSB_R1))       transmitToken("READY POSITION RELEASED");
  if(ps2x.ButtonPressed(PSB_R2))        transmitToken("SYSTEM HOME");
  if(ps2x.ButtonReleased(PSB_R2))       transmitToken("SYSTEM HOME RELEASED");

  if(ps2x.ButtonPressed(PSB_L3))        transmitToken("STICK CLICK LEFT");
  if(ps2x.ButtonReleased(PSB_L3))       transmitToken("STICK CLICK LEFT RELEASED");
  if(ps2x.ButtonPressed(PSB_R3))        transmitToken("STICK CLICK RIGHT");
  if(ps2x.ButtonReleased(PSB_R3))       transmitToken("STICK CLICK RIGHT RELEASED");

  // ZONE 3: INCOMING SERIAL LISTENER (LIGHTING & TELEMETRY CONTROL)
  if (Serial.available() > 0) {
    String rcved = Serial.readStringUntil('\n');
    rcved.trim();
    
    // Telemetry Gate Control Commands
    if (rcved == "ANALOG:ENABLE") {
      analogEnabled = true;
    }
    else if (rcved == "ANALOG:DISABLE") {
      analogEnabled = false;
    }
    // Error / Alarm Signal
    else if (rcved == "ERROR:OUT_OF_BOUNDS") {
      isBlinkingError = true;
      lastBlinkTime = millis();
      errorLedState = true;
      setLEDs(strip.Color(255, 0, 0));
    }
    // Existing LED commands
    else if (rcved.startsWith("LED:LOCK:")) {
      isBlinkingError = false;
      char hexChar = rcved.charAt(9);
      int count = (hexChar >= 'A') ? (hexChar - 'A' + 10) : (hexChar - '0');
      
      uint32_t activeColor   = strip.Color(0, 0, 255);
      uint32_t inactiveColor = strip.Color(10, 10, 10);

      strip.setPixelColor(3, (count & 1) ? activeColor : inactiveColor);
      strip.setPixelColor(2, (count & 2) ? activeColor : inactiveColor);
      strip.setPixelColor(1, (count & 4) ? activeColor : inactiveColor);
      strip.setPixelColor(0, (count & 8) ? activeColor : inactiveColor);
      strip.show();
    }
    else if (rcved == "LED:STATE:GREEN") {
      isBlinkingError = false;
      setLEDs(strip.Color(0, 255, 0)); 
    }
  }

  // ZONE 4: NON-BLOCKING BLINK ENGINE
  if (isBlinkingError) {
    unsigned long currentMillis = millis();
    if (currentMillis - lastBlinkTime >= BLINK_INTERVAL) {
      lastBlinkTime = currentMillis;
      errorLedState = !errorLedState;
      if (errorLedState) {
        setLEDs(strip.Color(255, 0, 0));
      } else {
        setLEDs(strip.Color(0, 0, 0));
      }
    }
  }
  
  delay(40);
}

(th)

Offline

Like button can go here

Board footer

Powered by FluxBB