Postagem em destaque

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte I

Este post é o primeiro de uma série de seis que escrevi tratando de controle de potência e PID (controle proporcional, integral e derivativo...

domingo, 21 de outubro de 2012

Automação no Parque, 20/10/2012

Hoje a Automação no Parque bombou! Com a aproximação da data da guerra de robôs na Anhanguera a turma tá com pressa de deixar tudo no jeito para a arena.
Uma dupla levou um "genérico" de controle de PlayStation 2, via rádio, que eles pretendem usar para controlar o seu robô da categoria Sumô. Eu tinha levado um braço robótico do amigo Fábio, que eu estou recuperando.

Daí... porque não ligar um no outro?

Ligamos o controle PS no Arduino e achamos uma lib para lidar com ele na net. Em seguida implementamos o acionamento de 2 dos motores do braço robô pelo controle, e...



Mais tarde um pouquinho, apareceu o ex-aluno Makson, com o seu TCC. O projeto dele é automação na veia: controle automatizado de um biodigestor. Com dois modos de atuação, automático e manual, o sistema é completamente fiel ao processo que acontece no campo. Monitora automaticamente a temperatura da chama e a pressão do gás, entrando em "modo falha" caso a pressão caia ou a temperatura se mostre abaixo do valor adequado (normalmente porque a chama se apagou). Ou seja, controle malha fechada implementado como deve ser feito.

Abaixo, o diagrama de blocos do projeto, gentilmente cedido pelo Makson:



E aqui um vídeo do equipamento funcionando. Eu começo ligando o equipamento no modo automático. Ele então abre a válvula do gás, aciona o compressor. Em seguida tenta ligar a chama, se a chama é ligada (temperatura alta), acende-se o LED verde indicando que a operação está correta.
Em seguida baixamos a temperatura até o limite em que o sistema entende que a chama apagou (<40 oC). O sistema tenta então por três vezes religar a chama. Caso não consiga, a válvula fecha, o compressor é desligado e o sistema entra em modo falha, piscando o LED vermelho e acionando um alarme sonoro. Para reiniciar é preciso que o operador coloque novamente o sistema em espera e então o coloque em modo automático ou manual. Veja abaixo:


Aqui, outras imagens da brincadeira de ontem. 


Euclides instrui as crianças.

 Receptor do controle de PS2 conectado ao Arduino.



 Receptor do controle em detalhe.
Receptor e controle PS2.

Abaixo, esquema de conexão do controle de biodigestor:



Apareceram também:

- Duas crianças que já tinham ido. Trouxeram motores de passo, que eu testei. O amigo Euclides deu a eles a atenção merecida. Vou ver se consigo reativar um notebook velho que tenho aqui para levar e deixar com quem aparecer e não tiver esse recurso.

- Apareceu o Fábio Luiz, sujeito boa gente que doou para o FreeLab um monte de equipamentos interessantes, alguma sucata mas muito equipamento legal. Fábio, obrigado mais uma vez!

Abaixo, o código fonte do controle do robô pelo controle do PlayStation 2. Para maiores informações sobre como conectar esse tipo de equipamento e a biblioteca que usei podem ser obtidos aqui.

Abaixo, outro esquema de conexão do bicho.




#include <Servo.h>
#include <PS2X_lib.h> 

PS2X ps2x; // cria a classe para controle do PS2

Servo shoulder;
Servo elbow;

int shoulderPos = 180;
int elbowPos = 30;

int error = 0;
byte type = 0;
byte vibrate = 0;

void setup()

{

 Serial.begin(57600);
 shoulder.attach(5);
 elbow.attach(6);

 error = ps2x.config_gamepad(13,11,10,12, true, true);  

 //GamePad(clock, command, attention, data, Pressures?, Rumble?)

 if(error == 0)

 {
   Serial.println("Controle encontrado e configurado");
   Serial.println("Os botões L1 e L2, R1 e L2 acionarão os motores.");
 }
  else if(error == 1)
   Serial.println("Controle não encontrado.");
  else if(error == 2)
   Serial.println("Controle encontrado, mas não aceita comandos.");
  else if(error == 3)
   Serial.println("Controle não aceita modo pressão.");

   type = ps2x.readType();

     switch(type) 
{

       case 0:
        Serial.println("Tipo desconhecido");
        break;

       case 1:
        Serial.println("Controle DualShock");
        break;

       case 2:
         Serial.println("Controle GuitarHero");
         break;
     }
}

void loop()
{
 if(error == 1)
  return;
 ps2x.read_gamepad(false, vibrate);
if (ps2x.NewButtonState())            
 {
        if(ps2x.Button(PSB_L1))
        {
           Serial.println("L1 pressionado");
           elbowPos=elbowPos+5;
           if (elbowPos > 60)
             elbowPos=60;
           elbow.write(elbowPos);
        }          if(ps2x.Button(PSB_L2))
        {
           Serial.println("L2 pressionado");
           elbowPos=elbowPos-5;
           if (elbowPos < 30)
             elbowPos=30;
           elbow.write(elbowPos);
        }  
        if(ps2x.Button(PSB_R1))
        {
           Serial.println("R1 pressionado");
           shoulderPos=shoulderPos+10;
           if (shoulderPos > 180)
             shoulderPos=180;
           shoulder.write(shoulderPos);
        }  
        if(ps2x.Button(PSB_R2))
        {
           Serial.println("R2 pressionado");
           shoulderPos=shoulderPos-10;
           if (shoulderPos < 0)
             shoulderPos=0;
           shoulder.write(shoulderPos);        }  
    }   

    delay(50);
}

sexta-feira, 19 de outubro de 2012

Comunicação Serial

Dia desses, por demanda de um projeto, resolvi criar um programa do tipo linha de comando, para enviar dados através da porta serial. Agora publico o dito, incluindo, como é de lei nesse blog, os fontes.

Para usar o programa, basta fazer o download e copiá-lo para alguma pasta (ia escrevendo "diretório", estou ficando velho...) e usar.

serialcomm -pCOM4 -b9600 -ddadosaenviar -w

Nesse caso o sistema enviará pela porta (-p) COM4, a uma taxa de (-b) 9600 bauds a sequencia de caracteres dadosaenviar (-d). Em seguida esperará (-w) que algum dado seja enviado de volta pela porta, encerrando com CRLF (char(13),char(10)). A sequência enviada sera escrita na tela e então o programa terminará. O parâmetro -w é, obviamente, opcional.

Pode-se também optar por enviar um arquivo em disco inteiro pela porta, para tanto:


serialcomm -pCOM4 -b9600 -farquivo.txt

sendo arquivo.txt o arquivo cujo conteúdo deverá ser enviado pela porta.

É isso. Abaixo, o fonte. Observem que eu usei uma lib chamada CommandLine para implementar o tratamento dos comandos enviados pelo usuário pela linha de comando. Eu acho esse lib sensacional, então aí vai para quem tiver interesse o link para a dita: http://commandline.codeplex.com/



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using CommandLine;
using CommandLine.Text;

namespace SerialComm
{
    sealed class Program
    {
        private static readonly HeadingInfo _headingInfo = new HeadingInfo("SerialComm", "0.9");
        private sealed class Options : CommandLineOptionsBase
        {
            [Option("p", "serialport", DefaultValue = "COM4", HelpText = "Serial port to be used (default=COM4).")]
            public string SerialPort { get; set; }

            [Option("b", "baudrate", DefaultValue = "9600", HelpText = "Speed to be used (bauds, default=9600).")]
            public string BaudRate { get; set; }

            [Option("d", "data", Required = true, HelpText = "Data to be sent.")]
            public string Data { get; set; }

            [Option("f", "filename", Required = false, HelpText = "Name of the file containing data to be sent.")]
            public string FileName { get; set; }

            [Option("w", "wait", HelpText = @"I will wait for data sending back. Sent data will be shown after end of transmition (/r/n ($D$A).")]
            public bool Wait { get; set; }

            [HelpOption]
            public string GetUsage()
            {
                var help = new HelpText
                {
                    Heading = _headingInfo,
                    Copyright = new CopyrightInfo("Mauro Assis (assismauro@hotmail.com)", 2012),
                    AdditionalNewLineAfterOption = true,
                    AddDashesToOption = true
                };
                help.AddOptions(this);
                return help;
            }
        }

        static SerialPort serial = null;
       
        static Options options = new Options();

        static void SendData()
        {
            try
            {
                serial.Write(options.Data);
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("Error sending data to {0}: {1}", options.SerialPort, ex.Message));
            }

        }

        static void SendFile()
        {
            try
            {
                byte[] binaryData = System.IO.File.ReadAllBytes(options.FileName);
                serial.Write(binaryData, 0, binaryData.Length);
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("Error sending file {0} to {1}: {2}",options.FileName, options.SerialPort, ex.Message));
            }
        }

        static void WaitForReply()
        {
            string receivedData=serial.ReadLine();
            Console.WriteLine("Answer:");
            Console.WriteLine(receivedData);
        }
        
        static bool CreateSerialObject()
        {
            try
            {
                serial = new SerialPort(options.SerialPort, Convert.ToInt32(options.BaudRate));
                serial.Open();
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("Error acessing {0}: {1}", options.SerialPort, ex.Message));
                return false;
            }
            return true;
        }

        static void Main(string[] args)
        {
            options = new Options();
            var parser = new CommandLineParser(new CommandLineParserSettings(Console.Error));
            if (!parser.ParseArguments(args, options))
                Environment.Exit(1);
      
            if (CreateSerialObject())
                if (options.Data != string.Empty)
                {
                    SendData();
                    if (options.Wait)
                        WaitForReply();
                    serial.Close();
                }
                else
                    SendFile();
        }
    }
}