Quantcast
Channel: Dragão sem Chama
Viewing all articles
Browse latest Browse all 24

Sensor Ultrassônico no Arduino e Raspberry Pi

$
0
0

Uma dúvida que atormenta boa parte da humanidade é “como construir robôs autônomos?”. Quanto mais pensamos e realizamos cálculos complexos, mais chegamos à conclusão inevitável de que uma máquina autônoma precisa de uma maneira de compreeender o ambiente em que está, ou seja, necessita de sensores. O objeto de estudo de hoje são os sonares, ou sensores de distância ultrassônicos. Vamos aprender como funcionam, como utilizá-los, com exemplos em duas plataformas DIY (Arduino e Raspberry Pi) e quais são seus limites.

Introdução

Sonares são dispositivos que utilizam o som para medir distância até um obstáculo. Estes são também chamados sensores de distância ultrassônicos, pois utilizam ondas sonoras de frequêcia acima da faixa audível do ser humano de forma a evitar interferência com o batidão do funk ali da esquina. A ideia é a seguinte: um sonar possui dois elementos principais, um transmissor e um receptor de som, posicionados lado a lado. Quando se deseja fazer uma medida, o transmissor é ativado e produz uma série de pulsos sonoros. Esses pulsos viajam pelo espaço entre o sonar e um obstáculo na velocidade do som. Lembrando que a velocidade do som é diferente dependendo do meio percorrido, mas nessa discussão vamos imaginar que o meio em questão é o ar. Quando as ondas sonoras atingem um obstáculo, parte delas sofre reflexão. Essas ondas refletidas são então captadas pelo receptor. A diferença de tempo entre a transmissão dos pulsos sonoros e a captação pelo receptor é usada para calcular a distância até o objeto.

sonar-diagrama-funcionamento
Uma figura para ilustrar o comportamento de reflexão das ondas transmitidas pelo sensor ultrassônico

A equação abaixo pode ser usada para obter a distância (d), em metros, a partir da velocidade do som (vs), em metros por segundo, e do seu tempo de ida e volta (Δt), em segundos:

distance

O sensor ultrassônico mais famoso no mercado atualmente é o modelo HC-SR04. Esse foi o modelo que utilizamos para os testes. Ele possui 4 pinos: VCC, GND, TRIG, ECHO e exige uma alimentação de 5V. TRIG é o pino de ativação do transmissor: quando esse pino recebe um pulso de 10 microssegundos, o transmissor do módulo produz uma série de pulsos ultrassônicos. O pino ECHO vai para o nível lógico alto logo após o transmissor finalizar o envio de seus pulsos ultrassônicos e permanece em alto até o momento em que o receptor capta as ondas refletidas por um obstáculo. O intervalo em que ECHO está em nível lógico alto é o tempo de ida e volta dos pulsos ultrassônicos.

HC-SR04 front
O módulo HC-SR04
HC-SR04 back
Visão traseira do módulo HC-SR04

Arduino

Esquemático

A plataforma perfeita para testar o HC-SR04. Basta conectar TRIG e ECHO a dois pinos digitais, VCC a 5V, GND a GND. Não há nenhum detalhe que, se esquecido, possa derreter seu Arduino.

sonar_arduino_bb
À prova de erros!

Código

O código que elaboramos tem alguns truques, então vou mencioná-los aqui.

No Arduino, as medidas do sonar serão feitas continuamente dentro da função loop(). Isso significa que podemos escolher a frequência média com que fazemos a leitura do sonar ao configurar um pequeno delay entre as medições. Essa frequência de leitura é chamada taxa de amostragem, ou seja, a taxa com que obtemos amostras de um sensor. Devemos fazer 20 leituras por segundo (20 Hz)? Ou que tal forçar a barra e tentar 1 milhão (1MHz)? Hum, a velocidade do som e o próprio equipamento não permitem aumentar a taxa de amostragem tanto assim. No código, fixamos a taxa de amostragem (sampling_rate) a 20Hz.

O módulo HC-SR04 não é adequado para medições a longa distância. O alcance máximo do módulo é 4 metros, mas a confiabilidade das leituras já cai bastante após 2.5 metros. Logo não faz sentido tentar medir distâncias muito maiores que essas. No código abaixo definimos uma distância máxima (max_distance) a ser medida e isso implica em um tempo máximo de espera pela borda de descida de ECHO (max_delta_t). Você verá esse valor sendo usado na linha 75, para impedir que fiquemos esperando demais por resultados incertos.

Pronto! Execute o código a seguir e veja o resultado no Monitor Serial. Por favor funciona.

/*  TRIG será conectado ao pino 7 
 *  ECHO ao pino 8.
 */
int TRIG = 7;
int ECHO = 8;

/*  Variáveis utilizadas para medir o intervalo de tempo 
 *  em que ECHO permanece em alto. Isso é o tempo de ida
 *  e volta dos pulsos ultrassônicos.
 *  start_t: momento da borda de subida de ECHO
 *  end_t:   momento da borda de descida de ECHO
 *  delta_t: intervalo entre a borda de subida e descida de ECHO
 */
unsigned long start_t;
unsigned long end_t;
unsigned long delta_t;

/*  Variáveis para auxiliar no controle do loop principal
 *  sampling_rate: taxa de amostragem em Hz, isto é, em média,
 *    quantas leituras do sonar serão feitas por segundo
 *  speed_of_sound: velocidade do som no ar a 30ºC em m/s
 *  max_distance: máxima distância permitida para medição
 *  max_delta_t: um valor máximo para a variável delta_t,
 *    baseado na distância máxima max_distance
 */
double sampling_rate = 20;
double speed_of_sound = 349.10;
double max_distance = 4;
unsigned long max_delta_t = max_distance*pow(10,6)/speed_of_sound;

/*  A variável de saída. Tudo que se faz nesse código é para
 *  obtê-la. Bem valorizada.
 */
double distance;

void setup() {
  /* Código de inicialização
   * Inicializa Serial
   * Define TRIG como saída digital
   * Define ECHO como entrada digital
   * Inicializa TRIG em nível lógico baixo
   */
  Serial.begin(9600);
  pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);
  digitalWrite(TRIG, LOW);
}

void loop() {
  /*  Gera um pulso de 10ms em TRIG.
   *  Essa ação vai resultar na transmissão de ondas 
   *  ultrassônicas pelo transmissor do módulo sonar.
   */
  digitalWrite(TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);

  /*  Atualiza a variável start_t enquanto ECHO está em nível
   *  lógico baixo. Quando ECHO trocar de estado, start_t 
   *  manterá seu valor, marcando o momento da borda de subida
   *  de ECHO. Este é o momento em que as ondas sonoras 
   *  acabaram de ser enviadas pelo transmissor.
   */
  while(digitalRead(ECHO) == LOW) start_t = micros();

  /*  Atualiza a variável end_t enquando ECHO está em alto.
   *  Quando ECHO voltar ao nível baixo, end_t vai manter 
   *  seu valor, marcando o tempo da borda de descida de ECHO,
   *  ou o momento em que as ondas refletidas por um objeto 
   *  foram captadas pelo receptor.
   *  Caso o intervalo de tempo seja maior que max_delta_t,
   *  o loop de espera também será interrompido.
   */
  while(digitalRead(ECHO) == HIGH 
        && micros() - start_t < max_delta_t) end_t = micros();

  /*  Se a diferença entre end_t e start_t estiver dentro
   *  dos limites que foram impostos, atualizamos a variável
   *  delta_t e calculamos a distância até um obstáculo.
   *  
   *  O valor de delta_t que obtemos é em microssegundos,
   *  portanto dividimos o valor obtido por 10^4 para obter
   *  a distância em centímetros.
   *  
   *  Caso o valor de delta_t não esteja nos limites determinados
   *  definimos a distância como -1, sinalizando uma medida
   *  mal-sucedida.
   */
  if(end_t - start_t < max_delta_t) {
    delta_t = end_t - start_t;
    distance = (0.5*delta_t*speed_of_sound)/pow(10,4);
  } else {
    distance = -1;
  }

  /*  Enviamos o valor calculado pela Serial
   *  Um pequeno delay para manter a média da taxa de amostragem
   *  definida anteriormente.
   */
  Serial.println(distance);
  delay(int(1000/sampling_rate));
}

Raspberry Pi

Esquemático

Os pinos digitais do Raspberry trabalham com níveis lógicos de 0 a 3.3V. Portanto, não podemos conectar diretamente o pino ECHO do HC-SR04 a um pino de entrada do Raspberry, já que ECHO estará a 5V quando for ativado pelo módulo. Você corre o risco de danificar o GPIO do Raspberry se fizer isso. Uma solução simples é usar um divisor de tensão para trazer o nível lógico alto de 5V para 3.3V. Usamos 3 resistores de 1kΩ para construir o divisor de tensão. Veja o esquema abaixo e faça as conexões com carinho.

sonar_raspberry_bb8.png
TCHA-RAM

Código

Usamos o mesmo procedimento que elaboramos anteriormente no código para Arduino. Se precisar, confira os pontos em que menciono o porquê da utilização das variáveis sampling_rate, max_distance e max_delta_t. Fora isso, adicionamos uma função no código a seguir para interromper de forma segura  a execução do programa ao pressionarmos CTRL-C. O código em Python foi testado com a versões 2.7 e 3.5, na placa Raspberry Pi 3. Caso esteja usando um outro modelo do Raspberry, é melhor verificar a numeração dos pinos e trocá-los para um número adequado, se necessário. Tomei o cuidado de escolher pinos que não mudaram nas diversas revisões dos Raspberries que eu conheço. Usamos a numeração da placa, em que os pinos 16 e 18 são equivalentes aos GPIO23 e GPIO24 na numeração BCM.

# coding:utf-8

import sys
import time
import signal
import RPi.GPIO as GPIO

# Define a numeração dos pinos de acordo com a placa
GPIO.setmode(GPIO.BOARD)

# Função para finalizar o acesso à GPIO do Raspberry de forma segura
def clean():
    GPIO.cleanup()

# Função para finalizar o programa de forma segura com CTRL-C
def sigint_handler(signum, instant):
    clean()
    sys.exit()

# Ativar a captura do sinal SIGINT (Ctrl-C)
signal.signal(signal.SIGINT, sigint_handler)

# TRIG será conectado ao pino 18. ECHO ao pino 16.
TRIG = 18
ECHO = 16

# Variáveis para auxiliar no controle do loop principal
# sampling_rate: taxa de amostragem em Hz, isto é, em média,
#   quantas leituras do sonar serão feitas por segundo
# speed_of_sound: velocidade do som no ar a 30ºC em m/s
# max_distance: máxima distância permitida para medição
# max_delta_t: um valor máximo para a variável delta_t,
#   baseado na distância máxima max_distance
sampling_rate = 20.0
speed_of_sound = 349.10
max_distance = 4.0
max_delta_t = max_distance / speed_of_sound

# Define TRIG como saída digital
# Define ECHO como entrada digital
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)

# Inicializa TRIG em nível lógico baixo
GPIO.output(TRIG, False)
time.sleep(1)

print ("Sampling Rate:", sampling_rate, "Hz")
print ("Distances (cm)")

# Loop principal. Será executado até que que seja pressionado CTRL-C
while True:

    # Gera um pulso de 10ms em TRIG.
    # Essa ação vai resultar na transmissão de ondas ultrassônicas pelo
    # transmissor do módulo sonar.
    GPIO.output(TRIG, True)
    time.sleep(0.00001)
    GPIO.output(TRIG, False)

    # Atualiza a variável start_t enquanto ECHO está em nível lógico baixo.
    # Quando ECHO trocar de estado, start_t manterá seu valor, marcando
    # o momento da borda de subida de ECHO. Este é o momento em que as ondas
    # sonoras acabaram de ser enviadas pelo transmissor.
    while GPIO.input(ECHO) == 0:
      start_t = time.time()

    # Atualiza a variável end_t enquando ECHO está em alto. Quando ECHO
    # voltar ao nível baixo, end_t vai manter seu valor, marcando o tempo
    # da borda de descida de ECHO, ou o momento em que as ondas refletidas
    # por um objeto foram captadas pelo receptor. Caso o intervalo de tempo
    # seja maior que max_delta_t, o loop de espera também será interrompido.
    while GPIO.input(ECHO) == 1 and time.time() - start_t < max_delta_t:
      end_t = time.time()

    # Se a diferença entre end_t e start_t estiver dentro dos limites impostos,
    # atualizamos a variável delta_t e calculamos a distância até um obstáculo.
    # Caso o valor de delta_t não esteja nos limites determinados definimos a
    # distância como -1, sinalizando uma medida mal-sucedida.
    if end_t - start_t < max_delta_t:
        delta_t = end_t - start_t
        distance = 100*(0.5 * delta_t * speed_of_sound)
    else:
        distance = -1

    # Imprime o valor da distância arredondado para duas casas decimais
    print (round(distance, 2))

    # Um pequeno delay para manter a média da taxa de amostragem
    time.sleep(1/sampling_rate)

Considerações

Limites para a taxa de amostragem

Depois de alguns testes, verifiquei que as medições com o Arduino funcionam bem até uma taxa aproximada de 40 medições por segundo (40 Hz). Mais do que isso e começa a aparecer ruído, valores sem sentido. Já no Raspberry, obtive taxas maiores, com medidas seguras dentro de uma margem de 5% até 100 Hz.

The post Sensor Ultrassônico no Arduino e Raspberry Pi appeared first on Dragão sem Chama.


Viewing all articles
Browse latest Browse all 24

Trending Articles