Skip to content

Instantly share code, notes, and snippets.

@carlosdelfino
Last active June 3, 2020 17:11
Show Gist options
  • Save carlosdelfino/3772100 to your computer and use it in GitHub Desktop.
Save carlosdelfino/3772100 to your computer and use it in GitHub Desktop.
Código para controle e segurança de uma Cadeira de Rodas Inteligente.

Cadeira de Rodas Inteligente

Antes de tudo hoje 31/05/2020 fiz uma revisão rápida dos códigos acima, e todos precisam ser revisto, há erros que podem ser chamados de bug, ou mesmo erros conceituais, já que os códigos foram escritos de cabeça sem fazer testes práticos.

Links Relevantes

Anotações

Abaixo algumas anotações relevantes a serem consideradas.

Filtros de Hardware

Pode se considerar conforme alguns o uso de filtros de hardware pare evitar o ruído de leitura do pontenciometro, porém da minha parte prefiro que tal correção seja feita através de código, como o sugerido na ultima inserção, o uso do EMA - Exponencial Moving Averange é uma boa forma de se evitar mudanças abruptas do código, outras formas são também a multiplas leituras da porta e obtendo-se assim a média de leituras.

Abaixo a formula para calculo do filtro de hardware, um filtro passa baixa:

Fc=1/(2πRC)
Fc- cutoff frequency
R-resistance
C-capacitance
          R
°------/\/\/\/\---+---------°
                  |
               C-----
                -----
                  |
°-----------------+---------°
/*
Cadeira Inteligente
Código para controle de Cadeira de Rodas.
O Código lê o nível de sinal nas portas analógicas A0 e A1,
A0 indica se deve ir para frente ou para traz.
A1 indica se deve dar mais potência para Direita ou para Esquerda
Foram criadas algumas constantes, para facilitar o ajuste de valores para calibração do código.
É fundamental que o pino aref do arduino esteja conectado ao mesmo nível de tenção que o joystick
para manter a referência de tenção, quando usando uma tenção diferente do padrão. Veja comentário
no setup() sobre uso externo de tenções de referencia maiores que 5v.
02/10/2012
Foi adicionado dois novos pinos digitais, que sao ativados quando ha sinalizacao nas portas pwm
de controle da ponte.
Tambem mudei o algoritimo para que em cada ciclo as variaveis de controle da porta PWM sejam zeradas
Evitando o perigo de acionamento em codigos futuros.
18/10/2012
Devido a problemas de saturação da ponte H, o limite para a potência no PWM foi definido como 190.
This example code is in the public domain.
*/
#define DEBUG true
#define Port_1a 10 // Porta 1a, PWM 10 para controlar o lado esquerdo
#define Port_2a 11 // Porta 2a, PWM 11 para controlar o lado esquerdo
#define Port_3a 5 // Porta 3a, PWM 5 para controlar o lado direito
#define Port_4a 6 // Porta 4a, PWM 6 para controlar o lado direito
#define Port_1b 8 // Porta 1b, Digital 8, lado esquerdo
#define Port_2b 4 // Porta 2b, Digital 4, lado esquerdo
#define Port_3b 2 // Porta 1b, Digital 2, lado direito
#define Port_4b 12 // Porta 2b, Digital 12, lado direito
#define Port_emg 12 // porta de controle do circuito de emergência,
// alta quando o sinal de emergência estiver ativo.
#define joy_x A0 // Joystick Eixo X, porta analogica
#define joy_y A1 // Joystick Eixo Y, porta analogica
#define Pin_emg 3 // Porta de emergencia, Pino 3, interrupcao 1
#define Int_emg 1 // Interrupcao de emergencia, Pino 3, interrupcao 1
#define Pin_rele 7 // Porta de controle do Rele,
//forward, backward
#define FORWARD_LEFT_MAX_POWER 190
#define BACKWARD_LEFT_MAX_POWER 190
#define FORWARD_LEFT_MIN_POWER 0
#define BACKWARD_LEFT_MIN_POWER 0
#define FORWARD_RIGHT_MAX_POWER 190
#define BACKWARD_RIGHT_MAX_POWER 190
#define FORWARD_RIGHT_MIN_POWER 0
#define BACKWARD_RIGHT_MIN_POWER 0
// Constantes do Eixo X do Joystick
// movimenta a cadeira para frente e para tras
#define EIXO_X_MIN 0
#define EIXO_X_MAX 1023
#define RELE_MAX_X 551
#define RELE_MIN_X 471
#define EIXO_X_LIMIAR_SUPERIOR 556
#define EIXO_X_LIMIAR_INFERIOR 465
#define EIXO_X_START_SUPERIOR 512
#define EIXO_X_START_INFERIOR 511
#define EIXO_X_MEDIO 511
// Constantes do Eixo Y do joystick
// movimenta a cadeira para os lados
#define EIXO_Y_MIN 0
#define EIXO_Y_MAX 1023
#define RELE_MAX_Y 551
#define RELE_MIN_Y 471
#define EIXO_Y_LIMIAR_SUPERIOR 556
#define EIXO_Y_LIMIAR_INFERIOR 465
#define EIXO_Y_START_SUPERIOR 512
#define EIXO_Y_START_INFERIOR 511
#define EIXO_Y_MEDIO 511
////////////////////////////////////
int val_x = EIXO_X_MEDIO;
int val_y = EIXO_Y_MEDIO;
int val_esquerdo1 = 0;
int val_esquerdo2 = 0;
int val_direito1 = 0;
int val_direito2 = 0;
volatile boolean emg = false;
void monitorBotaoEmergencia();
void setup()
{
noInterrupts();
if(DEBUG) Serial.begin(9600);
/* **********************
* ATENÇÃO:
* se optar por usar uma referência externa,
* esta não pode ser maior que 5V nem menor que 0V
* Use uma rede de resitores para ajustar o valor de
* de referência para algo igual ou menor que 5V.
* A saída do Joystick também precisa ser ajustada.
*/
analogReference(DEFAULT);
/*
* as 4 leituras abaixo ajustam a porta para o novo valor.
*/
analogRead(joy_x);
analogRead(joy_y);
analogRead(joy_x);
analogRead(joy_y);
pinMode(Port_1a,OUTPUT);
pinMode(Port_2a,OUTPUT);
pinMode(Port_1b,OUTPUT);
pinMode(Port_2b,OUTPUT);
pinMode(Port_emg, OUTPUT);
pinMode(Pin_rele,OUTPUT);
digitalWrite(Port_emg, LOW);
analogWrite(Port_1a,0);
analogWrite(Port_2a,0);
digitalWrite(Port_1b,0);
digitalWrite(Port_2b,0);
analogWrite(Port_3a,0);
analogWrite(Port_4a,0);
digitalWrite(Port_3b,0);
digitalWrite(Port_4b,0);
pinMode(Pin_emg,INPUT_PULLUP);
attachInterrupt(Int_emg,monitorBotaoEmergencia,FALLING); // O uso da opcao LOW demanda um maior gerencimento.
interrupts();
}
void monitorBotaoEmergencia(){
emg = true;
}
void loop()
{
boolean rele_on;
int val_x_d = EIXO_X_MEDIO;
int val_y_d = EIXO_Y_MEDIO;
digitalWrite(Port_emg,emg);
/* passei a zerar as variaveis a cada
* ciclo para evitar que tenham valores
* sujos em algoritimos futuros.
*/
val_esquerdo1 = 0;
val_esquerdo2 = 0;
val_direito1 = 0;
val_direito2 = 0;
if(emg){
digitalWrite(Pin_rele,0);
val_x = 0;
val_y = 0;
analogWrite(Port_1a,FORWARD_LEFT_MIN_POWER);
analogWrite(Port_2a,BACKWARD_LEFT_MIN_POWER);
analogWrite(Port_3a,FORWARD_LEFT_MIN_POWER);
analogWrite(Port_4a,BACKWARD_LEFT_MIN_POWER);
digitalWrite(Port_1b,LOW);
digitalWrite(Port_2b,LOW);
digitalWrite(Port_3b,LOW);
digitalWrite(Port_4b,LOW);
}
else{
val_x_d = val_x = analogRead(joy_x);
val_y_d = val_y = analogRead(joy_y);
rele_on = val_x > RELE_MAX_X || val_x < RELE_MIN_X;
digitalWrite(Pin_rele, rele_on);
if(val_x > EIXO_X_MEDIO){
if(val_x < EIXO_X_LIMIAR_SUPERIOR) {
val_x = EIXO_X_START_SUPERIOR;
}
if(val_y < EIXO_Y_LIMIAR_SUPERIOR) {
val_y = EIXO_Y_START_SUPERIOR;
}
// aqui ira calcular os valores para ajustar o movimento correto:
// frente, re, frente direita, frente esquerda, re direita, re esquerda,
// direita parado, esquerda parado (girando ou nao sobre o prio eixo
val_esquerdo2 = map(val_x,512,1023,FORWARD_LEFT_MIN_POWER,FORWARD_LEFT_MAX_POWER);
val_direito2 = map(val_x,512,1023,FORWARD_RIGHT_MIN_POWER,FORWARD_RIGHT_MAX_POWER);
}
else{
if(val_x > EIXO_Y_LIMIAR_INFERIOR) {
val_x = EIXO_Y_START_INFERIOR;
}
if(val_y > EIXO_Y_LIMIAR_INFERIOR) {
val_y = EIXO_Y_START_INFERIOR;
}
// aqui ira calcular os valores para ajustar o movimento correto:
// frente, re, frente direita, frente esquerda, re direita, re esquerda,
// direita parado, esquerda parado (girando ou nao sobre o prio eixo
val_esquerdo1 = map(val_x,0,511,BACKWARD_LEFT_MAX_POWER,BACKWARD_LEFT_MIN_POWER);
val_direito1 = map(val_x,0,511,BACKWARD_RIGHT_MAX_POWER,BACKWARD_RIGHT_MIN_POWER);
}
analogWrite(Port_1a,val_esquerdo1);
analogWrite(Port_2a,val_esquerdo2);
digitalWrite(Port_1b,val_esquerdo1 > 0);
digitalWrite(Port_2b,val_esquerdo2 > 0);
analogWrite(Port_3a,val_direito1);
analogWrite(Port_4a,val_direito2);
digitalWrite(Port_3b,val_direito1 > 0);
digitalWrite(Port_4b,val_direito2 > 0);
}
if(DEBUG){
Serial.print("Joystick X Debug: ");
Serial.print(val_x_d);
Serial.print(", ");
Serial.print("Joystick X: ");
Serial.print(val_x);
Serial.print(", ");
Serial.print("Esquerdo 1: ");
Serial.print(val_esquerdo1);
Serial.print(", ");
Serial.print("Esquerdo 2: ");
Serial.print(val_esquerdo2);
Serial.print(", ");
Serial.print("Direito 1: ");
Serial.print(val_direito1);
Serial.print(", ");
Serial.print("Direito 2: ");
Serial.print(val_direito2);
Serial.print(", ");
Serial.print("Rele: ");
Serial.print(rele_on?"Ativado":" Desativado");
Serial.print(", ");
Serial.print("Emergencia: ");
Serial.println(emg?"Ativado":" Desativado");
}
}
/**
* Exemplo de uso do Algoritmo Exponencial Moving Averate - EMA
* fonte inicial: https://www.norwegiancreations.com/2015/10/tutorial-potentiometers-with-arduino-and-filtering/
*/
//Global Variables
int sensorPin = 0; //pin number to use the ADC
int sensorValue = 0; //initialization of sensor variable, equivalent to EMA Y
float EMA_a = 0.6; //initialization of EMA alpha
int EMA_S = 0; //initialization of EMA S
void setup(){
Serial.begin(115200); //setup of Serial module, 115200 bits/second
EMA_S = analogRead(sensorPin); //set EMA S for t=1
}
void loop(){
sensorValue = analogRead(sensorPin); //read the sensor value using ADC
EMA_S = (EMA_a*sensorValue) + ((1-EMA_a)*EMA_S); //run the EMA
Serial.println(EMA_S); //print digital value to serial
delay(50); //50ms delay
}
int h1 = 10; //porta da ponte 1
int h2 = 11;//porta da ponte 1
int h3 = 5;//porta da ponte 2
int h4 = 6;//porta da ponte 2
int joy1 = 1;//pino 1 do joy controla a ponte 1
int joy = 0;//pino 2 do joy controla a ponte 2
int val;
int vala;
int val1;
int val2;
int val3;
int val4;
void setup()
{
Serial.begin(9600);
}
void loop()
{
val = analogRead(joy);//controle da ponte 1
val1 = map(val,0,511,255,0);
val2 = map(val,512,1023,0,255);
if(val > 511) val1 = 0;
else val2 = 0;
delay(150);
analogWrite(h1,val1);
analogWrite(h2,val2);
delay(150);
vala = analogRead(joy1);//controle da ponte 2
val3 = map(vala,0,511,255,0);
val4 = map(vala,512,1023,0,255);
if(vala > 511) val1 = 0;
else val4 = 0;
delay(150);
analogWrite(h3,val3);
analogWrite(h4,val4);
delay(150);
}
#define joy_x A0 // Joystick Eixo X, porta analogica
int val_x;
void setup()
{
Serial.begin(9600);
Serial.println( "INiciado teste do Joystick");
Serial.println("##########################");
Serial.println("");
}
void loop(){
val_x = analogRead(joy_x);
Serial.print("Joystick X Debug: ");
Serial.print(val_x);
delay(20);
}
/*
Smoothing
Reads repeatedly from an analog input, calculating a running average and
printing it to the computer. Keeps ten readings in an array and continually
averages them.
The circuit:
- analog sensor (potentiometer will do) attached to analog input 0
created 22 Apr 2007
by David A. Mellis <dam@mellis.org>
modified 9 Apr 2012
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Smoothing
*/
// Define the number of samples to keep track of. The higher the number, the
// more the readings will be smoothed, but the slower the output will respond to
// the input. Using a constant rather than a normal variable lets us use this
// value to determine the size of the readings array.
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int inputPin = A0;
void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
}
void loop() {
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = analogRead(inputPin);
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
// ...wrap around to the beginning:
readIndex = 0;
}
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
Serial.println(average);
delay(1); // delay in between reads for stability
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment