1

Prelude

I haven't done a lot of work in programming chips. The ATTiny85 is the first chip I've programmed, and I have the hang of the basics I think, but I don't have an in-depth understanding of it's capabilities and how to perform complex circuits with it.

The Issue

I cannot get the following to work: utilize any combination of PWM Pins with 2 Servos, and ADC (Analog to Digital Converter) Pins connected to a Joystick to control the servos using an ATTiny85.

My code works fine with an Arduino Uno R3. Porting it over to the ATTiny85 only lets me control 1 servo with 1 axis of the joystick (x or y).

As far as I can see from ATTiny85 Pinout, there are 3 PWM pins (PB0, PB1 and PB4) that I can use for the Servo data line, and 4 ADC Pins (PB2, PB3, PB4 and PB5) that I can use to send output from the joystick.

Swapping servos works fine - so I know they're not causing issues. Swapping joystick axis works fine - so that's not it.

Running the code on the Arduino and viewing in the Serial Monitor shows that the joystick is writing correctly for both the X and Y axis - and is correctly mapping the coordinates to the serial output.

I can list out the different pins I've tried to use for the servos and the joystick - but at this point I think this is a capability issue of the ATTiny85 - and the latest pins I've tried are in the code.

I can give pictures/diagrams of my wiring for the servos and joysticks to the ATTiny85 if someone needs them, or of the wiring I use to program the ATTiny85 if it's useful.

I'm currently still debugging this issue and trying to find what's going wrong - but so far no luck. I haven't tried debugging the ATTiny85 with the serial monitor, but I've just been reprogramming it and trying different combinations of pins and code commented out. I will update the question as I discover more information.

Something strange

In my setup() code - the S1_.write(S1_Center) works, and the servo moves to the center of it's set limitations - but after that it is not responsive to the joystick. At least that tells me every time I run it that the servo is attached and able to receive a write() and so is functional - and leads me to believe that I have an issue with the Analog/Serial side of things, but I'm not sure.

Questions

Is it possible to control 2 servos with a joystick (X-axis for one servo, Y-axis for another - essentially 2 potentiometers in lieu of joystick) using an ATTiny85?

Am I using incorrect pins for the ATTiny85 to do this? ADC and PWM?

Is the issue with the code I'm using or is this a hardware constraint for the ATTiny85?

If anyone has any advice at the least it would be helpful. I know this question is to a somewhat specific scenario - but in doing my (apparently not very good) research I can only find very basic - non analog/serial ways people drive servos which I already know how to do.

Here is the code I've written that works standalone with Arduino but not with the ATTiny85.

#include <Servo_ATTinyCore.h>

Servo S1_;  // create servo object to control a servo
Servo S2_;  // create servo object to control a servo

//Joystick 1 inputs (Joystick -> Arduino)
int J1_VRx = PIN_PB3; //Attiny85 PB3 (Physical pin 2) - as per SpenceKonde ATtinyCore Github 'You cannot use the Pxn notation (ie, PB2, PA1, etc) to refer to pins ... use PIN_Pxn (ex, PIN_PB2)'
int J1_VRy = PIN_PB2; // Attiny85 PB4 (Physical pin 7)
int J1_SW = PIN_PB4; // Attiny85 PB2 (Physical pin 3)

//Joystick 1 variables
int J1_xPosition = 0;
int J1_yPosition = 0;
int J1_SW_state = 0;
boolean J1_SW_pressed = false;
//int J1_SW_state_read = 0;
//boolean buttonPressed
int J1_mapX = 0;
int J1_mapY = 0;

//Servo output (Arduino -> Servo)
int S1_Output = PIN_PB1;
int S2_Output = PIN_PB0;

//Servo Variables
int S1_Limits[2] = {0,180};  // set limitations (min/max: 0->180)
int S2_Limits[2] = {0,180};  // set limitations (min/max: 0->180)
boolean refresh = false;  // toggle refresh on/off
int S1_Degree = 0;
int S2_Degree = 0;
int S1_Speed = 0;
int S2_Speed = 0;
int S1_Speed_Limit = 2; //controls how quickly the servo can move
int S2_Speed_Limit = 2; //controls how quickly the servo can move
int speedModes[3] = {1,2,3}; //Define the speeds which can be toggled between
int speedMode = 2; //Set initial speed mode (speedModes[1] if this value is 1) 


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

  //Assign Joystick 1 pins
  pinMode(J1_VRx, INPUT);
  pinMode(J1_VRy, INPUT);
  pinMode(J1_SW, INPUT_PULLUP);

  //Assign Servo pin
  S1_.attach(S1_Output);
  S2_.attach(S2_Output);

  //Get center of Servo limitations
  int S1_Center = ((S1_Limits[0]/2) + (S1_Limits[1]/2));
  int S2_Center = ((S2_Limits[0]/2) + (S2_Limits[1]/2));

  //Send servos to center
  S1_.write(S1_Center);
  S2_.write(S2_Center);

  //Set servo current degrees as at center
  S1_Degree = S1_Center;
  S2_Degree = S2_Center;

  //Set servo initial speed limit
  S1_Speed_Limit = speedModes[speedMode - 1];
  S2_Speed_Limit = speedModes[speedMode - 1];

}

void loop() {

  //Reset servo direction speeds
  S1_Speed = 0;
  S2_Speed = 0;

  //Read Joystick 1 inputs
  J1_xPosition = analogRead(J1_VRx);
  J1_yPosition = analogRead(J1_VRy);
  J1_SW_state = digitalRead(J1_SW);
  J1_mapX = map(J1_xPosition, 0, 1023, -1024, 1024); //X-position of joystick
  J1_mapY = map(J1_yPosition, 0, 1023, -1024, 1024); //Y-position of joystick

  //Fix offsets for joysticks (custom fixes because these joysticks aren't perfect :/)
  J1_mapX += 6;
  J1_mapY += 20;

  delay(10);

  boolean J1_SW_toggled = false;
  //If the button is down
  if(J1_SW_state == 0) {
    J1_SW_pressed = true;
    //Joystick button pressed
  }
  //If the button was down and is now up
  if(J1_SW_pressed == true && J1_SW_state == 1) {
    J1_SW_pressed = false;
    J1_SW_toggled = true;
    //Joystick button released
  }

  //Cycle the speed mode for servos 1, 2 and 3
  if(J1_SW_toggled) {
    J1_SW_toggled = false;
    if (speedMode != speedModes[(sizeof(speedModes) / sizeof(int)) - 1]) { //This is how to get length of speedModes array of byte type int
      speedMode += 1;
    }
    else {
      speedMode = 1;
    }
    S1_Speed_Limit = speedModes[speedMode - 1];
    S2_Speed_Limit = speedModes[speedMode - 1];
  }

  int stutterSetting = 100; //+- buffer to keep servos from moving due to imperfect readouts from joysticks

  if(J1_mapY > stutterSetting || J1_mapY < -stutterSetting) {
    S1_Speed = map(J1_mapY, -512, 512, S1_Speed_Limit, -S1_Speed_Limit);
  }
  if(J1_mapX > stutterSetting || J1_mapX < -stutterSetting) {
    S2_Speed = map(J1_mapX, -512, 512, S2_Speed_Limit, -S2_Speed_Limit);
  }


  if(S1_Speed != 0) {
    if((S1_Degree + S1_Speed) < S1_Limits[1] && (S1_Degree + S1_Speed) > S1_Limits[0]) {
      S1_Degree += S1_Speed;
      S1_.write(S1_Degree);
      delay(10);
    }
  }

  if(S2_Speed != 0) {
    if((S2_Degree + S2_Speed) < S2_Limits[1] && (S2_Degree + S2_Speed) > S2_Limits[0]) {
      S2_Degree += S2_Speed;
      S2_.write(S2_Degree);
      delay(10);
    }
  }

//  Serial.print("J1_X: ");
//  Serial.print(J1_mapX);
//  Serial.print(" | J1_Y: ");
//  Serial.print(J1_mapY);
//  Serial.print(" | S1_Speed: ");
//  Serial.print(S1_Speed);
//  Serial.print(" | S1_Degree: ");
//  Serial.print(S1_Degree);
//  Serial.print(" | S2_Speed: ");
//  Serial.print(S2_Speed);
//  Serial.print(" | S2_Degree: ");
//  Serial.println(S2_Degree);
}
  • You could try to pinpoint the problem by outputting the data on the ATtiny over Serial (there are TX only Software Serial libraries, which are rather small and only need one pin, which you then can connect to the PC via an Arduino). Look at the ADC measurements and the results of your calculation. It will be way easier to fix, when we know, where exactly the problem occurs – chrisl Apr 27 '21 at 18:30

0 Answers0