Índice:

Infinity Bike - Vídeo game de treinamento de bicicleta dentro de casa: 5 etapas
Infinity Bike - Vídeo game de treinamento de bicicleta dentro de casa: 5 etapas

Vídeo: Infinity Bike - Vídeo game de treinamento de bicicleta dentro de casa: 5 etapas

Vídeo: Infinity Bike - Vídeo game de treinamento de bicicleta dentro de casa: 5 etapas
Vídeo: Subway Surfers dançarino 😂 2024, Setembro
Anonim
Image
Image
Materiais
Materiais

Durante o inverno, dias frios e mau tempo, os entusiastas do ciclismo têm poucas opções para se exercitar praticando seu esporte favorito. Estávamos procurando uma maneira de tornar o treinamento interno com uma configuração de bicicleta / treinador um pouco mais divertido, mas a maioria dos produtos disponíveis são caros ou simplesmente enfadonhos de usar. É por isso que começamos a desenvolver o Infinity Bike como um videogame de treinamento de código aberto. A bicicleta infinita lê a velocidade e a direção da sua bicicleta e oferece um nível de interatividade que não pode ser facilmente encontrado com os treinadores de bicicleta.

Aproveitamos a simplicidade disponível do microcontrolador Arduino e algumas peças impressas em 3D para proteger sensores baratos para uma bicicleta montada em um treinador. A informação é retransmitida para um videogame feito com o popular mecanismo de criação de jogos, Unity. Ao final deste instrutível, você deve ser capaz de configurar seus próprios sensores em sua bicicleta e transferir as informações de seus sensores para o Unity. Incluímos até uma pista na qual você pode pedalar e testar sua nova configuração. Se estiver interessado em contribuir, você pode conferir nosso GitHub.

Etapa 1: Materiais

Materiais
Materiais

A lista de materiais de que você precisa pode variar um pouco; para

Por exemplo, o tamanho da sua bicicleta ditará os comprimentos dos cabos auxiliares de que você precisa, mas aqui estão as peças principais de que você precisa. Você provavelmente poderia encontrar preços mais baratos para cada peça em um site como o AliExpress, mas esperar 6 meses pelo envio nem sempre é uma opção, então estava usando as peças um pouco mais caras para que a estimativa não seja distorcida.

1 x Arduino nano ($ 22,00)

1 x Mini breadboard ($ 1,33 / unidade)

1 x resistor de 220 Ohm ($ 1,00 / kit)

1 x Potenciômetro de 10K ($ 1,80 / unidade)

1 x sensor Hall ($ 0,96)

Correia dentada de impressora 3D de 20 cm x 6 mm ($ 3,33)

1 kit x parafusos e parafusos M3 de vários comprimentos ($ 6,82)

1 x ímã velocímetro de bicicleta ($ 0,98)

Montamos o material acima com peças impressas em 3D. Os arquivos que utilizamos estão listados abaixo e são numerados com a mesma convenção da imagem no início desta seção. Todos os arquivos podem ser encontrados no Thingiverse. Você pode usá-los como estão, mas certifique-se de que as dimensões que usamos correspondem à sua bicicleta.

1. FrameConnection_PotentiometerHolder_U_Holder.stl

2. FrameConnection_Spacer.stl

3. BreadboardFrameHolder.stl

4. Pulley_PotentiometerSide.stl

5. Pot_PulleyConnection.stl

6. FrameConnection.stl

7. Pulley_HandleBarSide_Print2.stl

8. FrameToHallSensorConnector.stl

9. PotHolder.stl

10. HallSensorAttach.stl

Etapa 2: Leitura e transferência de dados para o Unity

Lendo e transferindo dados para o Unity
Lendo e transferindo dados para o Unity

O código do Arduino e do Unity trabalharão juntos para coletar, transferir e processar os dados dos sensores na bicicleta. O Unity solicitará o valor do Arduino enviando uma string pelo serial e aguardará que o Arduino responda com os valores solicitados.

Primeiro, preparamos o Arduino com a biblioteca Serial Command, que é usada para gerenciar as solicitações do Unity, emparelhando uma string de solicitação com uma função. Uma configuração básica para esta biblioteca pode ser feita como segue;

#include "SerialCommand.h"

SerialCommand sCmd; void setup () {sCmd.addCommand ("TRIGG", TriggHanlder); Serial.begin (9600); } void loop () {while (Serial.available ()> 0) {sCmd.readSerial (); }} void TriggHandler () {/ * Leia e transmita os sensores aqui * /}

A função TriggHandler é anexada ao objeto SCmd. Se o serial receber uma string que corresponda ao comando anexado (neste caso TRIGG), a função TriggHandler é executada.

Usamos potenciômetro para medir a direção da direção e um sensor Halls para medir a rotação por minuto da bicicleta. As leituras do potenciômetro podem ser feitas facilmente usando as funções integradas do Arduino. A função TriggHandler pode então imprimir o valor no serial com a seguinte alteração.

void TriggHandler () {

/ * Lendo o valor do potenciômetro * / Serial.println (analogRead (ANALOGPIN)); }

O sensor Hall tem um pouco mais de configuração antes que possamos ter medições úteis. Ao contrário do potenciômetro, o valor instantâneo do sensor Halls não é muito útil. Já que estávamos tentando medir a velocidade da roda, o tempo entre os gatilhos é o que estava interessado.

Cada função usada no código do Arduino leva tempo e, se o ímã se alinhar com o sensor Hall no momento errado, a medição pode ser atrasada na melhor das hipóteses ou totalmente ignorada na pior. Isso é obviamente ruim porque o Arduino pode relatar uma velocidade MUITO diferente da velocidade real da roda.

Para evitar isso, usamos um recurso do Arduinos chamado attach interrupt que nos permite acionar uma função sempre que um pino digital designado é acionado com um sinal crescente. A função rpm_fun é anexada a uma interrupção com uma única linha de código adicionada ao código de configuração.

void setup () {

sCmd.addCommand ("TRIGG", TriggHanlder); attachInterrupt (0, rpm_fun, RISING); Serial.begin (9600); } // A função rpm_fun é usada para calcular a velocidade e é definida como; não assinado long lastRevolTime = 0; sem sinal longo revolSpeed = 0; void rpm_fun () {sem sinal longo revolTime = millis (); deltaTime longo sem sinal = revolTime - lastRevolTime; / * revolSpeed é o valor transmitido ao código do Arduino * / revolSpeed = 20000 / deltaTime; lastRevolTime = revolTime; } O TriggHandler pode então transmitir o resto das informações quando solicitado. void TriggHanlder () {/ * Lendo o valor do potenciômetro * / Serial.println (analogRead (ANALOGPIN)); Serial.println (revolSpeed); }

Agora temos todos os blocos de construção que podem ser usados para construir o código do Arduino, que irá transferir dados por meio do serial para quando uma solicitação for feita pelo Unity. Se você quiser uma cópia do código completo, pode baixá-lo em nosso GitHub. Para testar se o código foi configurado corretamente, você pode usar o monitor serial para enviar TRIGG; certifique-se de definir o final da linha como Retorno de carro. A próxima seção se concentrará em como nossos scripts do Unity podem solicitar e receber as informações do Arduino.

Etapa 3: recebimento e processamento de dados

Recebendo e processando dados
Recebendo e processando dados

O Unity é um ótimo software disponível gratuitamente para amadores

interessado na criação de jogos; ele vem com um grande número de funcionalidades que podem realmente reduzir o tempo de configuração de certas coisas, como threading ou programação de GPU (AKA shading), sem restringir o que pode ser feito com os scripts C #. Os microcontroladores Unity e Arduino podem ser usados juntos para criar experiências interativas exclusivas com um orçamento relativamente pequeno.

O foco deste instrutível é ajudar a configurar a comunicação entre o Unity e o Arduino para que não nos aprofundemos muito na maioria dos recursos disponíveis com o Unity. Existem muitos tutoriais ÓTIMOS para o Unity e uma comunidade incrível que poderia fazer um trabalho muito melhor explicando como o Unity funciona. No entanto, há um prêmio especial para quem conseguir percorrer este instrutivo que serve como uma pequena vitrine do que poderia ser feito. Você pode baixar em nosso Github nossa primeira tentativa de fazer uma pista com física de bicicleta realista.

Primeiro, vamos examinar o mínimo que precisa ser feito para se comunicar com um Arduino por meio do serial. Ficará rapidamente aparente que este código não é adequado para o jogo, mas é bom passar por cada etapa e aprender quais são as limitações.

No Unity, crie uma nova cena com um único GameObject vazio denominado ArduinoReceive em anexar um script C # também denominado ArduinoReceive. É nesse script que adicionaremos todo o código que trata da comunicação com o Arduino.

Existe uma biblioteca que deve ser acessada antes que possamos nos comunicar com as portas seriais do seu computador; O Unity deve ser configurado para permitir o uso de certas bibliotecas. Vá para Edit-> ProjectSerring-> Player e próximo ao Api Compatibility Level em Configuration switch. NET 2.0 Subset to. NET 2.0. Agora adicione o seguinte código na parte superior do script;

using System. IO. Ports;

Isso permitirá que você acesse a classe SerialPort, que pode ser definida como um objeto para a classe ArduinoReceive. Torne-o privado para evitar qualquer interferência de outro script.

private SerialPort arduinoPort;

O objeto arduinoPort pode ser aberto selecionando a porta correta (por exemplo, em qual USB o Arduino está conectado) e uma taxa de transmissão (ou seja, a velocidade na qual as informações são enviadas). Se você não tiver certeza de em qual porta o Arduino está conectado, você pode descobrir no gerenciador de dispositivos ou abrindo o IDE do Arduino. Para a taxa de transmissão, o valor padrão na maioria dos dispositivos é 9600, apenas certifique-se de ter esse valor em seu código Arduino e ele deve funcionar.

O código agora deve ter a seguinte aparência;

using System. Collections;

using System. Collections. Generic; using UnityEngine; using System. IO. Ports; public class ArduinoReceive: MonoBehaviour {private SerialPort arduinoPort; // Use para inicialização void Start () {arduinoPort = new SerialPort ("COM5", 9600); arduinoPort. Open (); WriteToArduino ("TRIGG"); }}

O seu número COM provavelmente será diferente. Se você estiver em um MAC, seu nome COM pode ter um nome parecido com /dev/cu.wchusbserial1420. Certifique-se de que o código da seção 4 seja carregado no Arduino e o monitor serial esteja fechado para o resto desta seção e que este código seja compilado sem problemas.

Vamos agora enviar uma solicitação para o Arduino a cada quadro e gravar os resultados na janela do console. Adicione a função WriteToArduino à classe ArduinoReceive. O retorno de carro e a nova linha são necessários para que o código do Arduino analise a instrução de entrada corretamente.

private void WriteToArduino (mensagem de string)

{mensagem = mensagem + "\ r / n"; arduinoPort. Write (mensagem); arduinoPort. BaseStream. Flush (); }

Essa função pode então ser chamada no loop de atualização.

void Update ()

{WriteToArduino ("TRIGG"); Debug. Log ("Primeiro valor:" + arduinoPort. ReadLine ()); Debug. Log ("Segundo valor:" + arduinoPort. ReadLine ()); }

O código acima é o mínimo necessário para ler os dados de um Arduino. Se você prestar atenção ao FPS dado pela unidade, verá uma queda significativa no desempenho. No meu caso, vai de cerca de 90 FPS sem ler / escrever para 20 FPS. Se o seu projeto não requer atualizações frequentes, pode ser suficiente, mas para um videogame, 20 FPS é muito baixo. A próxima seção cobrirá como você pode melhorar o desempenho usando multiencadeamento.

Etapa 4: Otimizando a transferência de dados

A seção anterior cobriu como configurar o básico

comunicação entre o programa Arduino e Unity. O maior problema com esse código é o desempenho. Em sua implementação atual, o Unity precisa esperar que o Arduino receba, processe e responda a solicitação. Durante esse tempo, o código do Unity tem que esperar que a solicitação seja feita e não faz mais nada. Resolvemos esse problema criando um encadeamento que tratará das solicitações e armazenará a variável no encadeamento principal.

Para começar, devemos incluir a biblioteca de encadeamento adicionando;

using System. Threading;

A seguir, configuramos a função que estamos iniciando nas threads. AsynchronousReadFromArduino começa gravando a solicitação no Arduino com a função WrtieToArduino. A leitura é incluída em um bloco try-catch, se a leitura expirar, as variáveis permanecerão nulas e a função OnArduinoInfoFail será chamada em vez de OnArduinoInfoReceive.

Em seguida, definimos as funções OnArduinoInfoFail e OnArduinoInfoReceive. Para isso, imprimimos os resultados no console, mas você pode armazenar os resultados nas variáveis de que precisa para o seu projeto.

private void OnArduinoInfoFail ()

{Debug. Log ("Falha na leitura"); } private void OnArduinoInfoReceived (rotação da string, velocidade da string) {Debug. Log ("Readin Sucessfull"); Debug. Log ("Primeiro valor:" + rotação); Debug. Log ("Segundo valor:" + velocidade); }

A última etapa é iniciar e parar os threads que solicitarão os valores do Arduino. Devemos garantir que o último thread seja concluído com sua última tarefa antes de iniciar um novo. Caso contrário, várias solicitações podem ser feitas ao Arduino de uma só vez, o que pode confundir o Arduino / Unity e produzir resultados imprevisíveis.

privado Thread activeThread = null;

void Update () {if (activeThread == null ||! activeThread. IsAlive) {activeThread = new Thread (AsynchronousReadFromArduino); activeThread. Start (); }}

Se você comparar o desempenho do código com o que escrevemos na seção 5, o desempenho deve ser significativamente melhorado.

private void OnArduinoInfoFail ()

{Debug. Log ("Falha na leitura"); }

Etapa 5: onde virá a seguir?

Onde próximo?
Onde próximo?

Preparamos uma demonstração que você pode baixar em nosso Github (https://github.com/AlexandreDoucet/InfinityBike), baixar o código e o jogo e pedalar por nossa trilha. Está tudo configurado para um treino rápido e esperamos que possa lhe dar uma amostra do que você pode construir se usar o que ensinamos com este instrutível.

Créditos

Contribuintes do projeto

Alexandre Doucet (_Doucet_)

Maxime Boudreau (MxBoud)

Recursos externos [The Unity game engine] (https://unity3d.com)

Este projeto começou depois que lemos o tutorial de Allan Zucconi "como integrar o Arduino com o Unity" (https://www.alanzucconi.com/2015/10/07/how-to-int…)

As solicitações do Arduino são tratadas usando a biblioteca SerialCommand (https://github.com/kroimon/Arduino-SerialCommand)

Recomendado: