Página 1 de 1

midi2pu - um conversor MIDI para LEGO

Enviado: 23 abr 2025, 18:17
por CyberX
Extendi o meu DIY sensor compatível com LEGO Powered Up
com uma outra library para Arduino que permite usar MIDI, um protocolo usado para interligação de instrumentos e outros equipamentos musicais.

O MIDI originalmente utilizava fichas DIN de 5 pinos, ainda existe muito equipamento com pelo menos uma dessas fichas (IN ou OUT, por vezes também TRU para permitir daisy chaining) mas depois foi extendida para o USB MIDI (e mais recentemente para Bluetooth embora com bastante menos sucesso, vá-se lá perceber porquê >:D )

Como os microcontroladores que tenho estado a usar têm todos USB é muito fácil criar um dispositivo USB MIDI apenas com software (uma library chamama Control_Surface). Também seria possível DIN mas teria de soldar alguns componentes adicionais, assim é muito mais simples, a única diferença é que não é possível ligar directamente dois dispositivos USB MIDI sem pelo meio haver um "USB MIDI host" que faça o routeamento das mensagens MIDI. Nada que não haja cá em casa.

Com um Raspberry Pi Pico 2, um cabo vindo da Ásia e uma caixa pequena temos um dispositivo relativamente discreto:

Imagem

Imagem

Resumo da implementação:
- com o Control_Surface o meu microcontrolador apresenta-se como um dispositivo MIDI e consigo "escutar" mensagens como por exemplo as notas enviadas por um teclado MIDI
- com a minha variante do MyOwnBricks consigo enviar dados para o Hub Technic
- com mais meia duzia de linhas de C++ junto as duas libraries e reencaminho as notas MIDI recebidas por USB para a ficha PU
- no Pybricks aciono cada um de 3 motores conforme as notas recebidas



Vantagens:
- não há Bluetooth pelo meio logo não há latência
- é possível ter mais micontroladores em paralelo, cada um ligado a um Hub, todos eles pendurados num único HUB USB

Desvantagens:
- como o Technic Hub só tem 4 portas Powered Up, gastando uma com o conversor só posso controlar 3 motores; se quiser usar isto com a gaita de foles que tem 8 "dedos" preciso de 3 Technic Hubs
- não há latência mas também não há milagres, ainda tenho de estudar isto do Control_Surface para evitar algumas situações que ocorrem quando estou a tocar mais que uma nota ao mesmo tempo e páro demasiado rápido

Re: midi2pu - um conversor MIDI para LEGO

Enviado: 26 abr 2025, 09:24
por CyberX
"tenho de estudar isto do Control_Surface para evitar algumas situações que ocorrem quando estou a tocar mais que uma nota ao mesmo tempo e páro demasiado rápido"
isto já apanhei, tem mais a ver com a library que implementa Powered Up do que a library MIDI:

por qualquer motivo não dá vazão a mais que dez transmissões por segundo para o HUB LEGO; penso que esta limitação venha de alguma opção menos eficiente no código da library já que o microcontrolador executa cerca de 200 milhões de instruções por segundo e o protocolo LEGO PU comunica a 115200 bps, mesmo com o overhead do protocolo daria perfeitamente para 1000 transmissões por segundo;

além disso, por opção minha, apenas estou a enviar um byte a cada transmissão (estou a reaproveitar código anterior, até aqui limitei-me a emular um dispositivo capaz de enviar ou receber 1 byte apenas mas é possível mais)

quando faço um acorde de 2 notas no teclado midi, são gerados 2 eventos de "note on" e quando largo simutâneamente as 2 teclas são gerados 2 eventos de "note off". Da maneira que estava a processar os eventos, apenas um era enviado a cada ciclo de transmissão e por isso por vezes o acorde apenas activava um motor e por vezes o final do acorde não desactivava todos os motores (e das vezes que funcionava era porque na verdade havia uma pequena diferença de tempo entre os meus dedos e isso permitia o envio dos eventos em separado)

Implementei uma queue FIFO do lado da recepção MIDI e a cada 100 ms tiro o primeiro evento e envio.

Assim já funciona bem mas assim num acorde de 2 notas uma delas chega ao hub 100 ms depois da outra e num acorde de 3 notas uma delas chega 100 ms e outra chega 200 ms o que já começa a ser mau. Vou ter de implementar a possibilidade de enviar 3 bytes a cada transmissão para poder dar resposta a acordes de até 3 notas.

E enquanto não descobrir a razão da limitação a 10 transmissões por segundo fico-me com um lag de 100 ms na resposta a eventos MIDI e um limite a 5 notas por segundo (5 eventos 'note on' e 5 eventos 'note off') o que não me preocupa muito, numa música moderna não-trash metal o ritmo anda em torno das 2 notas por segundo.

Quando for implementar outros conversores (tenho pelo menos a ideia de um DMX2PU para poder integrar uma máquina de bolhas de sabão em LEGO num sistema DMX de controlo de palco) terei de ter em conta estas limitações.

Re: midi2pu - um conversor MIDI para LEGO

Enviado: 14 mai 2025, 10:27
por CyberX
CyberX Escreveu: 26 abr 2025, 09:24 por qualquer motivo não dá vazão a mais que dez transmissões por segundo para o HUB LEGO; penso que esta limitação venha de alguma opção menos eficiente no código da library já que o microcontrolador executa cerca de 200 milhões de instruções por segundo e o protocolo LEGO PU comunica a 115200 bps, mesmo com o overhead do protocolo daria perfeitamente para 1000 transmissões por segundo;
Ao fim de quase duas semanas a partir pedra lá descobri a razão das 10 transmissões por segundo: os exemplos do MyOwnBricks apenas invocam um comando ("process") que se limita a responder ao HUB apenas quando este lhe pergunta "estás aí?", o que acontece exactamente de 100 em 100 ms (10 vezes por segundo portanto).

Lá descobri que posso invocar outro comando para forçar o microcontrolador a enviar para o HUB. Estou a fazê-lo agora cada 10 ms (portanto 100x por segundo) e funciona bastante bem, podia até puxar mais por ele mas para MIDI está bem assim, consigo reencaminhar streams de 300 bpm (beats por minuto) sem problema:



Uma música em geral anda entre os 90 e os 120 bpm, apenas coisas como o Death Metal chegam aos 300 bpm e não estou a pensar ir por aí :D

No video uso um sequencidor MIDI que envia um evento a cada batimento. Como uma nota tem dois eventos ("note on" seguido de "note off") e o meu código no HUB apenas se limita a fazer o motor rodar com note on e pará-lo com note off, quando o ritmo é muio alto o motor mal tem tempo para arrancar quando já o estão a mandar parar.

Por isso agrupei alguns batimentos para alongar os eventos: os primeiros 4 accionam o primeiro motor, os 2 últimos o terceiro motor.

Uma alternativa seria do lado do HUB implementar código para alongar a duração de cada motor mas por enquanto não quero ir por aí, quero manter isto generalista o suficiente.