Skip navigation

Category Archives: arduino

continuamos revisões e dúvidas durante a primeira parte da sessão. depois entramos no laboratório, onde estamos a desenvolver projectos individuais, colectivos e alguns exercícios a alojar na net.

no pure data focámos noções elementares de programação visual, o que é o som digital, como o sintetisamos e o processamos temporalmente, espacialmente ou espectralmente. ler ficheiros do disco, gerar frequências, ruídos, impulsos, granular inputs,  resintetisar frequências, filtrar microfones, analisar níveis de som, criar processos interactivos. (sessões 11, 12)

ainda analisámos comunicação via rede na própria máquina ou entre várias máquinas, entre o pure data, max e o processing, openframeworks. para tal usamos o protocolo osc através de udp para ser mais rápido, criamos objectos que escrevem e lêem para a rede nos vários ambientes de programação, e por fim criámos programas exemplo que enviam valores de uma aplicação para outra.

introduzimos depois o arduino, e criámos um digitalizador de sensores. fizemos um controlador à base de ldr’s e pot’s numa breadboard, conectamos os sensores ao arduino, e criámos programas que lêem e usam os valores recebidos, gerando sons, sintetisando imagens, controlando estados dinâmicos também com piezos. vimos como o arduino ide é tão semelhante ao processing e o código que usamos também é parecido com java/c. (sessões 13, 14)

ainda fomos usar o arduino como actuador, controlando motores 5v e ventoinhas através dos outputs analógicos conseguimos emitir voltagens variáveis até 5v que controlam directamente ou através de outros componentes motores e actuadores sobre o mundo físico, criando o esboço de uma escultura cinética com led’s, motores e ventoinhas.

por agora já temos umas luzes sobre conceber e implementar interfaces híbridos que recorrem a várias tecnologias, como interfaces à base de computação física usando sensores, arduino, actuadores, outros materiais; interfaces à base de câmara analisando e confrontando as imagens que chegam, destacando posições distintas do fundo, obtendo parâmetros de localização, fazer actuar esses parâmetros; interfaces à base de som, analisando intensidades de frequências e construir listas de valores que fazem oscilar outros algoritmos.

por fim analisamos vários projectos construídos em c++ com o ambiente de programação openframeworks. analisamos a estrutura e funcionamento do compilador, linker, geração de código executável, e expandimos alguns exemplos de processing em c++. primeiro analisamos a programação por objectos, recorrendo a classes que têm variáveis e funções membros, e construímos vários exemplos em c++ que usam partículas, reconhecimento de imagem, som, comunicação por rede, interacções com sons e rato e electrónicas. (sessões 15, 16)

o c++ é mais robusto, um degrau acima na complexidade de escrever código comparado com o processing, mas  com as bibliotecas do openframeworks, torna-se extremamente simples, tal como no processing. a grande diferença é que cada sketch de processing extende a classe base papplet, enquanto que no openframeworks cada aplicação testapp extende a aplicação ofsimpleapp, que engloba a mecânica inicial necessária de uma aplicação c++.

continuamos com a análise de projectos individuais e criação de um laboratório na sala que tenha alguns projectores e câmaras para situações video-interactivas, microfones e colunas, e mesas para construir circuitos entre arduinos e sensores. brevemente mais novidades. boa semana. vejam as plantas, sugiram alternativas,

Anúncios

fizemos revisões de todos os conteúdos das várias linguagens que aprendemos, frisando conceitos chave de programação como variáveis, ciclos for, testes if(){}else{}, classes e objectos, chegar as variáveis a modificar, construir algoritmos base no processing, pd, arduino, openframeworks.

primeiro as noções iniciais de programação exploradas em máquinas de desenhar, onde a posição do rato serve como foco para o lançamento de novos objectos de classes programadas por nós. o sistema de coordenadas cartesiano e o sistema de coordenadas polar. (sessão 2)

primeiras noções de interactividade usando os microfones ligados ao computador, samplando a energia rms sonora, ou um espectro fft que nos dá intensidade por banda de frequência. aplicar os parâmetros do áudio em variáveis que controlam gráficos. noções de classes mais avançadas com os exemplos dos triângulos de som. (sessão 3)

paralelamente, primeiras máquinas lógicas simples, onde a nossa interacção controla um ou mais elementos, e há outros elementos que reagem face à nossa posição, distância, status, etc. os sketches círculos_attack.

depois fomos analisar o tipo de dados pimage e a biblioteca video do processing, que é um tipo de dados que armazena imagens. começamos com os sketches que acedem à informação de cor de cada pixel — criando travelers que oscilam com base nessa cor –, depois ler e scrubbing de video, gravar video e aceder a câmaras. terminamos com acessos mais elaborados à array dos pixels de cada pimage, modificando-os ou lendo-os directamente. (sessão 4)

o próximo tópico foram as partículas e sistemas de partículas, onde elementos simples mantêm variáveis de posição, velocidade, aceleração. a aceleração será o vector que controla a magnitude da deslocação. é também o vector que define a totalidade das forças aplicadas nas partículas. os próximos passos são actualizar a velocidade com a aceleração, actualizar a posição com base na nova velocidade, desenhar o elemento na nova posição. (sessão 5)

introdução ao 3d com noções de coordenadas espaciais, onde está a câmara, onde estão os objectos no espaço, como criar algorimos que gerem formas que se movimentem em três dimensões. (sessão 6)

alguns exemplos mais elaborados de video, como slitscan, delays, texturas em 3d; início do tracking de vídeo: detecção de presença, movimento, background removal, detecção de posição de centróides de blobs, frame differencing, detecção de outras features como caras, mãos, … (sessão 7, 8)

arraylists como recipientes dinâmicos de dados, texto no processing, como ler linhas de texto, separar palavras e espalhá-las espacialmente para desenhar. o sistema esférico (semelhante ao polar, mas em 3d), como desenhar pontos no espaço em forma de esfera e modificá-los com base no som. (sessão 9)

máquinas de estado simples mais avançadas, onde criamos várias classes, obstáculos, bolas, tiros, e todos elas comunicam entre si. cada bola, mesmo as autónomas colidem com os obstáculos, a nossa bola envia tiros que colidem com bolas e obstáculos, e implementamos uma lógica simples quando as bolas em cena terminam, re-iniciamos um novo nível. (sessão 10)

depois vimos puredata, arduino, open frameworks, que ficará como resumo no próximo post.

o curso está na fase laboratorial, estamos activamente a desenvolver projectos individuais e uns projectos colectivos, tirar dúvidas mais específicas em torno de algumas coisas, estamos de antenas apontadas para uma apresentação de projectos de fim de curso que ocorrerá no início de julho.

a sessão de hoje foi dedicada ao arduino. revimos noções base de ligar sensores ao arduino; analisámos modos de leitura de maior precisão; ligação de piezos (besouros / buzzers / contact mics) como input de pressão/contacto ou output de tons sonoros; ligação de motores e controlo de velocidade; mistura de circuitos 5v com circuitos de maior potência.

1. leitura melhor precisão

no lado do arduino colocamos um sensor, e enviamos o valor através do modo DEC. este modo envia cada dígito que compõe o valor em caracter ascii. imediatamente a seguir escrever um caracter new line(\n = 10,13 ascii) que funciona como caracter de controlo identificador do fim do número.

14-arduino_ldr_6203

assim, do lado do pd ou processing ou outro programa, abrimos ligação à porta série do arduino, lemos cada caracter ascii, convertemos em representação numérica, e finalmente eliminamos os espaços para agrupar o número final. este último passo apenas é realizado quando chega o caracter de controlo.

2. piezos

as chapas de cerâmica dos buzzers, além de poderem servir como microfones de contacto, podem ser utilizadas ainda como um sensor de pressão/toque, ou como emissor de tons.

14-arduino_piezo_7315

para funcionarem como sensores, conectamos a cabo preto ao ground e o vermelho à entrada analógica do arduino, e lemos os valores que chegam à porta analógica.

14-arduino_tocar_piezo_10426

para funcionarem como colunas, basta alterar o cabo vermelho para uma porta de saída pwm do arduino, e fazer o upload do código que emite tons para o piezo.

14-arduino_lerpiezo_9490

3. motores

começamos com motores dc de 5v, com algum cuidado podemos ligar directamente ao arduino. com algum cuidado porque costumam enviar picos de corrente em sentido inverso quando desligamos a voltagem. para prevenir esta situação usamos diodos, que bloqueiam a passagem da corrente em sentido inverso.

os motores dc têm 2 pins, um para ground, outro para voltagem. se trocarem a ordem alteram a direcção de rotação. há pontes h para fazer as duas direcções.

14-arduino_motores5v_0941

4. circuitos com ac

é muito comum usar-se o arduino como circuito de controlo de circuitos que requerem mais voltagem e mais intensidade de corrente, além de que já são perigosos, podem queimar o arduino e o computador se as coisas estiverem mal feitas.

como exemplo, ligamos uma ventoinha de 12v e colocamos um potenciómetro a controlar a velocidade da ventoinha. para tal, alimentamos a ventoinha com corrente vinda dum transformador 12v que passa num potenciómetro e escala a voltagem de saída. ainda vimos mais usos com relés, diodos, condensadores e de que formas controlamos aparelhos num circuito mais pesado através das saídas digitais e analógicas do arduino.

14-arduino_ventoinha12v_1232

hoje vemos mais processos áudio de síntese, e iniciamos arduino com dois sensores ligados a um patch de som e um sketch de processing.

1. audio
os patches que analisamos são quase todos do pd-extended, e acedem-se melhor através do browser do pd (menu help > browser ou maçã/ctrl+b). dentro do browser, são tudo exemplos de audio (help browser > 3.audio.examples > c08.etc)

começamos com emulação de sintetisador analógicos, e fomos ver mais patches de samplehold, síntese aditiva, vibrato, complex fm, delay loops e resíntese por fft. aqui ficam algumas imagens dos patches a correrem.

13-c8

13-complexfm1

13-delayfeedback

 

13-fft-resintese

 

 

2. arduino

o arduino é um aparelho que digitaliza o mundo analógico, ou para ele envia voltagens, através do protocolo série (rs-232). hoje vamos ligar dois sensores às portas analógicas do arduino; fazemos um mini-programa no chip do arduino que lê os valores dos sensores e os envia para o computador; por fim criamos um patch e um sketch que lêem os valores e fazem coisas simples, dois osciladores, e dois quadrados.

usamos um LDR, que é uma resistência variável foto-voltaica, e um knob, um potenciometro (ou pot), que também é uma resistência variável, e faz variar a resposta voltaica dos sensores que vamos ler para fazer interagir esses dados.

do arduino fazemos conexões do +5v e do ground para as fileiras horizontais da breadboard. um pin do ldr entra directamente num dos pins de +5v da fileira da breadboard; o outro pin liga-se a uma fileira horizontal. da fileira horizontal da breadboard lemos o sinal para uma das portas analógicas do arduino e finalizamos a ligar uma resistência do fim da fileira para a linha de ground da fileira horizontal da breadboard.

o potenciómetro é mais simples, visto que já tem 3 pins; os exteriores ligam-se aos +5v e ao ground, e ligamos o pin do meio a uma porta analógica do arduino.

13-arduino_4496

depois criamos os programas no arduino ide, e fazemos upload para o chip atmega168 do arduino; o código começa logo a funcionar no chip e a correr os programas que  se seguem. usamos duas versões, um lê um sensor apenas, e outra lê dois valores analógicos:

/// arduino ler um sensor
int valor = 0; // variavel para o valor
int pin = 5; // variavel para o pin de entrada do valor

void setup() {
// open the serial port at 9600 bps:
Serial.begin(9600);
digitalWrite(13,HIGH); //turn on led
}

void loop() {
// ler o valor do pin
valor = analogRead(pin);
// escrever para a porta série o valor
Serial.print(valor, BYTE);
// esperar 10 ms próxima leitura
delay(10);
}

 

/// arduino ler dois sensores
// aqui enviamos um caracter que sincroniza
// no fim da mensagem

int valorldr = 0;
int valorpot = 0;
int pinldr = 5;
int pinpot = 3;

void setup() {
// open the serial port at 9600 bps:
Serial.begin(9600);
digitalWrite(13,HIGH); //turn on led
}

void loop() {
// ler os valores do pin
valorldr = analogRead(pinldr);
valorpot = analogRead(pinpot)/4;
// escrever para a porta série a mensagem
Serial.print(valorldr, BYTE);
Serial.print(valorpot, BYTE);
Serial.print(9); // tab = 9 ascii
// esperar 10 ms próxima leitura
delay(10);
}

 

do lado físico as coisas já estão finalizadas: os valores dos sensores já são enviados para o computador. agora precisamos de os ler. no pd usamos o [comport], um objecto que lê tudo o que chega através de série, no processing fazemos o import da serial lib, configuramos a porta e lemos a data. aqui ficam algumas imagens dos patches e sketches que criámos para começar a ler os valores e brincar com eles. na próxima semana vamos rever esta introdução ao arduino e introduzir actuação física com alguns motores.

13-sensor1

 

13-sensor21

13-p5sensor2

instalar, instalar, abrir os programas, correr exemplos teste, primeiras noções de programação.

a primeira aula foi em torno de uma abordagem aos programas que vamos usar ao longo do curso, bem como da análise da bibliografia que nos vai acompanhar, e finalmente uma primeira abordagem às linguagens de programação e principalmente, programação por objectos.

ainda falta instalar os compiladores nas máquinas para ter o openframeworks a funcionar (para os mac’s, instalar o x-code, para os pc’s, instalar o code::blocks), mas já conseguimos abrir o processing, pd e arduino, o que não foi nada mal para primeira sessão.

o tema principal desta primeira sessão foi a análise de um primeiro programa exemplo em processing, que já usa programação por objectos. vimos que cada variável tem um tipo, e que esse tipo pode ser ou um tipo básico de dados (boolean, int, float, char, string…), ou então um tipo/class/objecto por nós preparado, que consiste no diferente re-arranjo de várias variáveis de tipos básicos.

assim, quando na primeira linha do programa declaramos uma variável que se chama circulo do tipo Circulo, estamos já a pressupor que este tipo Circulo está por nós definido algures.

Circulo circulo;

na definição dos objectos vimos que os pontos principais correspondem à criação de variáveis membro que fazem parte desse mesmo objecto, bem como das funções próprias de cada classe. A função principal que é chamada aquando da criação do objecto é o chamado construtor, que instancia variáveis e lhes atribui valores.

o objecto Circulo está definido como:

class Circulo {

float posx, posy, rad;

Circulo(){
rad = random(10,30);
posx = random(rad,width-rad);
posy = random(rad,height-rad);
}

void draw(){

stroke(0);
fill(82,247,195);

ellipse(posx,posy,rad,rad);

}

void reset(){
posx = random(rad,width-rad);
posy = random(rad,height-rad);

}

}

o objecto Circulo tem 3 variáveis fraccionárias, posx, posy, e rad. o construtor do objecto quando é chamado atribui valores aleatórios a cada um destes campos e que têm a ver com a própria variável. o raio, rad, só tem valores de 10 a 30, as posições têm valores entre rad e largura e altura menos rad, para que sejam instanciados dentro da tela. além do construtor do objecto, temos mais duas funções, uma chamada draw e outra chamada reset, ambas do tipo void, porque não devolvem parâmetros nenhuns (por oposição à função random que devolve um parâmetro float quando é chamada)

o objecto circulo do tipo Circulo é criado na função setup(), através desta linha:

circulo = new Circulo(); // criar um novo circulo

depois desta linha ser executada, temos a certeza que a nossa variável circulo tem agora três campos, já com valores atribuídos, valores esses que são aleatórios, ie, calculados através do random(min,max). podemos aceder aos campos para os usar em funções fora da classe através do ‘.’, ex:

circulo.posx = 100; // colocar a variável posx do obj circulo com o valor 100
circulo.rad = (2*frameCount % 50); // atribuir ao raio duas vezes o número de frames que já passaram, entre 0 e 50

circulo.posy = circulo.posy + 1; // novo valor de y é igual ao valor antigo mais 1

ou então, dentro do próprio objecto, não precisamos do ponto para aceder aos valores da função. reparem que na função draw acedemos aos valores actuais posx, posy, e rad sem usarmos o ponto, pois estamos dentro do objecto.

além de aceder às variáveis fora do objecto, podemos aceder às funções:

circulo.draw(); // chamar a função draw do objecto circulo

circulo.reset(); // chamar a função reset do objecto circulo

e pronto, feito o objecto, podemos agora começar a brincar com ele/eles.(eles + à frente).

lembrem-se que no processing a função setup é corrida em primeiro lugar uma única vez, que serve para inicializar janela/som/variáveis/etc. depois é a função draw que faz um loop contínuo infinito até que optemos por terminar o programa com o esc.

esta função draw executa os seguintes passos:

1. background (58,95,83);
2. go_mouse();
3. circulo.draw();

1. apaga sempre a frame anterior e preenche a tela com aquela cor rgb
2. mexe nas coordenadas do círculo em função do pressionamento do botão
3. desenha o círculo com as coordenadas actuais

e faz estes 3 passos continuamente, em loop.

a função go_mouse é que mexe nas coordenadas do círculo, em função das coordenadas do rato e se carregamos no botão.

é definido principalmente com um bloco de código

if (condição v ou f) {
//este código é executado se a condição for V
} else {
//este código é executado se a condição for F
}

e a nossa condição é o mousePressed. se o rato for premido, o círculo tende a ir ter com a posição do rato, se for largado, o circulo afasta-se do rato. usamos um low pass filter para alterar as posições, é um filtro comum e simples que suaviza as transições de valores.

assim, o programa completo para adicionar à classe Circulo criada acima é o seguinte:

/// circulo , processing, som do pensamento

Circulo circulo; //declarar a variável do tipo Circulo

void setup(){
size(500,281); // criar uma janela
circulo = new Circulo(); // criar um novo circulo

//overwrite dos valores das variáveis mouse e mousePressed
mouseX = width/2;
mouseY = height/2;
mousePressed = true;
}

void draw(){

background (58,95,83);
go_mouse();
circulo.draw();

}

void go_mouse(){

if(mousePressed){
// um filtro low pass ao movimento com destino ao rato
float filter = 0.01;
circulo.posx = circulo.posx * (1.0-filter) + mouseX * filter;
circulo.posy = circulo.posy * (1.0-filter) + mouseY * filter;
} else {
//se o rato não premido, afastamo-nos
float filter = 0.01;
// calcular um vector com origem no rato até ao circulo
float dx = circulo.posx – mouseX;
float dy = circulo.posy – mouseY;
// as coordenadas de destino são a posição do círculo + o vector
circulo.posx = circulo.posx * (1.0-filter) + (circulo.posx +dx) * filter;
circulo.posy = circulo.posy * (1.0-filter) + (circulo.posy +dy) * filter;

}

}

outro ponto importante que observámos foi a localidade das variáveis. posso ter duas variáveis filter dentro desta função go_mouse() porque o seu alcance não se toca, estão em níveis distintos, podem ter valores diferentes, só existem dentro das chavetas em que são declaradas.

este programa instancia apenas um círculo, de seguida, vimos um programa que instancia N circulos, e a grande alteração foi inserir os ciclos for e alterar a variável circulo para uma array de variáveis circulos.

este é o segundo programa, mantendo a classe Circulo acima definida.

Circulo circulos[];
int NUM_CIRCULOS = 10;

void setup(){
size(500,281); // criar uma janela

circulos = new Circulo[NUM_CIRCULOS]; // criar espaço na memória para N variáveis do tipo Circulo
for(int i=0; i<NUM_CIRCULOS; i++) {
circulos[i] = new Circulo(); // instanciar cada uma das variáveis Circulo
}

//overwrite dos valores das variáveis mouse e mousePressed
mouseX = width/2;
mouseY = width/2;
mousePressed = true;
}

void draw(){

background (58,95,83);
go_mouse();
for(int i=0; i<NUM_CIRCULOS; i++) {
circulos[i].draw();
}

}

void go_mouse(){

for(int i = 0; i < NUM_CIRCULOS; i++) {

if(mousePressed){
// um filtro low pass ao movimento com destino ao rato
float filter = 0.01;
circulos[i].posx = circulos[i].posx * (1.0-filter) + mouseX * filter;
circulos[i].posy = circulos[i].posy * (1.0-filter) + mouseY * filter;
}
else {
//se o rato não premido, afastamo-nos
float filter = 0.01;
// calcular um vector com origem no rato até ao circulo
float dx = circulos[i].posx – mouseX;
float dy = circulos[i].posy – mouseY;
// as coordenadas de destino são a posição do círculo + o vector
circulos[i].posx = circulos[i].posx * (1.0-filter) + ( circulos[i].posx +dx) * filter;
circulos[i].posy = circulos[i].posy * (1.0-filter) + ( circulos[i].posy +dy) * filter;
}

}

}

as alterações não são muitas, e já podemos ver a riqueza de começar a programar com objectos: agora com o mesmo código que tinhamos usado para apenas um circulo, podemos ter o mesmo comportamento para N circulos.

algumas imagens dos programas com 1 circulo e N circulos

circulo_26

circulos31

no fim da aula o nuno disse-me que com mil circulos a coisa já ficava lenta. pois é. o comando para desenhar um círculo (ellipse no processing) é mais pesado que o comando para desenhar um quadrado. a outra coisa que lhe mostrei foi o mesmo código em c++ no openframeworks, e aí os mil círculos já andavam bem a 60 frames por segundo.

ainda antes de terminar a primeira aula, vimos a funcionar um programa mais avançado, que consistia em duas partes a comunicar por rede através do protocolo OSC (open sound control) no próprio computador. uma parte para analisar blobs no movimento da imagem, a outra parte sintetisa som a partir das coordenadas das blobs. a parte que analisa a imagem pelas blobs, construí há pouco tempo uma aplicação no openframeworks para ter a melhor performance possível na parte da análise de imagem. chama-se blosc e têm o código na pasta da aula, bem como binários para o osx prontos a executar aqui. a segunda parte é um patch em pure data, que recebe na própria máquina, na port 7737, os valores calculados pela aplicação e usa os valores para controlar 10 osciladores que funcionam de acordo com as blobs analisadas.

aqui ficam imagens em funcionamento dos dois programas, e serve já para uma introdução a síntese sonora, sendo que o som e a continuação da análise de tarefas simples de programação é o que nos vai ocupar nos próximos tempos.

blosc-34

blosc-pd-37

até para a semana! leiam se puderem os livros, começem a ler os capítulos introdutórios que têem estas noções sobre variáveis e objectos e ciclos, etc, e tragam dúvidas que encontrem pelo caminho. boas leituras.