I mean that the shaft in not on the face that you use to mount the motor, that complicated things a lot
The tooth profile is HTD 3M, and yes every battery soldered, not the best idea but the worst part in that in every weld there is a rectangular pcb piece, a lot of pcb pieces, cutting then took a lot of time
So a update, changed everything:
-The motor is strong enough, the weld is strong enough but... the aluminum is not
, i even made a reinforcement, but didn't work unfortunately
-The belt mesh is small and i need a lot of pre tension on the belt, more than my mount can support without flexing and more than the wheel can take without flexing, and i could make it work only once for about 500m
-This ESC is crap for out use, even push kicking it's hard to get sync, and braking or not make no difference, but the worst part in that if you are cruising with no throttle and try to get the motor started again it's a no go
-the only thing that working is my arduino code, and worked beautifully, current control and current limiting, and very smooth operation, with the current limit set to 26A i got a max of 25,5A, perfect!
And the changes:
-VESC on the next enertion batch
-torqueboards 170kv sensored motor
-7075 or 6061 T6 cnc milled motor mount
the sad part is that all the code of arduino is not going to be used, if anyone want's it, its bellow, you need an arduino nano, NRF24l01, and a ACS712 current sensor
Code:
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include <Servo.h>
//Variáveis relacionadas ao controle do ESC
int joystick_y = 1; //Define que o eixo y do analógico está no pino A1
int neutro = 1550; //Define leitura do ponto neutro(ms)
double corrente_desejada; //Define a corrente desejada na bateria
double corrente_bat_max = 26; //Define a corrente máxima suportada pela bateria
double erro; //Erro entre a corrente desejada e a corrente atual
long lastProcess; //Armazena o tempo (ms) do ciclo anterior
double kP = 8; //Coeficiente proporcional
double kI = 4; //Coeficiente integral
double kD = 0; //Coeficiente diferencial
double lastSample; //Armazena o valor da corrente no ciclo anteiror
double P, I, D; //Armazena o valor de cada correção
int pwm_ESC = 1550; //Cria a variável que ira controlar o esc e o posiciona no neutro(ms)
double corrente_fase_max = 26; //Define a corrente máxima suportada pelo motor
double erro_fase; //Erro entre a corrente máxima suportada pelo motor e a corrente de fase atual
double P_fase, I_fase; //Correção de fase
double kP_fase = kP * 2; //Coeficiente proporcional da fase
double kI_fase = kI * 2; //Coeficiente integral da fase
//Variaveis relacionadas à leitura e cálculo da corrente na bateria e nas fases do motor
int dutycycle = 0; //Cria a variável que sera armazenada a porcentagem do pwm
int amppin = 2; //Define que o sensor de corrente esta no pino A2
double corrente = 0; //Cria a variável que sera armazenada a corrente a cada ciclo
double leitura_corrente = 0; //Cria a variàvel que sera armazenada a saida do sensor de corrente a cada ciclo
int mVperAmp = 88; //Define a relação entre saida do sensor e corrente
int ACSoffset = 2276; //Define o desvio em relação ao terra da saida do sensor
double tensao_sensor = 0; //Cria a variável que sera armazenada a tensão de saida do sensor
double corrente_fase = 0; //Cria a variável que sera armazenada a corrente da fase
double correntemedia = 0; //Cria a variável que sera armazenada a corrente média
double medicoes[10];
int i;
//nRF24L01+ CE and CSN pins
RF24 radio(9, 10);
// Single radio pipe address for the 2 nodes to communicate.
const uint64_t pipe = 0xe7e7e7e7e7LL;//0xE8E8F0F0E1LL;
static uint32_t message_count = 1;
//#define USE_SERIAL
Servo ESC;
void setup()
{
#ifdef USE_SERIAL
Serial.begin(115200); // First open the serial connection via the USB
// while (!Serial) {}
Serial.println("Started!");
#endif
radio.begin();
// We will be using the Ack Payload feature, so please enable it
radio.enableAckPayload();
radio.enableDynamicPayloads();
radio.writeAckPayload( 1, &message_count, sizeof(message_count) );
ESC.attach(6);
ESC.writeMicroseconds(neutro);
radio.openReadingPipe(1, pipe);
radio.startListening();
#ifdef USE_SERIAL
radio.printDetails();
#endif//USE_SERIAL
}
int threshold = 3;
const int min_payload_size = 4;
const int max_payload_size = 32;
const int payload_size_increments_by = 2;
int next_payload_size = min_payload_size;
unsigned char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char
unsigned long bla;
struct MyStatus
{
int message_count;
char potValueA;
char potValueB;
char unused1;
char unused2;
};
int timeout = 0;
int targetValueA = 0;
void loop()
{
timeout++;
if (timeout > 100)
{
ESC.writeMicroseconds(neutro);
#ifdef USE_SERIAL
Serial.println("Timeout!");
#endif
}
{
// if there is data ready
if ( radio.available() )
{
// printf("radio available\n");
// Dump the payloads until we've gotten everything
static unsigned long got_time;
bool done = false;
bool dynamicPayload = true;
if (dynamicPayload)
{
while (!done)
{
// Fetch the payload, and see if this was the last one.
int len = radio.getDynamicPayloadSize();
done = radio.read( receive_payload, len );
// done = radio.read( &bla, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
//some simple 'checksum'
if (receive_payload[0] == 238)
{
targetValueA = map(receive_payload[1], 0, 255, 1300, 1810);
#ifdef USE_SERIAL
Serial.print("receive=");
Serial.println(receive_payload[1]);
Serial.print("servo=");
Serial.println(targetValueA);
#endif
timeout = 0;
}
//Serial.println(targetValueA);
// Spew it
#ifdef USE_SERIAL
printf("Got dynamic payload size=%d:\n\r", len);
for (int i = 0; i < len; i++)
{
int v = receive_payload[i];
printf("value[%d]=%d\n", i, v);
}
#endif //USE_SERIAL
}
} else
{
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( &got_time, sizeof(unsigned long) );
#ifdef USE_SERIAL
// Spew it
printf("Spew Got payload %lu\n", got_time);
#endif//USE_SERIAL
}
}
// Add an ack packet for the next time around. This is a simple
// packet counter
MyStatus stat;
stat.message_count = message_count;
stat.potValueA = targetValueA;
stat.potValueB = targetValueA;
stat.unused1 = 2;
stat.unused2 = sizeof(int);
radio.writeAckPayload( 1, &stat, sizeof(MyStatus) );
++message_count;
}
}
//Fim radio
//Cálculos e leituras relacionadas à corrente
for ( i = 0 ; i <= 10; i++ ) {
leitura_corrente = analogRead(amppin); //Lê a saida do sensor de corrente
tensao_sensor = (leitura_corrente / 1023.0) * 4550; //Converte a leitura em uma tensão equivalente
medicoes[i] = ((tensao_sensor - ACSoffset) / mVperAmp); //Cálcula a corrente equivalente
}
sort(medicoes, 10);
correntemedia = medicoes[5]; //Cálcula a corrente media dividindo o somatório do vetor pelo número de medições
if (targetValueA < 1570)
dutycycle = 0;
else
dutycycle = map(targetValueA, 1550, 1810, 0, 100); //Mapeia a posição do analógico para -100 e 100
if (dutycycle <= 0) {
corrente_fase = 0;
}
else {
corrente_fase = (correntemedia * 100) / dutycycle; //Cálcula a corrente da fase
}
//Cálculos e leituras relacionados ao controle do ESC
//Le a posição do analógico
//Caso o analógico esteja abaixo do neutro, ignora o PID e aplica o freio
if (targetValueA <= 1570) {
pwm_ESC = targetValueA; //Mapeia para o pwm do ESC
corrente_desejada = 0;
I = 0;
}
else {
//Aplica o PID com base no controle por corrente
corrente_desejada = map( targetValueA, 1550, 1810, 0, corrente_bat_max);
//implementação PID
erro = corrente_desejada - correntemedia; //corrente_fase;
float deltaTempo = (millis() - lastProcess) / 1000.0;
lastProcess = millis();
//P
P = erro * kP;
//I
I = I + (erro * kI) * deltaTempo;
//D
D = (lastSample - correntemedia) * kD / deltaTempo;
//Limite Corrente Fase PI
if (corrente_fase_max > 26) {
erro_fase = corrente_fase_max - corrente_fase;
P_fase = erro_fase * kP_fase;
I_fase = I_fase + (erro_fase * kI_fase) * deltaTempo;
}
else {
P_fase = 0;
I_fase = 0;
}
//Soma PID
pwm_ESC = P + I + D + P_fase + I_fase + neutro;
if (pwm_ESC > 1810) {
pwm_ESC = 1810;
I = 1810 - neutro;
}
}
ESC.writeMicroseconds(pwm_ESC);
//Serial
Serial.print('\n');
Serial.print("duty cycle: ");
Serial.print(dutycycle);
Serial.print(" % ");
Serial.print("Corrente: ");
Serial.print(correntemedia, 2);
Serial.print("A ");
Serial.print(" Corrente Desejada: ");
Serial.print(corrente_desejada);
Serial.print("A");
Serial.print(" Corrente Fase: ");
Serial.print(corrente_fase, 2);
Serial.print("A ");
Serial.print(" Ms Esc: ");
Serial.print(pwm_ESC);
Serial.print(" Leitura Joystick ");
Serial.print(targetValueA);
}
void sort(double a[], double size) {
for (int i = 0; i < (size - 1); i++) {
for (int o = 0; o < (size - (i + 1)); o++) {
if (a[o] > a[o + 1]) {
double t = a[o];
a[o] = a[o + 1];
a[o + 1] = t;
}
}
}
}
EDIT:
New motor mount done
Testing pulley interference in max and min position:
Simulation with 7075-T6 aluminum (the previos one i used had a 100MPa UTS, wonder why it failed :lol: ) :
And testing interference with the truck and deck