Xbox controller -> raspberry pi -> serial -> arduino problems. Eg buttons sometimes don't register in arduino code

Python code

from evdev import list_devices, InputDevice, categorize, ecodes, KeyEvent,event_factory
from pySerialTransfer import pySerialTransfer as txfer
import time

gamepad = InputDevice('/dev/input/event0')

analogValue = [0,0,0,0,0,0]
buttonValue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
stickIndexes = [0,1,3,4]
buttonIndex = [304,305,307,308,310,311,314,315,316,317,318]

def map2(input,inmin,inmax,outmin,outmax):#Scales variable to range
	return int((input-inmin)*(outmax-outmin)/(inmax-inmin)+outmin)

def checkKeys():#If key is active it is then 1 on buttonValue[index]
	for x in gamepad.active_keys():
				for y in range(len(buttonIndex)):
					if x == buttonIndex[y]:
						buttonValue[y] = 1
	#print("checked keys")

stickDeadZone = 1000; #The raw value range is -32767/32767 so you will have a lot of space to correct

def checkAnalog():
	#allocates gamepad absinfo to correct analogValue[index] and scales with deadzone
	for x in range(4):
		if gamepad.absinfo(stickIndexes[x]).value > stickDeadZone or gamepad.absinfo(stickIndexes[x]).value < -stickDeadZone:
			analogValue[x] = map2(gamepad.absinfo(stickIndexes[x]).value,-32767,32767,-1000,1000)
		else:
			analogValue[x] = 0

		#trigger values as they are already 1023
		analogValue[4] = gamepad.absinfo(2).value
		analogValue[5] = gamepad.absinfo(5).value
	#D-pad values
	if gamepad.absinfo(16).value != 0:
		if gamepad.absinfo(16).value == -1:
			buttonValue[11] = 1
		elif gamepad.absinfo(16).value == 1:
			buttonValue[12] = 1
	else:
		buttonValue[11] = 0
		buttonValue[12] = 0

	if gamepad.absinfo(17).value != 0:
		if gamepad.absinfo(17).value == -1:
			buttonValue[13] = 1
		elif gamepad.absinfo(17).value == 1:
			buttonValue[14] = 1
	else:
		buttonValue[13] = 0
		buttonValue[14] = 0
	#print("checked analog")



if __name__ == '__main__':
	try:
		link = txfer.SerialTransfer('/dev/serial0')
		print("1");
		link.open()
		time.sleep(2) # allow some time for the Arduino to completely reset
		
		for event in gamepad.read_loop():
			print("2");
			keyevent = categorize(event)
			if event.type == ecodes.EV_KEY and keyevent.keystate == KeyEvent.key_down:
				checkKeys()
				print("3");
			else:
				buttonValue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
				print("4");

			#if event.type != 0:
			print("5")
			#checkAnalog()
			send_size = 0
			list_ = analogValue+buttonValue
			print(list_)
			list_size = link.tx_obj(list_)
			send_size += list_size
			link.send(send_size)

			#while not link.available():
			if False:
				print("6");
				if link.status < 0:
					if link.status == txfer.CRC_ERROR:
						print('ERROR: CRC_ERROR')
					elif link.status == txfer.PAYLOAD_ERROR:
						print('ERROR: PAYLOAD_ERROR')
					elif link.status == txfer.STOP_BYTE_ERROR:
						print('ERROR: STOP_BYTE_ERROR')
					else:
						print('ERROR: {}'.format(link.status))
			

	except KeyboardInterrupt:
		try:
			link.close()
		except:
			pass
	
	except:
		import traceback
		traceback.print_exc()
		
		try:
			link.close()
		except:
			pass

Arduino code

variables

const int xboxInputAmount = 21; //How many xbox values there will be
int32_t inputArray[xboxInputAmount]; //This will contain every xbox controller outputs

const int xbLSTICKAX = 0;//Left stick X axis
const int xbLSTICKAY = 1;//Left stick Y axis
const int xbLBA = 4;//Left trigger axis
const int xbRSTICKAX = 2;//Right stick X axis
const int xbRSTICKAY = 3; //Right stick Y axis
const int xbRBA = 5;//Right trigger axis
const int xbA = 6;//Button A
const int xbB = 7;//Button B
const int xbX = 8;//Button X
const int xbY = 9;//Button Y
const int xbLB = 10;//Button Left Bumber
const int xbRB = 11;//Button Right Bumber
const int xbSHARE = 12;//Button Share
const int xbSETTINGS = 13;//Button Settings
const int xbEMBLEM = 14;//Button Emblem
const int xbLSTICKD = 15;//Left stick down
const int xbRSTICKD = 16;//Right stick down
const int xbDL = 17;//Dpad left
const int xbDR = 18;//Dpad Right
const int xbDU = 19;//Dpad up
const int xbDD = 20;//Dpad down

//[Number of positions] [Number of axises]
//                     [lenght,turn,tilt]
int maxPositions = 10;
long positions[10][3];
long speedpositions[10]; //Speed value array
byte positionCount = 2;
byte indexValue = 0;

Main

#include <Arduino.h>
#include "variables.h" //Contains most of the variables
#include "Wire.h"
#include "SPI.h"
#include "SerialTransfer.h"
#include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h>
#include <AccelStepper.h>
#include <MultiStepper.h>

AccelStepper lenghtStepper = AccelStepper(1, LENGHT_STEP_PIN, LENGHT_DIR_PIN);
AccelStepper turnStepper = AccelStepper(1, TURN_STEP_PIN, TURN_DIR_PIN);
AccelStepper tiltStepper = AccelStepper(1, TILT_STEP_PIN, TILT_DIR_PIN);

MultiStepper steppers; // Manages multiple AccelSteppers


LiquidCrystal_I2C lcd(lcd_address, lcd_width, lcd_height);

///////////////////////////////////////////////////////////////////
//Main menu
//LINES
LiquidLine welcome_line1(6,0,"Main Menu");
LiquidLine welcome_line2(0,1,"Drive menu");

//SCREENS
// You can add 4 line items here but the rest would then be required to be put into setup
LiquidScreen welcome_screen1(welcome_line1,welcome_line2);

//MENU
LiquidMenu welcome_menu(lcd,welcome_screen1);

///////////////////////////////////////////////////////////////////
//Drive menu

//MENU1 where you set how many positions you want
	//LINES
	LiquidLine drive_line1(2,0,"Set index amount");
	LiquidLine drive_line2(4,1,"Index : ",positionCount);
	LiquidLine drive_line3(7,2,"Accept");

	//SCREEN
	LiquidScreen drive_screen1(drive_line1,drive_line2,drive_line3);

	//MENU
	
//MENU2 where you drive stepper motors into positions
	//LINES
		LiquidLine drive2_line1(0,0,"Index: ",indexValue);
		LiquidLine drive2_line2(0,1,indexValue," / ", positionCount);
		LiquidLine drive2_line3(0,2,"empty");

	//SCREEN
	LiquidScreen drive_screen2(drive2_line1,drive2_line2,drive2_line3);

	//MENU
	//LiquidMenu drive_menu2(lcd,drive_screen2);

LiquidMenu drive_menu(lcd,drive_screen1,drive_screen2);

///////////////////////////////////////////////////////////////////
//Menu system

LiquidSystem menu_system(welcome_menu,drive_menu);

///////////////////////////////////////////////////////////////////

void gotodrive(){
	menu_system.change_menu(drive_menu);
}


//Increases indexValue variable and checks if it is under max positions
void increaseIndex(){
	positionCount++;
	if(positionCount > positionCount){
		positionCount = maxPositions;
	}
	Serial.printf("In inc ind %d",positionCount);
	menu_system.update();
}
//Decreases indexValue variable and checks if it is over the min value
void decreaseIndex(){
	positionCount--;
	if(positionCount < 2){
		positionCount = 2;
	}
	Serial.printf("In dec ind %d",positionCount);
	menu_system.update();
}

SerialTransfer myTransfer; // remember to use myTransfer.tick(); to get callback

void drivemotors(){
	menu_system.next_screen();
		Serial.println("drive");
	for(indexValue = 0; indexValue < positionCount; indexValue++)
	{
		menu_system.update();
		Serial.printf("for i %d posc %d \n",indexValue,positionCount);
		while (true)
		{
			myTransfer.tick();
			Serial.printf(" while true i %d posc %d \n",indexValue,positionCount);
			lenghtStepper.setSpeed(inputArray[xbLSTICKAX]);
			turnStepper.setSpeed(inputArray[xbRSTICKAX]);
			tiltStepper.setSpeed(inputArray[xbRSTICKAY]);

			lenghtStepper.runSpeed();
			turnStepper.runSpeed();
			tiltStepper.runSpeed();

			if(inputArray[xbX]){
				positions[indexValue][0] = lenghtStepper.currentPosition();
				positions[indexValue][1] = turnStepper.currentPosition();
				positions[indexValue][2] = tiltStepper.currentPosition();
				delay(100);
				break;
			}
		}
	}
	for(int i = 0; i < 10; i++){
		Serial.printf("%d %d %d",positions[i][0],positions[i][1],positions[i][2]);
		Serial.println();
	}
}

void buttonsCheckMenuNavigation()//Menu navigation code
{
	if (inputArray[xbB])
	{
		menu_system.call_function(1);//Select
	}

	if (inputArray[xbRB])
	{
		menu_system.call_function(2);//Increase
	}

	if (inputArray[xbLB])
	{
		menu_system.call_function(3);//Increase
	}

	if (inputArray[xbDL])
	{

	}

	if (inputArray[xbDR])
	{

	}

	if (inputArray[xbY])
	{
		menu_system.switch_focus(false);//Up in menu
	}
	if (inputArray[xbA])
	{
		menu_system.switch_focus(true);//Down in menu
	}
}


void callbackController()
{
		Serial.println("callback");
		uint16_t recSize = 0;
		recSize = myTransfer.rxObj(inputArray, recSize); 
		buttonsCheckMenuNavigation();

		//Increase and decrease speed value
		if (inputArray[xbLBA] < inputArray[xbRBA])
		{
			//Right trigger code
			speedmodifier = map(inputArray[xbRBA], 0, 1000, 0, 100);
			speed = speed + speedmodifier;
			//Checks if speed is over max
			if(speed > MaxTotalSpeed){
				speed = MaxTotalSpeed;
			}
		}
		else
		{
			//Left trigger code
			speedmodifier = map(inputArray[xbLBA], 0, 1000, 0, 100);
			speed = speed - speedmodifier;
			//If speed is negative
			if(speed < 0){
				speed = 0;
			}
		}
		//Serial.println(speed);

		//Maps stick analog values to the speed
		for (int i = 0; i < 4; i++)
		{
			inputArray[i] = map(inputArray[i], 0, 1000, 0, speed);
		}

		//Print inputArray
		/*
		for(int i = 0; i < xboxInputAmount; i++){
			Serial.print(inputArray[i]);
			Serial.print("|");
		}
		Serial.println();
		*/
		
}




// supplied as a reference - persistent allocation required
const functionPtr callbackArr[] = { callbackController };


void setup()
{
	Serial1.begin(115200);
	Serial.begin(115200);
	Serial.println("Start");

	lcd.init();
	lcd.backlight();

	welcome_menu.init();
	drive_menu.init();

	welcome_line2.attach_function(1,gotodrive);

	drive_line2.attach_function(2,increaseIndex);
	drive_line2.attach_function(3,decreaseIndex);
	drive_line3.attach_function(1,drivemotors);
	menu_system.update();

	///////////////////////////////////////////////////////////////////
	configST myConfig;
	myConfig.debug        = true;
	myConfig.callbacks    = callbackArr;
	myConfig.callbacksLen = sizeof(callbackArr) / sizeof(functionPtr);
	///////////////////////////////////////////////////////////////////

	myTransfer.begin(Serial1, myConfig);

	lenghtStepper.setMaxSpeed(LENGHTMAXSPEED);
	turnStepper.setMaxSpeed(TURNMAXSPEED);
	tiltStepper.setMaxSpeed(TILTMAXSPEED);

	steppers.addStepper(lenghtStepper);
	steppers.addStepper(turnStepper);
	steppers.addStepper(tiltStepper);

	//Make sure that the position and speedposition arrays are zero
	for(int i = 0; i < maxPositions; i++){
		for(int j = 0; j < 3; j++){
			positions[i][j] = 0;
			speedpositions[i] = 0;
		}
	}

}


void loop()
{
	myTransfer.tick();
	//buttonsCheckMenuNavigation();
}

Hello!
I'm having problems with my arduino/python code.
The way I detect button presses sometimes does not register them.
The way I send button values over from raspberry to arduino is a bit finnicky and I get crc errors.

I can get the analog values pretty easily but the button values are the problem here.

I use
if(array from raspberry pi[xboxbuttons code]){
//do cool stuff here
}
as the button check. How should I do it instead?

I am using serial transfer library to send a list over to arduino. The list format is analog values and then button values[1/0]eg [analogval1][analogval2][button1][button2]. Should I be doing this or is there a better way of sending xbox values over to arduino?

Should I send the serial packet every python code loop or once the action(event) happens in python?

If I send serial for every event in game controller shouldn't I also send a blank button array to not cause stuck buttons or to zero the button array in arduino code?

I have fought with the python code for some days now...

Thank you for your help and I hope I have included enough info for you to try and help me.

What is your timing window for checking data from the controller?