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);
}