VIXI, BORA MEDIR O BARULHO!

🎤 Medindo o barulho da galera

"O primeiro olho do robô" — Desenvolva um programa que captura áudio do microfone, calcula intensidade sonora simulada e gera alertas personalizados com memes paranaenses.

Duração: 100 min (2 aulas)
Google Colab + Chromebook + Microfone
Memes & Alertas irreverentes
╭( ・ㅂ・)و ̑̑ 🔊
🎤📊🤣
Códigos BNCC

EM13CNT104 - Avaliar limites e potencialidades das tecnologias de captura de áudio
EM13MAT503 - Interpretar e representar dados sonoros em gráficos simples
EM13LGG702 - Utilizar diferentes linguagens para produção de sentido (memes como linguagem)
Competências Gerais

Competência 2 - Exercitar curiosidade intelectual
Competência 7 - Argumentar com base em dados
Etapas da Aula (100 minutos)
Etapa Tempo Atividade
Abertura 10 min Desafio: "Quanto barulho tem na nossa sala?" estimativa coletiva.
Conceituação 15 min Explicar decibéis (dB) e como o computador "escuta" (PCM, amostragem).
Codificação 40 min Implementar o código de captura de áudio e decisões com memes (em duplas).
Teste prático 20 min Criar diferentes níveis de barulho (sussurro, conversa, grito, palmas). Registrar no CSV.
Fechamento 15 min Gerar gráfico dos últimos 10 registros. Debater: "O robô reagiu certo?"
Simulador do Robô Fofoqueiro 🤣 Clique e teste os memes!

🎤 Nível de som simulado

0.0 dB

🚨 ALERTA! PASSOU DOS 75 dB! TÁ MUITO ALTO!

📢 Mensagem do Robô:

🤫 Clique nos botões para testar...
Materiais

  • Notebook Colab da aula anterior
  • Microfones (embutidos no Chromebook ou headsets)
  • Caixa de som (para gerar barulho controlado)
Adaptações para inclusão

  • Alunos com deficiência auditiva podem usar o recurso de "vibração do Chromebook" ou focar na parte visual do gráfico
  • Para alunos com TDAH: sessões curtas de codificação com pausas
robo_fofoqueiro_sensor_som.py — Código completo da aula 2 download disponível
# ===================================================================
#            Robô Fofoqueiro - Sensor de Som Irreverente
# ===================================================================
# Objetivo: Simular um sensor de som (KY-038) usando o microfone real,
#           medindo níveis de intensidade sonora em decibéis simulados,
#           emitindo alertas quando o volume ultrapassa 75 dB e
#           salvando logs em CSV para análise gráfica.
# Alunos: [A SER PREENCHIDO]
# Orientadora: Gisele Nunes
# Data  : 2026
# ===================================================================

# -*- coding: utf-8 -*-

# Importa a biblioteca pyaudio para capturar áudio do microfone em tempo real.
import pyaudio

# Importa numpy para operações matemáticas com arrays (cálculo de RMS, etc.).
import numpy as np

# Importa time para possíveis delays ou marcações de tempo.
import time

# Importa threading para executar tarefas em paralelo (não usado diretamente aqui,
# mas mantido para expansões futuras como captura contínua).
import threading

# Importa csv para salvar os dados das medições em formato de planilha.
import csv

# Importa datetime para gerar timestamps precisos de cada medição.
from datetime import datetime

# Importa matplotlib para gerar gráficos de barras com o histórico de medições.
import matplotlib.pyplot as plt

# Importa clear_output do IPython para limpar a saída do notebook Colab.
from IPython.display import clear_output

# ===== CONFIGURAÇÃO INICIAL =====
# No Colab, é necessário instalar as bibliotecas com:
# !pip install pyaudio keyboard matplotlib numpy
# !apt-get install portaudio19dev

# ===== FUNÇÃO PRINCIPAL =====
def medidor_fofoqueiro():
    """
    Função que simula o sensor KY-038 usando o microfone real.
    Captura 3 segundos de áudio, calcula a intensidade sonora (RMS),
    converte para uma escala simulada de 0 a 120 dB e retorna o nível,
    um status de alerta e uma mensagem de meme conforme o volume.
    
    Retorna:
    tuple: (decibeis_simulados, alerta, mensagem_meme)
    """
    
    # Define a duração da captura de áudio em segundos.
    DURACAO = 3
    
    # Define a taxa de amostragem (44.1 kHz é qualidade de CD).
    TAXA_AMOSTRAGEM = 44100
    
    # Define o tamanho do buffer (quantos samples por leitura).
    TAMANHO_BUFFER = 1024
    
    # Cria uma instância do objeto PyAudio para gerenciar o microfone.
    audio = pyaudio.PyAudio()
    
    # Abre um stream de áudio para captura (input=True significa microfone).
    stream = audio.open(
        format=pyaudio.paInt16,          # Formato 16 bits por sample.
        channels=1,                      # Mono (um canal).
        rate=TAXA_AMOSTRAGEM,            # Taxa de amostragem definida.
        input=True,                      # Modo captura.
        frames_per_buffer=TAMANHO_BUFFER # Tamanho de cada bloco de leitura.
    )
    
    # Mensagem informativa para o usuário.
    print("🎤 Gravando 3 segundos de áudio...")
    
    # Lista para armazenar os frames (blocos) de áudio capturados.
    frames = []
    
    # Calcula quantos blocos serão necessários para preencher DURACAO segundos.
    # Ex: 44100 samples/s / 1024 samples/bloco * 3 s = ~129 blocos.
    for _ in range(0, int(TAXA_AMOSTRAGEM / TAMANHO_BUFFER * DURACAO)):
        # Lê um bloco de dados do microfone.
        data = stream.read(TAMANHO_BUFFER)
        # Converte os bytes lidos em um array numpy de inteiros de 16 bits.
        dados_audio = np.frombuffer(data, dtype=np.int16)
        # Adiciona o bloco convertido à lista de frames.
        frames.append(dados_audio)
    
    # Para o stream de áudio para liberar o microfone.
    stream.stop_stream()
    # Fecha o stream.
    stream.close()
    # Termina a instância do PyAudio.
    audio.terminate()
    
    # Concatena todos os frames em um único array numpy de áudio.
    audio_data = np.concatenate(frames)
    
    # CÁLCULO DA INTENSIDADE SONORA (RMS - Root Mean Square)
    # RMS é uma média quadrática que representa a potência do sinal.
    # Quanto maior o RMS, mais alto o volume.
    rms = np.sqrt(np.mean(audio_data**2))
    
    # Valor máximo possível para um sinal int16 (2^15 = 32768).
    max_rms = 32768
    
    # Converte o RMS para uma escala simulada de decibéis (0 a 120 dB).
    # Um RMS de 0 resulta em 0 dB, um RMS de 32768 resulta em 120 dB.
    decibeis = (rms / max_rms) * 120
    
    # Garante que o valor não ultrapasse os limites de 0 a 120 dB.
    decibeis = min(120, max(0, decibeis))
    
    # EMOJI CONFORME VOLUME (faixas de intensidade)
    # Quanto maior o dB, mais "barulhento" é o emoji escolhido.
    if decibeis < 20:
        emoji = "🔇🤫"      # Silêncio absoluto.
    elif decibeis < 40:
        emoji = "🤫"        # Sussurro.
    elif decibeis < 60:
        emoji = "🗣️"        # Conversa normal.
    elif decibeis < 80:
        emoji = "📢"        # Gritaria moderada.
    elif decibeis < 100:
        emoji = "🔊"        # Muito alto.
    else:
        emoji = "💀📢"      # Extremamente alto (alerta máximo).
    
    # MENSAGEM MEME POR NÍVEL (texto humorístico para cada faixa)
    # Define também a variável alerta (True se ultrapassar 75 dB).
    if decibeis < 40:
        mensagem = "🤫 silêncio absoluto... até assusta"
        alerta = False
    elif decibeis < 60:
        mensagem = "🗣️ papinho normal, nada de mais"
        alerta = False
    elif decibeis < 80:
        mensagem = "📢 TÁ FICANDO BOM! logo logo viro fofoqueiro"
        alerta = True
    elif decibeis < 100:
        mensagem = "🔊 CALA A BOCA! vou piscar o LED vermelho"
        alerta = True
    else:
        mensagem = "💀 INFERNO ACÚSTICO! vou chamar a diretora robô"
        alerta = True
    
    # Alerta também é ativado separadamente se dB > 75 (redundante, mas seguro).
    alerta = decibeis > 75
    
    # Exibe um resumo formatado com emoji, valor em dB e mensagem.
    print("\n" + "="*50)
    print(f"Nível atual: {emoji}")
    print(f"Decibéis simulados: {decibeis:.1f} dB")
    print(f"📢 {mensagem}")
    print("="*50)
    
    # Retorna uma tupla com os três valores de interesse.
    return (decibeis, alerta, mensagem)

# ===== FUNÇÃO PARA SALVAR LOG EM CSV =====
def salvar_log(decibeis, mensagem, arquivo="log_fofoqueiro.csv"):
    """
    Salva uma medição em um arquivo CSV.
    Cria o cabeçalho se o arquivo estiver vazio.
    
    Parâmetros:
    decibeis: float - valor medido em dB.
    mensagem: str - mensagem de meme associada.
    arquivo: str - nome do arquivo CSV (padrão: log_fofoqueiro.csv).
    """
    
    # Gera um timestamp com data e hora atuais no formato ANO-MÊS-DIA HORA:MINUTO:SEGUNDO.
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    # Abre o arquivo em modo de adição ('a' = append).
    # newline='' evita linhas em branco extras no Windows.
    # encoding='utf-8' garante caracteres especiais (emoji, acentos).
    with open(arquivo, mode='a', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        
        # Move o ponteiro para o final do arquivo para verificar se está vazio.
        file.seek(0, 2)
        # Se o arquivo estiver vazio (tell() retorna 0), escreve o cabeçalho.
        if file.tell() == 0:
            writer.writerow(["Timestamp", "Decibeis (dB)", "Mensagem"])
        
        # Escreve a linha com os dados da medição atual.
        writer.writerow([timestamp, f"{decibeis:.1f}", mensagem])
    
    # Confirma o salvamento com uma mensagem.
    print(f"💾 Log salvo: {timestamp} - {decibeis:.1f} dB")

# ===== FUNÇÃO PARA MOSTRAR GRÁFICO =====
def mostrar_grafico(arquivo="log_fofoqueiro.csv"):
    """
    Lê o arquivo CSV de log e gera um gráfico de barras com as últimas 10 medições.
    Barras verdes para dB <= 75 (seguro) e vermelhas para dB > 75 (alerta).
    
    Parâmetros:
    arquivo: str - nome do arquivo CSV (padrão: log_fofoqueiro.csv).
    """
    
    try:
        # Tenta abrir o arquivo CSV para leitura.
        with open(arquivo, 'r', encoding='utf-8') as file:
            leitor = csv.reader(file)
            
            # Pula o cabeçalho (primeira linha).
            cabecalho = next(leitor)
            
            # Listas para armazenar os dados.
            timestamps = []
            decibeis = []
            contador = 0
            
            # Percorre todas as linhas do CSV.
            for linha in leitor:
                timestamps.append(linha[0])          # Primeira coluna: timestamp.
                decibeis.append(float(linha[1]))     # Segunda coluna: dB (converte para float).
                contador += 1
            
            # Pega apenas os últimos 10 registros (ou menos se houver menos de 10).
            ultimos = min(10, contador)
            timestamps = timestamps[-ultimos:]
            decibeis = decibeis[-ultimos:]
            
            # Cria uma figura com tamanho de 12 polegadas de largura por 6 de altura.
            plt.figure(figsize=(12, 6))
            
            # Define as cores das barras: verde se dB <= 75, vermelho se > 75.
            cores = ['green' if db <= 75 else 'red' for db in decibeis]
            
            # Cria o gráfico de barras com as cores definidas e transparência 0.7.
            barras = plt.bar(range(len(decibeis)), decibeis, color=cores, alpha=0.7)
            
            # Adiciona uma linha horizontal pontilhada no limite de 75 dB (alerta).
            plt.axhline(y=75, color='orange', linestyle='--', linewidth=2, label='Limite de Alerta (75 dB)')
            
            # Rótulo do eixo X.
            plt.xlabel('Medições (mais recente na direita)', fontsize=12)
            
            # Rótulo do eixo Y.
            plt.ylabel('Decibéis Simulados (dB)', fontsize=12)
            
            # Título do gráfico em negrito.
            plt.title('📊 Histórico do Robô Fofoqueiro - Últimas Medições', fontsize=14, fontweight='bold')
            
            # Define os rótulos do eixo X como os timestamps, rotacionados 45 graus.
            plt.xticks(range(len(timestamps)), timestamps, rotation=45, ha='right')
            
            # Define os limites do eixo Y de 0 a 120 dB.
            plt.ylim(0, 120)
            
            # Adiciona uma grade leve (alpha=0.3 = 30% opaco).
            plt.grid(True, alpha=0.3)
            
            # Adiciona a legenda da linha de alerta.
            plt.legend()
            
            # Adiciona os valores numéricos acima de cada barra.
            for i, (barra, db) in enumerate(zip(barras, decibeis)):
                altura = barra.get_height()
                # Posiciona o texto 2 unidades acima da barra, centralizado.
                plt.text(barra.get_x() + barra.get_width()/2., altura + 2, f'{db:.0f}dB', ha='center', va='bottom', fontsize=9)
            
            # Ajusta o layout automaticamente para evitar cortes.
            plt.tight_layout()
            
            # Exibe o gráfico.
            plt.show()
            
            print(f"📈 Gráfico mostrado com os últimos {ultimos} registros!")
    
    except FileNotFoundError:
        # Se o arquivo não existir, exibe uma mensagem amigável.
        print("⚠️ Ainda não há dados para mostrar. Faça algumas medições primeiro!")
    
    except Exception as e:
        # Captura qualquer outro erro e exibe uma mensagem genérica.
        print(f"❌ Erro ao gerar gráfico: {e}")

# ===== LOOP PRINCIPAL =====
def main():
    """
    Função principal que controla o fluxo do programa:
    - Exibe o cabeçalho com arte ASCII.
    - Executa medições em loop até o usuário pressionar 'q'.
    - Salva logs e exibe gráfico ao final.
    """
    
    # Exibe um cabeçalho estilizado com arte ASCII e instruções.
    print("""
╔══════════════════════════════════════════════════════════╗
║                                                          ║
║ 🤖 ROBÔ FOFOQUEIRO - VERSÃO PARANÁENSE 🤖                ║
║                                                          ║
║ "Bora medir o barulho da galera!"                        ║
║ "Égua, que gritaria danada!"                             ║
║                                                          ║
║ Pressione 'q' a qualquer momento para sair              ║
║                                                          ║
╚══════════════════════════════════════════════════════════╝
    """)
    
    # Contador de quantas medições foram realizadas.
    contador_medicoes = 0
    
    # Lista para armazenar todos os valores de dB para cálculo de estatísticas.
    historico_dB = []
    
    try:
        # Loop infinito controlado pelo usuário.
        while True:
            # Incrementa o contador de medições.
            contador_medicoes += 1
            
            # Exibe o número da medição atual.
            print(f"\n🔁 Medição #{contador_medicoes}")
            
            # Chama a função que captura o áudio e retorna os valores.
            dB, alerta, mensagem = medidor_fofoqueiro()
            
            # Salva a medição no arquivo CSV.
            salvar_log(dB, mensagem)
            
            # Adiciona o valor de dB à lista de histórico.
            historico_dB.append(dB)
            
            # Se o alerta estiver ativado (dB > 75), exibe mensagem de destaque.
            if alerta:
                print("🚨 ALERTA! 🚨")
                print("🔴🔴🔴 PASSOU DOS 75 dB! TÁ MUITO ALTO! 🔴🔴🔴")
            
            # Pergunta ao usuário se deseja continuar ou sair.
            comando = input("\nPressione ENTER para nova medição ou 'q' para sair: ")
            
            # Se o usuário digitar 'q' (maiúsculo ou minúsculo), interrompe o loop.
            if comando.lower() == 'q':
                break
    
    except KeyboardInterrupt:
        # Captura o Ctrl+C no terminal e exibe mensagem amigável.
        print("\n\n🛑 Programa interrompido pelo usuário!")
    
    # Exibe um resumo estatístico ao final do programa.
    print("\n" + "="*50)
    print("📊 RESUMO DO ROBÔ FOFOQUEIRO")
    print("="*50)
    print(f"Total de medições realizadas: {contador_medicoes}")
    
    # Só exibe estatísticas se houver pelo menos uma medição.
    if historico_dB:
        print(f"Maior nível registrado: {max(historico_dB):.1f} dB")
        print(f"Menor nível registrado: {min(historico_dB):.1f} dB")
        print(f"Média dos níveis: {sum(historico_dB)/len(historico_dB):.1f} dB")
    
    # Gera o gráfico final com todas as medições.
    print("\n📊 Gerando gráfico final com todo o histórico...")
    mostrar_grafico()
    
    # Mensagem de encerramento.
    print("\n✅ Programa encerrado com sucesso!")
    print("🙏 Valeu por usar o Robô Fofoqueiro - Tchê!")

# Verifica se o script está sendo executado diretamente (não importado como módulo).
if __name__ == "__main__":
    # Exibe instruções de instalação antes de iniciar o programa.
    print("⚠️ IMPORTANTE: Execute no terminal do Colab:")
    print("!pip install pyaudio keyboard matplotlib numpy")
    print("!apt-get install portaudio19dev")
    
    # Aguarda o usuário pressionar ENTER após instalar as bibliotecas.
    input("\nPressione ENTER após instalar as bibliotecas...")
    
    # Chama a função principal para iniciar o programa.
    main()

Checklist de avaliação - Aluno

  • Código funcional que captura som e exibe dB?
  • Log CSV gerado com sucesso?
  • Gráfico plotado ao final com as últimas 10 medições?
  • Participação na discussão sobre "O robô reagiu certo?"
  • Testou diferentes níveis de barulho (sussurro, conversa, grito, palmas)?
  • Os memes e alertas personalizados aparecem corretamente?
Simulação de Coleta de Dados

Clique no botão abaixo para simular uma coleta de dados com diferentes níveis de som:

Critérios de Avaliação

  • Código funcional que captura som e exibe dB
  • Log CSV gerado com sucesso
  • Gráfico plotado ao final
  • Participação na discussão

Dica: "Se o código não rodar, verifica se instalou o pyaudio e o portaudio!"

Plano de Aula - Docente

Título: "Medindo o barulho da galera: o primeiro olho do robô"

Códigos BNCC: EM13CNT104, EM13MAT503, EM13LGG702 | RCP - Paraná: Física - Ondulatória, Matemática - Tratamento da Informação

Duração: 2 aulas (100 minutos)

Materiais: Notebook Colab, microfones, caixa de som


Dicas de mediação
  • Abertura (10min): Desafio "Quanto barulho tem na nossa sala?" - estimativa coletiva
  • Conceituação (15min): Explique decibéis (dB) e como o computador "escuta" (PCM, amostragem)
  • Codificação (40min): Implemente o código em duplas, incentive comentários irreverentes
  • Teste prático (20min): Organize estações: sussurro, conversa, grito, palmas
  • Fechamento (15min): Gere o gráfico e debata "O robô reagiu certo?"
👩‍🏫🧑‍🏫

Kit do Professor

Códigos RCP - Paraná

Física - Ondulatória - Relacionar frequência e intensidade sonora com aplicações práticas
Matemática - Tratamento da Informação - Construir e interpretar gráficos de dados coletados