
Em preparação para o fórum anual de TI, surgiu a idéia de criar um manipulador simples controlado por um gamepad sem fio para demonstrar os recursos de microcontroladores e computadores de placa única. Estava à mão um controlador TRIC, vários servomotores, um construtor de ferro e um mês antes do início do fórum.
"Tudo está indo conforme o planejado", mas não neste caso.
Etapa 1. Preparação
O TRIC a bordo do Linux foi um fracasso para um manipulador desse tipo, mas “a coisa é usabilidade e manutenção banais” (citação do ClusterM sobre o Linux em um interfone inteligente ).
Depois de ler a especificação , descobriu-se que ele possui Bluetooth. Se você trabalhou com este controlador, sabe que a transferência de programas é via Wi-Fi e não há outras maneiras convenientes de se comunicar com ele. Não há menção de Bluetooth no menu. Mas como assim?
Armado com SSH, uma chave de fenda e curiosidade, comecei a procurar por Bluetooth. O sistema incluía hcitool, hciconfig e o daemon bluetoothd. Todos eles disseram que ele não estava lá.
root@trik-7dda93:~
root@trik-7dda93:~
root@trik-7dda93:~
Ligando para amigos em busca de um módulo USB externo, continuei pesquisando.
Depois de desmontar o controlador, o módulo Jorjin WG7311-0A foi encontrado. A especificação afirma que realmente há Wi-Fi, Bluetooth e até um rádio FM. A interface para comunicação com Bluetooth é UART e é ativada via BT_EN.

Depois de ler como o módulo Bluetooth é conectado via UART via hcitool, tentei a sorte e nada. Duas das três portas UART gratuitas estavam silenciosas.
Mas temos o contato BT_EN! É possível que o módulo esteja simplesmente desligado e não responda às solicitações. Após examinar o dispositivo do kernel do Linux para dispositivos ARM, foi encontrado um arquivo em que todos os contatos usados pelo SoC são registrados. Ao abrir arch/arm/mach-davinci/board-da850-trik.c
no código-fonte do kernel, um contato GPIO para Bluetooth foi realmente encontrado. Vitória! Eu pensei.
static const short da850_trik_bluetooth_pins[] __initconst = { DA850_GPIO6_11, DA850_GPIO6_10, -1 };
Etapa 2. Ofensivo
Para habilitar um contato através do GPIO, você precisa encontrar o número de série de ponta a ponta. Encontramos a seguinte linha no código do kernel com uma solicitação para inicializar o contato BT_EN_33 em arch/arm/mach-davinci/board-da850-trik.c
:
ret = gpio_request_one(GPIO_TO_PIN(6, 11), GPIOF_OUT_INIT_LOW, "BT_EN_33")
Ele usa a macro GPIO_TO_PIN. Veja a descrição da macro em arch/arm/mach-davinci/include/mach/gpio-davinci.h
:
#define GPIO_TO_PIN(bank, gpio) (16 * (bank) + (gpio))
Usando-o, você pode encontrar o número de contato completo. Nós entendemos que 16 * 6 + 11 = 107. Agora nos voltamos para a inclusão do contato.
echo 1 >> /sys/devices/virtual/gpio/gpio107/value
0 ou 1 no comando echo é o estado do contato.
Execute o comando para conectar e ...
root@trik-7dda93:~
incompreensível para nós (no momento) mensagens de erro. Tentamos configurar o dispositivo através do hcitool:
root@trik-7dda93:~
Não há dispositivos, embora a inicialização supostamente tenha sido aprovada. Tentamos conectar uma segunda vez, mas com um tipo diferente de adaptador:
root@trik-7dda93:~
E novamente, nada. Vamos voltar ao primeiro erro e aplicar o conhecimento de inglês:
Warning: cannot find BTS file: /lib/firmware/TIInit_7.6.15.bts
Abrimos a pasta / lib / firmware com firmware e não encontramos o arquivo que precisamos. Após uma longa pesquisa na Internet, encontramos o arquivo desejado no repositório da TI e o fazemos o download. Outras versões do mesmo arquivo se recusaram a funcionar.
curl -k https://git.ti.com/wilink8-bt/ti-bt-firmware/blobs/raw/45897a170bc30afb841b1491642e774f0c89b584/TIInit_7.6.15.bts > TIInit_7.6.15.bts cp TIInit_7.6.15.bts /lib/firmware/TIInit_7.6.15.bts
Reinicializamos o controlador e reconectamos:
root@trik-7dda93:~
Viva! O firmware foi inicializado. Verificando hciconfig:
root@trik-7dda93:~
Iniciamos o serviço bluetoothd, procuramos dispositivos e detectamos nosso módulo:
root@trik-7dda93:~
Uma pesquisa por computador encontra um dispositivo:

Para ativar o Bluetooth, você pode criar um script:
E adicione-o à execução automática:
cp init-bluetooth /etc/init.d/init-bluetooth update-rc.d init-bluetooth enable 99
A reinicialização e o desligamento do módulo se comportam de maneira imprevisível, portanto, as opções de parada e reinicialização não possuem comandos.
Etapa 3. Verificação da comunicação
A maneira mais fácil de verificar a comunicação nas duas direções é o serviço da porta COM. Com alguns comandos, ative-o:
root@trik-7dda93:~
Nós nos conectamos a partir do telefone e vemos um convite para entrar no sistema:

Nenhum dos terminais testados permitiu inserir uma senha de usuário vazia, então tive que enviar informações de login usando o redirecionamento de thread em uma sessão SSH.
Seguindo as instruções para conectar um gamepad ao Linux, encontramos os seguintes problemas:
- O BlueZ na distribuição está desatualizado e não entende os comandos do sixad daemon, que estabelece uma conexão com o gamepad
- Nova versão BlueZ da fonte se recusa a compilar devido a muitas dependências
- O BlueZ do Debian fresco requer udev e systemd, que estão ausentes na distribuição atual
A única dependência que foi capaz de satisfazer foi o módulo do kernel uinput.
Para fazer isso:
- obtenha a configuração do kernel atual no dispositivo
cp /proc/config.gz config.gz gunzip config.gz
- baixar código do kernel
- baixar e instalar toolchain
- copie a configuração do kernel para a pasta com o código do kernel
- adicione o módulo uinput à configuração
echo "CONFIG_INPUT_UINPUT=m" >> config
- inicie a montagem ativando primeiro a cadeia de ferramentas
source /opt/trik-sdk/environment-setup-arm926ejste-oe-linux-gnueabi make
- copie os módulos do kernel para o cartão de memória
make INSTALL_MOD_PATH=/mnt/trik-sd modules_install
- construa a imagem do uBoot e copie-a para / boot
make uImage cp arch/arm/boot/uImage /mnt/trik-sd/boot/uImage-3.6.7
Agora, o programa não jura pela falta de um módulo do kernel, mas não podemos fazer nada. Instruções para o gamepad serão úteis mais tarde.
Etapa 5. Cozinhe o mingau no machado
Chegando ao plano "tyap-blooper". Como não há uma maneira conveniente de colocar os programas necessários na distribuição original, colocaremos algo popular. O processador possui uma arquitetura ARMv5TE, o que significa que existem distribuições para ele.
Tentamos descompactar e executar o Arch Linux universal para ARM e, ao carregar no console, vemos que o systemd requer uma versão mais recente do kernel, que não possuímos. Tentativas de transferência do kernel 4.16 não tiveram êxito e levaram muito tempo.
Passamos para outra opção - Debian. Existe uma imagem de disco com um sistema instalado para ARM, mas é melhor colocar um sistema limpo com os pacotes e configurações necessários para nós.
Instalação no QEMU
Faça o download da imagem de instalação (link para .iso ) e instale o QEMU.
Também precisamos da imagem do kernel e do initrd para inicializar a instalação, que pode ser baixada aqui .
Crie uma imagem de um cartão de memória com o tamanho de um cartão de memória real (neste caso, 4 GB):
qemu-img create -f raw debian.img 4G
Iniciamos a instalação:
qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.gz -hda debian.img -cdrom debian-7.11.0-armel-CD-1.iso
Se você deseja criar um layout de disco com uma distribuição original relativa não padrão, deixe a partição raiz primeiro; caso contrário, você precisará alterar os parâmetros de inicialização do kernel no uBoot. Há o número da partição na qual o sistema de arquivos raiz está localizado.
A marcação padrão contém:
- Partição EXT4 para sistema de arquivos raiz de 1.3 GB
- Partição FAT32 para armazenar dados do usuário ≈ 500 MB de tamanho
A saída do fdisk para a imagem da distribuição original:
Disk: trik-distro.img geometry: 893/64/63 [3604478 sectors] Signature: 0xAA55 Starting Ending
Depois de definir os parâmetros, deixamos de beber algumas xícaras de chá, porque o emulador não é muito mais rápido que um processador ARM real.
Para iniciar o sistema instalado, você precisa de outra imagem initrd, que pode ser obtida aqui .
Iniciamos o sistema:
qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.img-3.2.0-4-versatile -hda debian.img -append "root=/dev/sda1"
Configuração do sistema
Após o início, entramos no superusuário, checamos a conexão com a Internet, atualizamos os repositórios e o sistema, colocamos o conjunto mínimo de programas:
apt-get update apt-get upgrade apt-get install curl git mc htop joystick
Terminais
/etc/inittab
, removemos terminais desnecessários, ligamos o UART de que precisamos e adicionamos entrada automática para o usuário certo (use o root somente ao depurar). A entrada automática é útil se você planeja executar o shell para controle no controlador.
1:2345:respawn:/sbin/getty 38400 tty1 --autologin root
Bluetooth e wifi
Instale o bluez-utils e o wpasupplicant para acessar o Wi-Fi e o Bluetooth.
apt-get install bluez-utils wpasupplicant
Desabilitamos a interface eth0 e configuramos a interface wlan1 em /etc/network/interfaces
:
# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8) # The loopback interface auto lo iface lo inet loopback # Wireless interfaces auto wlan1 iface wlan1 inet dhcp wireless_mode managed wireless_essid any wpa-driver wext wpa-conf /etc/wpa_supplicant.conf
Adicione a rede com antecedência ao /etc/wpa_supplicant.conf
, porque fazer isso no próprio controlador não é tão conveniente:
wpa_passphrase ssid password >> /etc/wpa_supplicant.conf
Se você não possui acesso Wi-Fi, pode usar o UART para outras configurações, mas lembre-se de que, por padrão, o kernel exibe todos os erros neste terminal. Portanto, durante a operação, uma mensagem repentina do kernel ou serviço pode interrompê-lo.
Adicione um script para ativar o Bluetooth. Desta vez, modifique /etc/init.d/bluetooth
:
139: case $1 in start) echo 1 >> /sys/devices/virtual/gpio/gpio107/value 168: hciattach /dev/ttyS0 texas log_end_msg 0 ;;
Assim, todos os serviços que requerem o serviço Bluetooth executam os comandos necessários para inicializar.
Deslize para a esquerda, deslize para a direita
Removemos programas e serviços desnecessários que podem ser visualizados usando o htop, porque eles ocupam um lugar precioso na RAM:

Nesse caso, o serviço ConsoleKit possui muitos processos . Mova o arquivo deste serviço para a pasta raiz em caso de recuperação:
mv /usr/share/dbus-1/system-services/org.freedesktop.ConsoleKit.service /root/
Antes de desligar o serviço, o consumo de RAM era de 19 MB e depois - de 16 MB.
Seções do sistema
Embora o uBoot transfira para o kernel o dispositivo no qual a partição raiz está localizada, vale a pena escrevê-lo em /etc/fstab
para /etc/fstab
a confiabilidade. Mudamos a primeira linha responsável pela seção raiz:
/dev/mmcblk0p1 / auto defaults 1 1 proc /proc proc defaults 0 0 devpts /dev/pts devpts mode=0620,gid=5 0 0 usbdevfs /proc/bus/usb usbdevfs noauto 0 0 tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 tmpfs /var/volatile tmpfs defaults 0 0
Se você não criou a partição raiz a primeira, não se esqueça de especificar o número da partição desejada.
Se você deixou a segunda partição FAT para obter dados do usuário, precisa criar uma pasta para montar a partição nela
mkdir /usr/share/trik
e escreva a seção em /etc/fstab
:
/dev/mmcblk0p2 /usr/share/trik vfat defaults 0 0
Etapa 6. Tentamos nosso mingau
Após configurar a imagem do sistema, você deve montá-la para instalar os módulos do kernel e o próprio kernel:
onde, NNNN = tamanho do setor * início da seção. O tamanho padrão do setor é 512 bytes.
Também montamos a distribuição original:
fdisk -l trik-distro.img mount -o loop,offset=NNNN trik-distro.img /mnt/trik-clean
Nós removemos o kernel do QEMU e seus módulos, como eles não são destinados à nossa plataforma. Copiamos o novo kernel e módulos, assim como na distribuição original.
rm -rf /mnt/debian/boot/ rm -rf /mnt/debian/lib/modules/3.2.0-4-versatile rm -rf /mnt/debian/lib/modules/3.2.0-5-versatile mkdir /mnt/debian/boot/ cp arch/arm/boot/uImage /mnt/debian/boot/ make INSTALL_MOD_PATH=/mnt/debian modules_install
Necessitaremos de firmware para o módulo Wi-Fi, que está na distribuição original na pasta / lib / firmware e no firmware Bluetooth que encontramos anteriormente.
cp /mnt/trik-clean/lib/firmware/* /mnt/debian/lib/firmware/ cp TIInit_7.6.15.bts /mnt/debian/lib/firmware/
Desconecte as imagens de disco:
umount /mnt/trik-clean umount /mnt/debian
E comece a copiar a imagem para o cartão de memória usando dd:
# ( ) lsblk dd if=debian.img of=/dev/sdX bs=4M
Etapa 7. A linha de chegada
Nós compilamos os programas para conectar o gamepad no novo sistema e instalamos o daemon sixad.
Conectamos o gamepad via USB ao controlador e executamos o programa para criar um par:
root@trik:~/bt
Quando o gamepad está conectado, nada acontece e o serviço sixad é silencioso:
sixad-bin[2675]: started sixad-bin[2675]: sixad started, press the PS button now sixad-bin[2675]: unable to connect to sdp session
Mas a comunidade Raspberry Pi já fez uma "muleta" para consertar a conexão .
Nós reconstruímos o programa e nos alegramos.
sixad-bin[2833]: started sixad-bin[2833]: sixad started, press the PS button now sixad-bin[2833]: unable to connect to sdp session sixad-sixaxis[2836]: started sixad-sixaxis[2836]: Connected 'PLAYSTATION(R)3 Controller (00:**:**:**:**:09)' [Battery 02]
Agora o gamepad está disponível para o sistema como um dispositivo de entrada e o programa jstest mostrará o status de todos os botões e sensores analógicos:
root@trik:~# ls /dev/input/ by-path event0 event1 event2 event3 js0 js1 js2 mice root@trik:~# jstest --normal /dev/input/jsX Driver version is 2.1.0. Joystick (PLAYSTATION(R)3 Controller (00:**:**:**:**:09)) has 29 axes (X, Y, Z, Rx, Ry, Rz, Throttle, Rudder, Wheel, Gas, Brake, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, (null), (null), (null), (null), (null), (null), (null), (null)) and 17 buttons (Trigger, ThumbBtn, ThumbBtn2, TopBtn, TopBtn2, PinkieBtn, BaseBtn, BaseBtn2, BaseBtn3, BaseBtn4, BaseBtn5, BaseBtn6, BtnDead, BtnA, BtnB, BtnC, BtnX). Testing ... (interrupt to exit) Axes: 0: 0 1: 0 2: 0 3: 0 4: -7150 5: -7746 6:-32767 7: 0 8: 0 9: 0 10: 0 11: 0 12: 0 13: 0 14: 0 15: 0 16: 0 17: 0 18: 0 19: 0 20: 0 21: 0 22: 0 23: 0 24: 0 25: 0 26: 0 27: 0 28: 0 Buttons: 0:off 1:off 2:off 3:off 4:off 5:off 6:off 7:off 8:off 9:off 10:off 11:off 12:off 13:off 14:off 15:off 16:off
onde X é o número do dispositivo no sistema, por padrão - 2. Os números de botões e eixos podem ser vistos aqui .
Use na prática
Vídeo mostrando o gamepad no YouTube .
Links úteis
Programas para conectar o gamepad Dualshock 3 - sixpair e sixad .
Para gamepads e outros dispositivos de entrada, existe uma biblioteca C leve - libenjoy .
O código fonte do programa para controlar servomotores e motores é o repositório GitHub .
Todos os arquivos de configuração do artigo para um kit de distribuição improvisado são o repositório GitHub .
A fonte do kernel é o repositório do GitHub .
Fatos interessantes sobre o controlador
- A especificação afirma que a RAM é de 256 MB. Mas se você executar o htop, verá que apenas 128 MB estão disponíveis. Isso é limitado pelas opções do kernel que podem ser exibidas no console do uBoot:
mem=128M console=ttyS1,115200n8 rw noinitrd rootwait root=/dev/mmcblk0p1 vt.global_cursor_default=0 consoleblank=0
O chip de memória está marcado com 3PC22 D9MTD, fabricado pela Micron. Não foi possível encontrar informações sobre o volume atual.
- O uBoot é armazenado na memória flash SPI na qual o kernel também está conectado e não é usado. Você pode tentar usar este local para suas tarefas ou copiar um novo kernel e reconfigurar o uBoot para usá-lo.
Endereços das imagens do dmesg:
[ 11.598170] 0x000000000000-0x000000040000 : "uboot" [ 11.642985] 0x000000040000-0x000000080000 : "uboot-env1" [ 11.706256] 0x000000080000-0x0000000c0000 : "uboot-env2" [ 11.761827] 0x0000000c0000-0x000000100000 : "config-periph" [ 11.805129] 0x000000100000-0x000000400000 : "kernel" [ 11.861864] 0x000000400000-0x000001000000 : "RootFS"
- A tela do controlador, embora pequena, na verdade possui um sensor resistivo. Se o próprio sensor está conectado é desconhecido.
- O Dualshock 3 possui LEDs no conector USB que mostram o número do gamepad / joystick. Há um gamepad no vídeo, mas seu número é 3. Isso não é um erro, porque existem mais dois "joysticks" no sistema: um acelerômetro e um giroscópio.
Problemas encontrados ao usar
- Às vezes, o robô fica firme, sem desligar os servomotores, o que lhes permite mudar de posição com relação ao ruído na linha de dados. Isso foi visto mesmo em uma distribuição padrão .
- A inclusão de controladores PWM é diferente do que está escrito na documentação . Pelo menos em C puro, isso não funcionou.
- Às vezes, o USB para de funcionar no Debian.