Debug: Database connection successful Arduino / Science, Technology, and Astronomy / New Mars Forums

You are not logged in.

Announcement

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

#1 2025-11-01 13:38:47

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Arduino

For SpaceNut ... we do not appear to have a topic for Arduino.

One of the robot kit vendors I am evaluating has designed their controller board to run Arduino code. 

There is a body of software for the Arduino, and one of the features is an IDE for development and deployment of Arduino Sketches.

Arduino IDE's are (apparently) also available for Microsoft Windows (I found one in Visual Studio 2022) and there appears to be one for Linux.

I expect that there is one for Apple as well.

(th)

Offline

Like button can go here

#2 2025-11-01 13:40:08

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post is reserved for an index to posts that may be contributed by NewMars members.

Index:
Post #3: Link to YouTube video about an Arduino emulator that runs on Linux that includes a segment on how to upload a Sketch to an Arduino board.

(th)

Offline

Like button can go here

#3 2025-11-01 13:41:10

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post contains a link to a YouTube video about an Arduino emulator that runs on Linux.

https://www.youtube.com/watch?v=qAM2S27FWAI

Apparently the video shows how to upload a .hex file to an Arduino board.

(th)

Offline

Like button can go here

#4 2026-05-17 12:58:58

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post contains an Arduino Sketch for the Cokoino circuit board fitted with a PS/2 wired game controller.

This particular sketch is designed to test the PS/2, as modified by Gemini to begin the process of controlling a LynxMotion robot arm.

#include <PS2X_lib.h>

PS2X ps2x;
int error = 0;
byte vibrate = 0;

// --- THE STATE DATABASE ---
// Indices: 0:Base, 1:Shoulder, 2:Elbow, 3:Wrist, 4:Gripper
int robotState[5] = {1500, 1500, 1500, 1500, 1500}; 
int stepSize = 20; // How fast the arm moves per loop

void setup(){
  // UPDATED to 9600 for LynxMotion compatibility
  Serial.begin(9600); 

  // GamePad(clock, command, attention, data) pins
  error = ps2x.config_gamepad(10,12,11,13); 
  
  if(error == 0) Serial.println("Robot Control System Ready");
}

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

  // --- HOME COMMAND (START BUTTON) ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Returning to HOME position...");
    for(int i=0; i<5; i++) {
      robotState[i] = 1500;
    }
    sendCommands();
  }

  // --- EXAMPLE MOVEMENT (PAD UP/DOWN for SHOULDER) ---
  // We check the array limits (500 to 2500) so we don't "break" the arm
  if(ps2x.Button(PSB_PAD_UP)) {
    if(robotState[1] < 2500) robotState[1] += stepSize;
    sendCommands();
  }
  if(ps2x.Button(PSB_PAD_DOWN)) {
    if(robotState[1] > 500) robotState[1] -= stepSize;
    sendCommands();
  }

  // --- ANALOG REPORTING (L1 HELD) ---
  if(ps2x.Button(PSB_L1)){
    Serial.print("Current State: ");
    for(int i=0; i<5; i++) {
      Serial.print(robotState[i]);
      Serial.print(" ");
    }
    Serial.println();
  }

  delay(50); // Controls the "speed" of the movement increments
}

// --- COMMAND GENERATOR ---
// This builds the strings for the LynxMotion controller
void sendCommands() {
  // Format: #<channel>P<pulse>
  // Channel 0 = Base, 1 = Shoulder, etc.
  for(int i=0; i<5; i++) {
    Serial.print("#");
    Serial.print(i);
    Serial.print("P");
    Serial.print(robotState[i]);
    Serial.print(" "); // Space between commands
  }
  Serial.println(); // Ends the string with a Carriage Return
}

The purpose of the posting is to facilitate transfer of this code from Windows 7 to Raspberry Pi 5 running Bookworm Linux.

The issue is line termination. Microsoft uses both a carriage return and a line feed, and Linux uses just Return to signal end-of-line. The bookkeeping is handled automatically by the cloud interface.

Update: The sketch loaded on the RP5 but it needs libraries. The link below pulls the libraries.
https://www.dropbox.com/scl/fi/m6q1ro1a … d6lix&dl=0
(th)

Offline

Like button can go here

#5 2026-05-17 16:35:59

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post is to show activity occurring in the Cokoino Board as the PS/2 controller is operated. 

Robot Control System Ready
Current State: 1500 1500 1500 1500 1500
Current State: 1500 1500 1500 1500 1500
Current State: 1500 1500 1500 1500 1500
#0P1500 #1P1520 #2P1500 #3P1500 #4P1500
#0P1500 #1P1540 #2P1500 #3P1500 #4P1500
#0P1500 #1P1560 #2P1500 #3P1500 #4P1500
#0P1500 #1P1540 #2P1500 #3P1500 #4P1500
#0P1500 #1P1520 #2P1500 #3P1500 #4P1500
#0P1500 #1P1500 #2P1500 #3P1500 #4P1500
Returning to HOME position...
#0P1500 #1P1500 #2P1500 #3P1500 #4P1500
Current State: 1500 1500 1500 1500 1500
Current State: 1500 1500 1500 1500 1500
Current State: 1500 1500 1500 1500 1500
#0P1500 #1P1520 #2P1500 #3P1500 #4P1500
#0P1500 #1P1540 #2P1500 #3P1500 #4P1500
#0P1500 #1P1560 #2P1500 #3P1500 #4P1500
#0P1500 #1P1540 #2P1500 #3P1500 #4P1500
#0P1500 #1P1520 #2P1500 #3P1500 #4P1500
#0P1500 #1P1500 #2P1500 #3P1500 #4P1500
#0P1500 #1P1480 #2P1500 #3P1500 #4P1500
Returning to HOME position...
#0P1500 #1P1500 #2P1500 #3P1500 #4P1500

Only a few buttons are programmed at this point. The numbers shown in the display are positions of the servos in the robot arm. 1500 is midrange.  Values less than 1500 are counter clockwise. Values greater than 1500 are clockwise.

(th)

Offline

Like button can go here

#6 2026-05-18 14:00:46

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

SearchTerm:PS/2 game controller

This post is about the buttons and controls available on the PS/2 game controller.  Google found a Wikipedia page on the subject.

AI Overview
The standard PlayStation 2 (DualShock 2) controller features 17 inputs: 4 face buttons, 4 D-Pad directions, 4 shoulder buttons, 2 clickable analog sticks, and 3 functional buttons.
Face & Directional Buttons (Pressure-Sensitive)
All 12 of these inputs feature 256 levels of pressure-sensitivity:

    Cross
    (often referred to as 'X')
    Circle
    Square
    Triangle
    D-Pad Up
    D-Pad Right
    D-Pad Down
    D-Pad Left
     

Shoulder Buttons (Pressure-Sensitive)
Like the face buttons, these 4 triggers and bumpers register how hard you squeeze them:

    L1 (Front left bumper)
    L2 (Back left trigger)
    R1 (Front right bumper)
    R2 (Back right trigger)

Analog Sticks & Functional Buttons
These buttons act as standard digital switches:

    L3 (Left analog stick click/depress)
    R3 (Right analog stick click/depress)
    Start
    Select
    Analog (Toggles the analog sticks on/off and enables/disables the red indicator light)

By inspection, I count 16 controls and one switch that is marked "Analog".
By re-reading the Wikipedia quote, I understand that two buttons I thought were controls are called "functional" buttons.
(th)

Offline

Like button can go here

#7 2026-05-18 15:06:03

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

In this post, we show an Arduino sketch to test the behavior of the game controller.  I am using a clone of the PS/2, and it may not support all the features of the original PlayStation device.  This sketch will watch the inputs from the shoulder buttons.

#include <PS2X_lib.h>

PS2X ps2x;
int error = 0;

void setup() {
  Serial.begin(9600);
  // Using the pins we verified on your Cokoino board yesterday
  error = ps2x.config_gamepad(13, 11, 10, 12, true, true); 
  
  if(error == 0) Serial.println("Diagnostic Tool Ready. Squeeze L1 and L2.");
}

void loop() {
  ps2x.read_gamepad(false, 0); // Read the controller
  
  // We are specifically checking the "analog" value of the buttons
  int L1_Value = ps2x.Analog(PSAB_L1);
  int L2_Value = ps2x.Analog(PSAB_L2);

  if (L1_Value > 0 || L2_Value > 0) {
    Serial.print("L1 Pressure: "); Serial.print(L1_Value);
    Serial.print(" | L2 Pressure: "); Serial.println(L2_Value);
  }
  
  delay(50); // Small delay to make the monitor readable
}

If the clone is minimal, we will only see 0 and 255 as outputs.

(th)

Offline

Like button can go here

#8 2026-05-20 14:39:21

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

It is taking longer than I had hoped to learn how to program sketches for the Arduino Cokoino board.  The code below is to be added to a test program to see if we can figure out how to light the four LED lights that are part of the board.

// Assuming your LEDs are on Pin 6 - adjust if your board uses Pin 4
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pixels(4, 6, NEO_GRB + NEO_KHZ800); 

void setup() {
  pixels.begin();
  pixels.setPixelColor(0, pixels.Color(255, 0, 0)); // Red
  pixels.setPixelColor(1, pixels.Color(0, 255, 0)); // Green
  pixels.show(); 
  // ... rest of your setup
}

(th)

Offline

Like button can go here

#9 2026-05-20 17:27:31

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

In this test sketch we will attempt to discover how to activate LED's.

// Version 4: Integrated PS/2 Logic with L1 LED Probe
#include <PS2X_lib.h>
#include <Adafruit_NeoPixel.h>

// Standard Cokoino NeoPixel Pin is 4
Adafruit_NeoPixel pixels(4, 4, NEO_GRB + NEO_KHZ800); 

PS2X ps2x;
int error = 0;
byte vibrate = 0;

// --- THE STATE DATABASE ---
int robotState[5] = {1500, 1500, 1500, 1500, 1500}; 
int stepSize = 20; 

void setup(){
  Serial.begin(9600); 
  
  // Initialize the pixels but keep them OFF initially
  pixels.begin();
  pixels.show(); 

  // GamePad(clock, command, attention, data) 
  // Using the pins verified in your previous test
  error = ps2x.config_gamepad(10, 12, 11, 13); 
  
  if(error == 0) Serial.println("Robot Control System Ready - V4");
}

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

  // --- HOME COMMAND (START BUTTON) ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Returning to HOME position...");
    for(int i=0; i<5; i++) {
      robotState[i] = 1500;
    }
    sendCommands();
  }

  // --- ANALOG REPORTING & LED PROBE (L1 BUTTON) ---
  // If L1 is held, LEDs turn White. If released, they turn Off.
  if(ps2x.Button(PSB_L1)){
    for(int i=0; i<4; i++) {
      pixels.setPixelColor(i, pixels.Color(255, 255, 255)); 
    }
    pixels.show();

    Serial.print("Current State: ");
    for(int i=0; i<5; i++) {
      Serial.print(robotState[i]);
      Serial.print(" ");
    }
    Serial.println();
  } else {
    // Turn LEDs OFF when button is not pressed
    for(int i=0; i<4; i++) {
      pixels.setPixelColor(i, pixels.Color(0, 0, 0)); 
    }
    pixels.show();
  }

  // --- MOVEMENT (PAD UP/DOWN) ---
  if(ps2x.Button(PSB_PAD_UP)) {
    if(robotState[1] < 2500) robotState[1] += stepSize;
    sendCommands();
  }
  if(ps2x.Button(PSB_PAD_DOWN)) {
    if(robotState[1] > 500) robotState[1] -= stepSize;
    sendCommands();
  }

  delay(50); 
}

void sendCommands() {
  for(int i=0; i<5; i++) {
    Serial.print("#");
    Serial.print(i);
    Serial.print("P");
    Serial.print(robotState[i]);
    Serial.print(" ");
  }
  Serial.println(); 
}

(th)

Offline

Like button can go here

#10 2026-05-20 17:48:46

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This is the Cokoino LED test sketch, which I hope will help us understand why our test code is not working.

/*****************************************************
 
 * This code applies to Arduino 6DOF Metal Arm Kit
 * Through this link you can download the source code:
 * https://github.com/Cokoino/CKK0017
 
*****************************************************/
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define WS2812_PIN A1   //WS2812 PIN
#define WS2812_COUNT  4  // How many NeoPixels are attached to the Arduino?
#define BRIGHTNESS 6  // NeoPixel brightness, 0 (min) to 255 (max)
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip = Adafruit_NeoPixel(WS2812_COUNT, WS2812_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)

///////////////////////////////////////////////////////////////////////////////////
void setup()
{
  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
 // #if defined (__AVR_ATtiny85__)
    //if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  //#endif        // END of Trinket-specific code.
  strip.begin();// INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show(); // Turn OFF all pixels ASAP
  strip.setBrightness(BRIGHTNESS);
}
///////////////////////////////////////////////////////////////////////////////////
void loop()
{
  // Fill along the length of the strip in various colors...
  colorWipe(strip.Color(255, 0, 0), 6); // Red
  delay(800);
  //colorWipe(strip.Color(255, 150, 0), 6); // yellow
  //delay(800);
  colorWipe(strip.Color(0, 255, 0), 6); // Green
  delay(800);
  //colorWipe(strip.Color(0, 255, 255), 6); // CYAN
  //delay(800);
  colorWipe(strip.Color(0, 0, 255), 6); // Blue
  delay(800);
  //colorWipe(strip.Color(180, 0, 255), 6); // purple
  //delay(800);
  colorWipe(strip.Color(127, 127, 127), 6); // White
  delay(800);
  //colorWipe(strip.Color(0, 0, 0), 0); // Clear
}

void colorWipe(uint32_t c, uint8_t wait) 
{
  for(uint16_t i=0; i<strip.numPixels(); i++) {// For each pixel in strip...
    strip.setPixelColor(i, c);                 //  Set pixel's color (in RAM)
    strip.show();                              //  Update strip to match
    delay(wait);                               //  Pause for a moment
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) 
{
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();
      delay(wait);
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
       }
     }
   }
 }

(th)

Offline

Like button can go here

#11 2026-05-20 17:57:43

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

And here is the revised test program.  The key information provided by the tutorial use of the Analog 1 pin for the color commands.

/*****************************************************
 
 * This code applies to Arduino 6DOF Metal Arm Kit
 * Through this link you can download the source code:
 * https://github.com/Cokoino/CKK0017
 
*****************************************************/
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define WS2812_PIN A1   //WS2812 PIN
#define WS2812_COUNT  4  // How many NeoPixels are attached to the Arduino?
#define BRIGHTNESS 6  // NeoPixel brightness, 0 (min) to 255 (max)
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip = Adafruit_NeoPixel(WS2812_COUNT, WS2812_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)

///////////////////////////////////////////////////////////////////////////////////
void setup()
{
  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
 // #if defined (__AVR_ATtiny85__)
    //if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  //#endif        // END of Trinket-specific code.
  strip.begin();// INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show(); // Turn OFF all pixels ASAP
  strip.setBrightness(BRIGHTNESS);
}
///////////////////////////////////////////////////////////////////////////////////
void loop()
{
  // Fill along the length of the strip in various colors...
  colorWipe(strip.Color(255, 0, 0), 6); // Red
  delay(800);
  //colorWipe(strip.Color(255, 150, 0), 6); // yellow
  //delay(800);
  colorWipe(strip.Color(0, 255, 0), 6); // Green
  delay(800);
  //colorWipe(strip.Color(0, 255, 255), 6); // CYAN
  //delay(800);
  colorWipe(strip.Color(0, 0, 255), 6); // Blue
  delay(800);
  //colorWipe(strip.Color(180, 0, 255), 6); // purple
  //delay(800);
  colorWipe(strip.Color(127, 127, 127), 6); // White
  delay(800);
  //colorWipe(strip.Color(0, 0, 0), 0); // Clear
}

void colorWipe(uint32_t c, uint8_t wait) 
{
  for(uint16_t i=0; i<strip.numPixels(); i++) {// For each pixel in strip...
    strip.setPixelColor(i, c);                 //  Set pixel's color (in RAM)
    strip.show();                              //  Update strip to match
    delay(wait);                               //  Pause for a moment
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) 
{
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();
      delay(wait);
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
       }
     }
   }
 }

(th)

Offline

Like button can go here

#12 2026-05-21 10:25:02

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This code is Version 5 of the Simple PS/2 test, with LED lighting added...

// Version 5: Factory-Aligned Pin Mapping (A1)
#include <PS2X_lib.h>
#include <Adafruit_NeoPixel.h>

// FACTORY CORRECT PIN: A1
#define LED_PIN A1
#define LED_COUNT 4
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

PS2X ps2x;
int error = 0;
byte vibrate = 0;

// --- THE STATE DATABASE ---
int robotState[5] = {1500, 1500, 1500, 1500, 1500}; 
int stepSize = 20; 

void setup(){
  Serial.begin(9600); 
  
  strip.begin();
  strip.setBrightness(60); // Set to a visible but safe level
  strip.show(); // Clear all pixels

  // Handshake with PS/2 Controller
  error = ps2x.config_gamepad(10, 12, 11, 13); 
  
  if(error == 0) Serial.println("Robot Control System Ready - V5 (A1 Alignment)");
}

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

  // --- ANALOG REPORTING & LED PROBE (L1 BUTTON) ---
  // If L1 is held, LEDs turn White. If released, they turn Off.
  if(ps2x.Button(PSB_L1)){
    for(int i=0; i<LED_COUNT; i++) {
      strip.setPixelColor(i, strip.Color(255, 255, 255)); 
    }
    strip.show();

    Serial.print("Current State: ");
    for(int i=0; i<5; i++) {
      Serial.print(robotState[i]);
      Serial.print(" ");
    }
    Serial.println();
  } else {
    // Return to "IDLE" State (Off)
    for(int i=0; i<LED_COUNT; i++) {
      strip.setPixelColor(i, strip.Color(0, 0, 0)); 
    }
    strip.show();
  }

  // --- HOME COMMAND (START BUTTON) ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Returning to HOME position...");
    for(int i=0; i<5; i++) {
      robotState[i] = 1500;
    }
    sendCommands();
  }

  // --- MOVEMENT (PAD UP/DOWN) ---
  if(ps2x.Button(PSB_PAD_UP)) {
    if(robotState[1] < 2500) robotState[1] += stepSize;
    sendCommands();
  }
  if(ps2x.Button(PSB_PAD_DOWN)) {
    if(robotState[1] > 500) robotState[1] -= stepSize;
    sendCommands();
  }

  delay(50); 
}

void sendCommands() {
  for(int i=0; i<5; i++) {
    Serial.print("#");
    Serial.print(i);
    Serial.print("P");
    Serial.print(robotState[i]);
    Serial.print(" ");
  }
  Serial.println(); 
}

(th)

Offline

Like button can go here

#13 2026-05-21 12:35:16

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post contains an update to the Analog test ... this is version 6 of the current series...

// Version 6: Analog Pressure Test with A1 LED Confirmation
#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;

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

  // CORRECTED PINS: Matching the working V5 setup
  error = ps2x.config_gamepad(10, 12, 11, 13, true, true); 
  
  if(error == 0) {
    Serial.println("V6 Diagnostic Ready. Squeeze L1 or L2 firmly.");
  } else {
    Serial.print("Controller Error: ");
    Serial.println(error);
  }
}

void loop() {
  if(error != 0) return;

  // We set "pressure" to true (second parameter) to enable analog reading
  ps2x.read_gamepad(false, 0); 
  
  int L1_Val = ps2x.Analog(PSAB_L1);
  int L2_Val = ps2x.Analog(PSAB_L2);

  // If we detect ANY pressure, we report it and light the LEDs
  if(L1_Val > 0 || L2_Val > 0) {
    Serial.print("L1 Pressure: ");
    Serial.print(L1_Val);
    Serial.print(" | L2 Pressure: ");
    Serial.println(L2_Val);

    // Light up BLUE to indicate we are in Analog mode
    for(int i=0; i<LED_COUNT; i++) {
      strip.setPixelColor(i, strip.Color(0, 0, 255)); 
    }
    strip.show();
  } else {
    for(int i=0; i<LED_COUNT; i++) {
      strip.setPixelColor(i, strip.Color(0, 0, 0)); 
    }
    strip.show();
  }
  
  delay(100); // Slowed down slightly for easier reading
}

(th)

Offline

Like button can go here

#14 2026-05-21 13:26:41

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post contains Version 6.1 of the PS 2 test series... We studied the libraries that support the PS/2, and Gemini identified the particular library we have available. Apparently that makes a subtle difference in how we pull data from the hardware.

// Version 6: Analog Pressure Test with A1 LED Confirmation
#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;

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

  // CORRECTED PINS: Matching the working V5 setup
  error = ps2x.config_gamepad(10, 12, 11, 13, true, true); 
  
  if(error == 0) {
    Serial.println("V6 Diagnostic Ready. Squeeze L1 or L2 firmly.");
  } else {
    Serial.print("Controller Error: ");
    Serial.println(error);
  }
}

void loop() {
  if(error != 0) return;

  // We set "pressure" to true (second parameter) to enable analog reading
  ps2x.read_gamepad(false, 0); 
  
  int L1_Val = ps2x.Analog(PSAB_L1);
  int L2_Val = ps2x.Analog(PSAB_L2);

  // If we detect ANY pressure, we report it and light the LEDs
  if(L1_Val > 0 || L2_Val > 0) {
    Serial.print("L1 Pressure: ");
    Serial.print(L1_Val);
    Serial.print(" | L2 Pressure: ");
    Serial.println(L2_Val);

    // Light up BLUE to indicate we are in Analog mode
    for(int i=0; i<LED_COUNT; i++) {
      strip.setPixelColor(i, strip.Color(0, 0, 255)); 
    }
    strip.show();
  } else {
    for(int i=0; i<LED_COUNT; i++) {
      strip.setPixelColor(i, strip.Color(0, 0, 0)); 
    }
    strip.show();
  }
  
  delay(100); // Slowed down slightly for easier reading
}

(th)

Offline

Like button can go here

#15 2026-05-21 14:19:17

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post contains Version 7 of the current series. We decided to fall back to a solid foundation, by using a demo program provided by Cokoino to test all the buttons in the PS/2 controller.

// Version 7.1: Clean Baseline for LynxMotion (9600 Baud)
#include <PS2X_lib.h>

PS2X ps2x;
int error = 0;
byte vibrate = 0;

// The State Database (0:Base, 1:Shoulder, 2:Elbow, 3:Wrist, 4:Gripper)
int robotState[5] = {1500, 1500, 1500, 1500, 1500};
int stepSize = 25; 

void setup(){
  Serial.begin(9600); // Corrected to 9600 for all connections
  
  // Setup GamePad(clock, command, attention, data)
  error = ps2x.config_gamepad(10, 12, 11, 13);
  
  if(error == 0){
    Serial.println("Found Controller, configured successful");
    Serial.println("System Ready for LynxMotion Commands at 9600 baud.");
  } else {
    Serial.print("Controller Error: ");
    Serial.println(error);
  }
}

void loop(){
  if(error != 0) return; 
  
  ps2x.read_gamepad(false, vibrate); 
  
  // --- UP/DOWN PAD: Shoulder Movement ---
  if(ps2x.Button(PSB_PAD_UP)) {
    if(robotState[1] < 2400) robotState[1] += stepSize;
    sendLynxCommands();
  }
  if(ps2x.Button(PSB_PAD_DOWN)) {
    if(robotState[1] > 600) robotState[1] -= stepSize;
    sendLynxCommands();
  }

  // --- START: Reset to Home ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Start Pressed: Homing Arm...");
    for(int i=0; i<5; i++) robotState[i] = 1500;
    sendLynxCommands();
  }

  // --- L1: Stick Reporting ---
  if(ps2x.Button(PSB_L1)){
    Serial.print("Sticks: ");
    Serial.print(ps2x.Analog(PSS_LX), DEC);
    Serial.print(",");
    Serial.println(ps2x.Analog(PSS_LY), DEC);
  }

  delay(50);
}

// Format: #<ch>P<pulse> ... <cr>
void sendLynxCommands() {
  for(int i=0; i<5; i++) {
    Serial.print("#");
    Serial.print(i);
    Serial.print("P");
    Serial.print(robotState[i]);
    Serial.print(" ");
  }
  Serial.println(); 
}

(th)

Offline

Like button can go here

#16 2026-05-21 14:46:00

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This version will be called 8, even thought the text shows 7.1.  We have made some progress today, despite a few setbacks.  We know how to operate the LED's, and we know which buttons are on/off and which have gradations from 0 to 255.

// Version 7.2: Shoulder Range Test + LED Pilot Light
#include <PS2X_lib.h>
#include <Adafruit_NeoPixel.h>

// Re-incorporating our verified LED pin
#define LED_PIN A1
#define LED_COUNT 4
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

PS2X ps2x;
int error = 0;

// State Database: [0]Base, [1]Shoulder, [2]Elbow, [3]Wrist, [4]Gripper
int robotState[5] = {1500, 1500, 1500, 1500, 1500};
int stepSize = 15; // Slightly smaller for better precision

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

  error = ps2x.config_gamepad(10, 12, 11, 13);
  
  if(error == 0) Serial.println("V7.2 Ready: Testing Shoulder Range (PAD UP/DOWN)");
}

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

  // --- SHOULDER MOVEMENT (PAD UP/DOWN) ---
  if(ps2x.Button(PSB_PAD_UP)) {
    if(robotState[1] < 2400) {
      robotState[1] += stepSize;
      moving = true;
    }
  }
  if(ps2x.Button(PSB_PAD_DOWN)) {
    if(robotState[1] > 600) {
      robotState[1] -= stepSize;
      moving = true;
    }
  }

  // --- LED PILOT LIGHT ---
  // If moving, turn LEDs Green. If not, turn them Off.
  if(moving) {
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 255, 0));
    strip.show();
    sendLynxCommands(); // Only send data when something changes
  } else {
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 0, 0));
    strip.show();
  }

  // --- START: Reset to Home ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Homing Arm...");
    for(int i=0; i<5; i++) robotState[i] = 1500;
    sendLynxCommands();
  }

  delay(30); // Faster refresh for smoother "ramping"
}

void sendLynxCommands() {
  // We'll focus on just printing the Shoulder (Channel 1) for this test
  Serial.print("Target: #1P");
  Serial.println(robotState[1]);
}

(th)

Offline

Like button can go here

#17 2026-05-22 11:56:07

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

Version 7.2 >> 8 is running, and I am happy with the results.

Gemini and I decided to attempt simulation of part of a robot command sequence. We set up two buttons on the directions pad, and they are working nicely. The up and down buttons simulate moving Servo 1 from 2400 to 600 and the LED lights illuminate during the movement. The physical movements are limited to 2500-500, so the software limits make sense to me. This is definitely progress.

If we adjusted the text slightly, and connected the Cokoino board to the LynxMotion board, the LynxMotion should rotate clockwise and counter  clockwise. What I have in mind is using the Left Joystick to control motion of the base servo. 

(th)

Offline

Like button can go here

#18 2026-05-22 12:03:06

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

This post contains Version 9 of our new Baseline_restart series...

In this version, I asked for a tiny change, to show LED's in red when we reach the limit of travel for one of the servos...

// Version 9: Shoulder Range with Red Limit Indicators
#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;

// State Database: [1] is the Shoulder
int robotState[5] = {1500, 1500, 1500, 1500, 1500};
int stepSize = 15; 

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("V9 Ready: Shoulder Limit Test (Red at 600/2400)");
}

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

  // --- SHOULDER MOVEMENT (PAD UP) ---
  if(ps2x.Button(PSB_PAD_UP)) {
    if(robotState[1] < 2400) {
      robotState[1] += stepSize;
      moving = true;
    } else {
      atLimit = true; // We hit the ceiling
    }
  }

  // --- SHOULDER MOVEMENT (PAD DOWN) ---
  if(ps2x.Button(PSB_PAD_DOWN)) {
    if(robotState[1] > 600) {
      robotState[1] -= stepSize;
      moving = true;
    } else {
      atLimit = true; // We hit the floor
    }
  }

  // --- LED LOGIC ---
  if(atLimit) {
    // RED for Limits
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(255, 0, 0));
    strip.show();
  } 
  else if(moving) {
    // GREEN for Active Movement
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 255, 0));
    strip.show();
    sendLynxCommands(); 
  } 
  else {
    // OFF for Idle
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 0, 0));
    strip.show();
  }

  // --- START: Reset to Home ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Homing Arm...");
    for(int i=0; i<5; i++) robotState[i] = 1500;
    sendLynxCommands();
  }

  delay(30); 
}

void sendLynxCommands() {
  Serial.print("Target: #1P");
  Serial.println(robotState[1]);
}

(th)

Offline

Like button can go here

#19 2026-05-23 12:49:07

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

In Version 10 we will exercise all 17 controls on the PS/2 by generating text strings that will appear in the test window. This is a phase in transitioning to direct control of the LynxMotion.

// Version 10: The Universal Test Bed (Full Controller Map)
#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;

// State Database for 6 Joints (0:Base, 1:Shoulder, 2:Elbow, 3:Wrist, 4:WristRot, 5:Gripper)
int robotState[6] = {1500, 1500, 1500, 1500, 1500, 1500};
int stepSize = 20;

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("V10 Universal Map Ready. Testing all inputs...");
}

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

  // --- D-PAD: Base (0) & Shoulder (1) ---
  if(ps2x.Button(PSB_PAD_UP))    { adjustState(1, stepSize); active = true; }
  if(ps2x.Button(PSB_PAD_DOWN))  { adjustState(1, -stepSize); active = true; }
  if(ps2x.Button(PSB_PAD_LEFT))  { adjustState(0, stepSize); active = true; }
  if(ps2x.Button(PSB_PAD_RIGHT)) { adjustState(0, -stepSize); active = true; }

  // --- SHAPES: Elbow (2) & Wrist (3) ---
  if(ps2x.Button(PSB_TRIANGLE))  { adjustState(2, stepSize); active = true; }
  if(ps2x.Button(PSB_CROSS))     { adjustState(2, -stepSize); active = true; }
  if(ps2x.Button(PSB_SQUARE))    { adjustState(3, stepSize); active = true; }
  if(ps2x.Button(PSB_CIRCLE))    { adjustState(3, -stepSize); active = true; }

  // --- L2 / R2: Gripper (5) ---
  if(ps2x.Button(PSB_L2))        { adjustState(5, stepSize); active = true; }
  if(ps2x.Button(PSB_R2))        { adjustState(5, -stepSize); active = true; }

  // --- ANALOG REPORTING (L1) ---
  if(ps2x.Button(PSB_L1)) {
    Serial.print("Sticks: L(");
    Serial.print(ps2x.Analog(PSS_LX)); Serial.print(",");
    Serial.print(ps2x.Analog(PSS_LY)); Serial.print(") R(");
    Serial.print(ps2x.Analog(PSS_RX)); Serial.print(",");
    Serial.print(ps2x.Analog(PSS_RY)); Serial.println(")");
  }

  // --- LED PILOT LIGHT ---
  if(active) {
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 255, 0));
    strip.show();
  } else {
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 0, 0));
    strip.show();
  }

  // --- START: Global Home ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Command: ALL HOMING #0P1500 #1P1500 #2P1500 #3P1500 #4P1500 #5P1500");
    for(int i=0; i<6; i++) robotState[i] = 1500;
  }

  delay(40);
}

// Logic to bound the movement and print the LynxMotion-style target
void adjustState(int joint, int change) {
  robotState[joint] += change;
  if(robotState[joint] > 2400) robotState[joint] = 2400;
  if(robotState[joint] < 600) robotState[joint] = 600;
  
  Serial.print("Target: #");
  Serial.print(joint);
  Serial.print("P");
  Serial.println(robotState[joint]);
}

(th)

Offline

Like button can go here

#20 2026-05-23 21:18:51

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

Testing of version 10 went well!  About half of the controls are doing something when pressed.  In version 11 we will begin activating the joysticks, and will change the shoulder buttons to text for now.

// Version 11: Joystick Fusion & Tool Text Messages
#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;

// State Database for 6 Joints
int robotState[6] = {1500, 1500, 1500, 1500, 1500, 1500};
int digitalStep = 25; // For Buttons
int analogStep = 8;   // For smooth Joystick drift

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("V11 Ready: Joystick Control Enabled for Base/Shoulder.");
}

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

  // --- LEFT JOYSTICK: Base(0) and Shoulder(1) ---
  int LX = ps2x.Analog(PSS_LX);
  int LY = ps2x.Analog(PSS_LY);

  // If LX is pushed Left (<100) or Right (>150)
  if(LX < 100) { adjustState(0, -analogStep); moving = true; }
  if(LX > 150) { adjustState(0, analogStep);  moving = true; }
  
  // If LY is pushed Up (<100) or Down (>150)
  if(LY < 100) { adjustState(1, analogStep);  moving = true; }
  if(LY > 150) { adjustState(1, -analogStep); moving = true; }

  // --- SHOULDER BUTTONS: Tool Status Messages ---
  if(ps2x.ButtonPressed(PSB_L1)) Serial.println("CMD: ADVANCE TOOL");
  if(ps2x.ButtonPressed(PSB_L2)) Serial.println("CMD: PULLBACK TOOL");
  if(ps2x.ButtonPressed(PSB_R1)) Serial.println("CMD: PITCH ROTATION UP");
  if(ps2x.ButtonPressed(PSB_R2)) Serial.println("CMD: PITCH ROTATION DOWN");

  // --- RESET (SELECT): LED Blink ---
  if(ps2x.ButtonPressed(PSB_SELECT)) {
    Serial.println("System Check: Reset/Select Pressed.");
    blinkLEDs(0, 0, 255); // Blue Blink
  }

  // --- SHAPES: Elbow (2) and Wrist (3) Remain Digital ---
  if(ps2x.Button(PSB_TRIANGLE)) { adjustState(2, digitalStep); moving = true; }
  if(ps2x.Button(PSB_CROSS))    { adjustState(2, -digitalStep); moving = true; }
  if(ps2x.Button(PSB_SQUARE))   { adjustState(3, digitalStep); moving = true; }
  if(ps2x.Button(PSB_CIRCLE))   { adjustState(3, -digitalStep); moving = true; }

  // --- LED PILOT LIGHT ---
  if(moving) {
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 255, 0));
    strip.show();
  } else {
    for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 0, 0));
    strip.show();
  }

  // --- START: Global Home ---
  if(ps2x.ButtonPressed(PSB_START)) {
    Serial.println("Homing All Servos...");
    for(int i=0; i<6; i++) robotState[i] = 1500;
  }

  delay(30); 
}

void adjustState(int joint, int change) {
  robotState[joint] += change;
  if(robotState[joint] > 2400) robotState[joint] = 2400;
  if(robotState[joint] < 600) robotState[joint] = 600;
  
  Serial.print("Target: #");
  Serial.print(joint);
  Serial.print("P");
  Serial.println(robotState[joint]);
}

void blinkLEDs(int r, int g, int b) {
  for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(r, g, b));
  strip.show();
  delay(100);
  for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(0, 0, 0));
  strip.show();
}

(th)

Offline

Like button can go here

#21 2026-05-25 18:53:35

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

Testing of Version 11 went well. The Left joystick sends appropriate commands for servo's 0 and 1.
Version 12 will investigate the click feature of the joysticks

// Version 12: L3/R3 Button Discovery & Precision Mode
// Baseline_restart_V12.ino
#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;

int robotState[6] = {1500, 1500, 1500, 1500, 1500, 1500};
int digitalStep = 25;
int analogStep = 8;

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("V12 Ready: Click the Joysticks to test L3/R3.");
}

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

  // --- L3 (Left Stick Click) Test ---
  if(ps2x.Button(PSB_L3)) {
    Serial.println("L3 (Left Click) DETECTED!");
    setLEDs(255, 255, 255); // White
  }

  // --- R3 (Right Stick Click) Test ---
  if(ps2x.Button(PSB_R3)) {
    Serial.println("R3 (Right Click) DETECTED!");
    setLEDs(255, 255, 0);   // Yellow
  }

  // --- Standard Joystick Drift (From V11) ---
  int LX = ps2x.Analog(PSS_LX);
  int LY = ps2x.Analog(PSS_LY);
  bool moving = false;

  if(LX < 100) { adjustState(0, -analogStep); moving = true; }
  if(LX > 150) { adjustState(0, analogStep);  moving = true; }
  if(LY < 100) { adjustState(1, analogStep);  moving = true; }
  if(LY > 150) { adjustState(1, -analogStep); moving = true; }

  // Pilot light logic
  if(moving) {
    setLEDs(0, 255, 0); // Green
  } else if (!ps2x.Button(PSB_L3) && !ps2x.Button(PSB_R3)) {
    setLEDs(0, 0, 0);   // Off
  }

  // (Remaining button logic from V11 omitted for brevity but included in your file)
  delay(30);
}

void setLEDs(int r, int g, int b) {
  for(int i=0; i<LED_COUNT; i++) strip.setPixelColor(i, strip.Color(r, g, b));
  strip.show();
}

void adjustState(int joint, int change) {
  robotState[joint] += change;
  if(robotState[joint] > 2400) robotState[joint] = 2400;
  if(robotState[joint] < 600) robotState[joint] = 600;
  Serial.print("Target: #"); Serial.print(joint);
  Serial.print("P"); Serial.println(robotState[joint]);
}

(th)

Offline

Like button can go here

#22 2026-05-25 20:08:56

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

Version 12 is working nicely.  We have tested the joystick buttons and confirmed they are working. Our current thinking is to toggle step size using the button. For Version 13 we have added code to enable action with the right joystick as well as the left on.e

// Version 13: The Finesse Toggle & Full Joint Map
#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;

// State Database for 6 Joints
int robotState[6] = {1500, 1500, 1500, 1500, 1500, 1500};

// Gear Settings
bool finesseMode = false;
int coarseStep = 15;
int fineStep = 4;
int digitalStep = 10; // For D-Pad fine tuning

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("V13 Ready: L3 Toggles Finesse Mode (Yellow).");
}

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

  // --- 1. THE GEARBOX (L3 Toggle) ---
  if(ps2x.ButtonPressed(PSB_L3)) {
    finesseMode = !finesseMode;
    Serial.print("MODE CHANGE: ");
    Serial.println(finesseMode ? "FINESSE (Small Steps)" : "TRAVEL (Large Steps)");
  }

  int currentStep = finesseMode ? fineStep : coarseStep;
  bool moving = false;

  // --- 2. LEFT JOYSTICK: Base(0) & Shoulder(1) ---
  int LX = ps2x.Analog(PSS_LX);
  int LY = ps2x.Analog(PSS_LY);
  if(abs(LX - 128) > 30) { adjustState(0, (LX > 128 ? 1 : -1) * currentStep); moving = true; }
  if(abs(LY - 128) > 30) { adjustState(1, (LY < 128 ? 1 : -1) * currentStep); moving = true; }

  // --- 3. RIGHT JOYSTICK: Wrist(3) & Gripper Rot(5) ---
  int RX = ps2x.Analog(PSS_RX);
  int RY = ps2x.Analog(PSS_RY);
  if(abs(RX - 128) > 30) { adjustState(5, (RX > 128 ? 1 : -1) * currentStep); moving = true; }
  if(abs(RY - 128) > 30) { adjustState(3, (RY < 128 ? 1 : -1) * currentStep); moving = true; }

  // --- 4. D-PAD: Fine Tuning (Elbow 2 & Base 0) ---
  if(ps2x.Button(PSB_PAD_UP))    { adjustState(2, digitalStep);  moving = true; }
  if(ps2x.Button(PSB_PAD_DOWN))  { adjustState(2, -digitalStep); moving = true; }
  if(ps2x.Button(PSB_PAD_LEFT))  { adjustState(0, -digitalStep); moving = true; }
  if(ps2x.Button(PSB_PAD_RIGHT)) { adjustState(0, digitalStep);  moving = true; }

  // --- 5. SHOULDER: Tool and Safety ---
  if(ps2x.ButtonPressed(PSB_L1)) Serial.println("CMD: TOOL ADVANCE");
  if(ps2x.ButtonPressed(PSB_L2)) Serial.println("CMD: TOOL RETRACT");
  if(ps2x.ButtonPressed(PSB_R1)) {
     Serial.println("CMD: READY POSITION"); // We'll define specific values later
  }
  if(ps2x.ButtonPressed(PSB_R2)) {
     Serial.println("CMD: SYSTEM HOME (1500)");
     for(int i=0; i<6; i++) robotState[i] = 1500;
  }

  // --- 6. VISUAL FEEDBACK ---
  if(moving) {
    // Green for Travel, Yellow for Finesse
    uint32_t color = finesseMode ? strip.Color(255, 150, 0) : strip.Color(0, 255, 0);
    setLEDs(color);
  } else {
    setLEDs(strip.Color(0, 0, 0)); // Off when idle
  }

  delay(40);
}

void adjustState(int joint, int change) {
  robotState[joint] += change;
  if(robotState[joint] > 2400) robotState[joint] = 2400;
  if(robotState[joint] < 600) robotState[joint] = 600;
  Serial.print("Target: #"); Serial.print(joint);
  Serial.print("P"); Serial.println(robotState[joint]);
}

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

(th)

Offline

Like button can go here

#23 2026-05-25 20:31:21

tahanson43206
Moderator
Registered: 2018-04-27
Posts: 24,733

Re: Arduino

Testing with both joysticks went well. In Version 14, we will tie up loose ends by sending text messages for each control that is not currently performing a functional task. We have both joysticks working in coarse and fine mode, and we have all 5 servo's under control. Servo 4 is NOT in the mix because that one is for the jaws, which will be locked onto a tool for the application we are working on.

// Version 14: The Complete Map & Diagnostic Baseline
#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;

int robotState[6] = {1500, 1500, 1500, 1500, 1500, 1500};
bool finesseMode = false;
int coarseStep = 15;
int fineStep = 4;
int digitalStep = 10;

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("V14 Ready: Complete Map Diagnostic Mode.");
}

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

  // --- 1. MODE TOGGLE (L3) & R3 REPORT ---
  if(ps2x.ButtonPressed(PSB_L3)) {
    finesseMode = !finesseMode;
    Serial.print("MODE CHANGE: ");
    Serial.println(finesseMode ? "FINESSE" : "TRAVEL");
  }
  if(ps2x.ButtonPressed(PSB_R3)) Serial.println("DIAGNOSTIC: Right Stick Click (R3) Pressed.");

  int currentStep = finesseMode ? fineStep : coarseStep;
  bool moving = false;

  // --- 2. JOYSTICKS: (0, 1, 3, 5) ---
  int LX = ps2x.Analog(PSS_LX);
  int LY = ps2x.Analog(PSS_LY);
  int RX = ps2x.Analog(PSS_RX);
  int RY = ps2x.Analog(PSS_RY);

  if(abs(LX - 128) > 30) { adjustState(0, (LX > 128 ? 1 : -1) * currentStep); moving = true; }
  if(abs(LY - 128) > 30) { adjustState(1, (LY < 128 ? 1 : -1) * currentStep); moving = true; }
  if(abs(RX - 128) > 30) { adjustState(5, (RX > 128 ? 1 : -1) * currentStep); moving = true; }
  if(abs(RY - 128) > 30) { adjustState(3, (RY < 128 ? 1 : -1) * currentStep); moving = true; }

  // --- 3. D-PAD: Fine Tuning ---
  if(ps2x.Button(PSB_PAD_UP))    { adjustState(2, digitalStep);  moving = true; }
  if(ps2x.Button(PSB_PAD_DOWN))  { adjustState(2, -digitalStep); moving = true; }
  if(ps2x.Button(PSB_PAD_LEFT))  { adjustState(0, -digitalStep); moving = true; }
  if(ps2x.Button(PSB_PAD_RIGHT)) { adjustState(0, digitalStep);  moving = true; }

  // --- 4. GEOMETRIC BUTTONS (Diagnostic Text) ---
  if(ps2x.ButtonPressed(PSB_TRIANGLE)) Serial.println("DIAGNOSTIC: Triangle Pressed.");
  if(ps2x.ButtonPressed(PSB_CIRCLE))   Serial.println("DIAGNOSTIC: Circle Pressed.");
  if(ps2x.ButtonPressed(PSB_CROSS))    Serial.println("DIAGNOSTIC: Cross Pressed.");
  if(ps2x.ButtonPressed(PSB_SQUARE))   Serial.println("DIAGNOSTIC: Square Pressed.");

  // --- 5. COMMAND BUTTONS (Diagnostic Text) ---
  if(ps2x.ButtonPressed(PSB_START))    Serial.println("DIAGNOSTIC: START Pressed.");
  if(ps2x.ButtonPressed(PSB_SELECT))   Serial.println("DIAGNOSTIC: SELECT/RESET Pressed.");

  // --- 6. SHOULDER: Tool & Safety ---
  if(ps2x.ButtonPressed(PSB_L1)) Serial.println("CMD: TOOL ADVANCE");
  if(ps2x.ButtonPressed(PSB_L2)) Serial.println("CMD: TOOL RETRACT");
  if(ps2x.ButtonPressed(PSB_R1)) Serial.println("CMD: READY POSITION");
  if(ps2x.ButtonPressed(PSB_R2)) {
     Serial.println("CMD: SYSTEM HOME (1500)");
     for(int i=0; i<6; i++) robotState[i] = 1500;
  }

  // Visuals
  if(moving) {
    uint32_t color = finesseMode ? strip.Color(255, 150, 0) : strip.Color(0, 255, 0);
    setLEDs(color);
  } else {
    setLEDs(strip.Color(0, 0, 0));
  }

  delay(40);
}

void adjustState(int joint, int change) {
  robotState[joint] += change;
  if(robotState[joint] > 2400) robotState[joint] = 2400;
  if(robotState[joint] < 600) robotState[joint] = 600;
  Serial.print("Target: #"); Serial.print(joint);
  Serial.print("P"); Serial.println(robotState[joint]);
}

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

(th)

Offline

Like button can go here

Board footer

Powered by FluxBB