Na continuação das experiências com o ev3dev, dois dispositivos USB um pouco mais complicados:
wireless gamepad
webcam
Desta vez mostro primeiro o resultado e preocupo-me depois com as explicações 🙂
O gamepad é um gamepad genérico para Sony Playstation 3 e PC, penso que a maioria dos gamepads USB serão igualmente reconhecidos. Já com as webcams não será bem assim, será necessário compatibilidade com v4l2 (webcams) ou gPhoto2 (máquinas fotográficas). Neste exemplo estou a usar uma webcam Logitech C170 que funciona com o v4l2 através do uvcvideo. Também utilizei com sucesso uma Canon Digital IXUS 500 com o gPhoto2. E também tentei com 3 webcams antigas sem sucesso (apesar de 2 delas funcionarem no meu Ubuntu… pelos vistos funcionam em modo de compatibilidade v4l1 que não parece existir no ev3dev).
A foto abaixo (não tocada) foi tirada pelo AD4M4ST0R durante o decorrer do video anterior:
[Actualizado a 20 de Agosto]
Para quem estiver interessado, publiquei em artigos distintos os detalhes quanto:
A webcam USB utilizada no AD4M4ST0R é uma Logitech C170.
Depois de ligada são reconhecidos dois devices: uma webcam propriamente dita do tipo UVC (USB Video Class) gerida pelo v4l2 e um microfone gerido como uma placa de som pelo ALSA:
root@ev3dev:~# dmesg
(...)
usb 1-1.3: new full-speed USB device number 5 using ohci
Linux video capture interface: v2.00
uvcvideo: Found UVC 1.00 device Webcam C170 (046d:082b)
input: Webcam C170 as /devices/platform/ohci.0/usb1/1-1/1-1.3/1-1.3:1.0/input/input3
usbcore: registered new interface driver uvcvideo
USB Video Class driver (1.1.1)
usbcore: registered new interface driver snd-usb-audio
O microfone não aparece como dispositivo USB, apenas a webcam:
root@ev3dev:~# lsusb
Bus 001 Device 005: ID 046d:082b Logitech, Inc.
(...)
mas se formos ver ao alsamixer temos lá uma nova placa de som: “Webcam C170”.
A parte mais crítica, a criação de um dispositivo video, também funcionou:
root@ev3dev:~# ls /dev
mostra entre outros “video0”.
Como a webcam foi também reconhecida como um dispositivo OHCI temos ainda:
root@ev3dev:~# ls /dev/input/by-id/ -la
(...)
lrwxrwxrwx 1 root root 9 Aug 18 12:13 usb-_Webcam_C170-event-if00 -> ../event3
(...)
Para capturar imagens da webcam optei pelo fswebcam
apt-get install fswebcam
Como já o tinha experimentado com esta mesma webcam no meu Ubuntu, avanço para um comando que sei que funciona:
E efectivamente funciona só que quando fui ver a imagem esta tinha apenas 176×144 e não 640×480 (e o próprio comando devolve isso: “Adjusting resolution from 640×480 to 176×144”). Mas que raio…?
Perdi algum tempo nisto por isso vou alongar-me um pouco mais para que outros que passem pelo mesmo possam beneficiar também.
Descobri que a câmara permite despejar video em dois formatos diferentes: YUYV e MJPG:
root@ev3dev:~# v4l2-ctl --list-formats
ioctl: VIDIOC_ENUM_FMT
Index : 0
Type : Video Capture
Pixel Format: 'YUYV'
Name : YUV 4:2:2 (YUYV)
Index : 1
Type : Video Capture
Pixel Format: 'MJPG' (compressed)
Name : MJPEG
MJPG (Motion JPEG) é um formato com compressão (e alguma perda também) e por isso consome menos largura de banda que o YUYV. A minha teoria é de que sendo o bus USB do EV3 apenas 1.1 (11 Mbps) em vez de USB 2.0 (480 Mbps) como no meu Ubuntu a webcam de algum modo se autoconfigura para a largura de banda disponível. Por isso no Ubuntu ao pedir com o fswebcam uma foto 640×480 extraída de video gerado em formato YUV ele consiga mas no EV3 seja obrigado a reduzir para 176×144.
A solução foi indicar ao fswebcam para lidar com MJPG:
Agora já funciona, excepto que nalgumas situações ocorre um erro semelhante a este (os dois números hexadecimais do final variam):
GD Error: gd-jpeg: JPEG library reports unrecoverable error: Not a JPEG file: starts with 0x92 0x7
Aparentemente algumas webcams (e pelos vistos a maioria são da Logitech?) demora a estabilizar a captura e por isso produz lixo nas primeiras frames. As soluções passam invariavelmente por descartar umas quantas frames inicais… só ainda não encontrem o número mágico:
Descartar 20 frames funciona sempre mas parece-me um exagero. Além disso descobri que à medida que se vai utilizando podemos baixar o número, até mesmo deixar de descartar qualquer frame… Parece que a câmara “aquece” ou se vai auto-ajustando, será?
Para facilitar a utilização a partir de outros programas criei um script ‘saycheese.sh’ que ao ser invocado tira uma fotografia e guarda-a com um nome correspondendo à data:
O gamepad utilizado no AD4M4ST0R é um “Gioteck VX-2 Wireless Controller” comprado na FNAC por €19.99. Qualquer modelo compatível com PC deverá funcionar, desde que use um dongle USB (os modelos por cabo USB também funcionarão mas não servem para o caso). Quando o stack bluetooth estiver funcional no ev3dev também deverão funcionar gamepads desse tipo
O gamepad é reconhecido automaticamente como um gamepad e como um disposito de classe OHCI:
root@ev3dev:~# dmesg
(...)
usb 1-1.4: new full-speed USB device number 4 using ohci
hid-generic 0003:25F0:83C2.0001: usb_submit_urb(ctrl) failed: -1
hid-generic 0003:25F0:83C2.0001: timeout initializing reports
input: Goodbetterbest Ltd Gioteck VX2 2.4G Wireless Controller as /devices/platform/ohci.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:25F0:83C2.0001/input/input2
hid-generic 0003:25F0:83C2.0001: input: USB HID v1.10 Gamepad [Goodbetterbest Ltd Gioteck VX2 2.4G Wireless Controller] on usb-ohci.0-1.4/input0
Mas a implementação USB deixa um bocado a desejar:
root@ev3dev:~# lsusb
Bus 001 Device 004: ID 25f0:83c2
Bela porcaria, nem um descritivo? Vamos inspeccionar com mais detalhe:
root@ev3dev:~# lsusb -d 25f0:83c2 -v
Bus 001 Device 004: ID 25f0:83c2
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 16
idVendor 0x25f0
idProduct 0x83c2
bcdDevice 3.15
iManufacturer 1 Goodbetterbest Ltd
iProduct 2 Gioteck VX2 2.4G Wireless Controller
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 41
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 137
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 1
Device Status: 0x0000
(Bus Powered)
Sendo OHCI temos também:
root@ev3dev:~# ls /dev/input/by-id/ -la
total 0
drwxr-xr-x 2 root root 60 Aug 15 07:16 .
drwxr-xr-x 4 root root 140 Aug 15 07:16 ..
lrwxrwxrwx 1 root root 9 Aug 15 07:16 usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick -> ../event2
No Ubuntu consigo ver o estado dos vários botões e joysticks do gamepad com o comando ‘jstest’ do pacote ‘joystick’ por isso:
root@ev3dev:~# apt-get install joystick
root@ev3dev:~# jstest --normal /dev/input/by-id/usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick
Driver version is 0.8.0.
jstest is not fully compatible with your kernel. Unable to retrieve button map!
Joystick (Unknown) has 2 axes and 2 buttons.
Testing ... (interrupt to exit)
jstest: error reading: Invalid argument
carregar um botão apenas gerou esta sequência de caracteres estranha… pelo menos sabemos que funciona só falta entender o formato. Como sou preguiçoso fui buscar o PyGame, um módulo de python muito usado na comunidade Raspberry Pi que já faz isso – a semelhança do EV3 com o Raspberry Pi é tão impressionante que lhe podemos ir buscar ideias para quase tudo.
import traceback, os
os.environ['SDL_VIDEODRIVER'] = 'dummy'
from pygame import joystick, event, display
def main():
try:
display.init()
joystick.init()
js=joystick.Joystick(0)
js.init()
num_axes=js.get_numaxes()
num_buttons=js.get_numbuttons()
num_hats=js.get_numhats()
print 'Axes:', num_axes
print 'Buttons:', num_buttons
print 'Hats:', num_hats
while True:
event.pump()
for i in range(0, num_axes):
print 'Axis %i: %6.3f' % (i, js.get_axis(i))
for i in range(0, num_buttons):
print 'Button %i: %r' % (i, js.get_button(i))
for i in range(0, num_hats):
print 'Hat %i: %s' % (i, js.get_hat(i))
except (KeyboardInterrupt, SystemExit):
print "Exiting..."
except Exception:
traceback.print_exc(file=sys.stdout)
sys.exit(0)
if __name__ == "__main__":
main()
À custa deste script fiquei a saber que o gamepad tem 4 axes (2 por cada joystick analógico), 13 buttons e 1 hat (o hat é o conjunto de 4 teclas direccionais à esquerda do gamepad) que quando accionados devolvem:
Para cada um dos 13 botões:
gatilho esquerdo = 6
botão sobre gatilho esquerdo = 4
gatilho direito = 7
botão sobre gatilho direito = 5
select = 8
start = 9
home = 12
triangulo = 0
circulo = 1
cruz = 2
quadrado = 3
botão do joystick esquerdo = 10
botão do joystick direito = 11
(o botão “Turbo’ ao centro do gamepad parece não funcionar)
todo para cima: Eixo 3 = -1
todo para baixo: Eixo 3 = 1
todo para direita: Eixo 2 = 1
todo para esquerda: Eixo 2 = -1
=> (x,y) = (axis2,-axis3)
Para o joystick da esquerda:
todo para cima: Eixo 1 = -1
todo para baixo: Eixo 1 = 1
todo para direita: Eixo 0 = 1
todo para esquerda: Eixo 0 = -1
=> (x,y) = (axis0,-axis1)
O gamepad tem também um motor interno para vibração (force feedback?) mas que só funciona com Playstation 3. Curiosamente de vez em quando acontece-me poucos minutos depois de desligar o EV3 o gamepad desatar a vibrar.
Para terminar a apresentação do AD4M4ST0R faltava apenas o código.
O programa principal é um script escrito em python ‘joy.py’ que lida com o gamepad e os motores. O controlo da webcam e do buzzer é delegado em dois bash scripts (‘saycheese.sh’ e ‘beep.sh’).
O programa principal, “joy.py’:
import sys, traceback, os
os.environ['SDL_VIDEODRIVER'] = 'dummy'
# from math import sqrt
from math import log10
from subprocess import call
from time import sleep
from pygame import joystick, event, display
### botoes ###
B_TRIANG = 0
B_CIRC = 1
B_CROSS = 2
B_SQUARE = 3
B_LTRIG2 = 4
B_RTRIG2 = 5
B_LTRIG = 6
B_RTRIG = 7
B_SELECT = 8
B_LJOY = 10
B_RJOY = 11
B_START = 9
def main():
try:
display.init();
joystick.init();
js=joystick.Joystick(0);
js.init();
### arranca em modo Joystick ###
control_by_JOY=True;
num_axes=js.get_numaxes();
num_buttons=js.get_numbuttons();
num_hats=js.get_numhats();
### sabemos a priori que tem 4 axes, 13 buttons e 1 hat
### inicializa motores com Duty Cycle=0
call("echo 0 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp", shell=True);
call("echo 0 > /sys/class/tacho-motor/tacho-motor1/duty_cycle_sp", shell=True);
call("echo 1 > /sys/class/tacho-motor/tacho-motor0/run", shell=True);
call("echo 1 > /sys/class/tacho-motor/tacho-motor1/run", shell=True);
flag=False;
while True:
x=y=motor_direito=motor_esquerdo=0.0;
event.pump();
button_mode=js.get_button(B_SELECT);
button_shot=js.get_button(B_SQUARE);
if button_mode ==1:
call("./beep.sh" , shell=True);
if control_by_JOY==True:
control_by_JOY=False;
print 'Control Mode=HAT';
else:
control_by_JOY=True;
print 'Control Mode=JOYSTICK';
if button_shot==1:
print 'Cheese!!!';
call("/root/saycheese.sh", shell=True);
### eixo dos joysticks entre -1 e +1
### x=axis2 , y=-axis3
### ignorar valores abaixo de 0.1 (dead zone)
### aplicar log10(100x) aos restantes (para dar enfase aos mais baixos)
### o resultado e' 0 ou 1 a 2 por isso
### multiplicar por 25 da' valores Duty Cycle nulos ou entre 25 e 50
if control_by_JOY==True:
# Control by Right Joystick, Axis 2 e 3
axis2=js.get_axis(2);
axis3=js.get_axis(3);
if axis2>0:
if axis2<0.1:
x=0;
else:
x=log10(axis2*100);
elif axis2<0:
if axis2>-0.1:
x=0;
else:
x=-log10(-axis2*100);
if axis3>0:
if axis3<0.1:
y=0;
else:
y=-log10(axis3*100);
elif axis3<0:
if axis3>-0.1:
y=0;
else:
y=log10(-axis3*100);
else:
y=0;
if y<>0:
if x<0:
motor_direito=50*y/2;
# rodar para a esquerda => reduzir motor esquerdo
motor_esquerdo=motor_direito*(1+x/3);
else:
motor_esquerdo=50*y/2;
# rodar para a direita => reduzir motor direito
motor_direito=motor_esquerdo*(1-x/3);
elif x<>0:
# y=0, apenas roda
motor_esquerdo=25*x;
motor_direito=-motor_esquerdo;
else:
# Control by HAT keys
hat=js.get_hat(0);
if hat==(0,1):
### anda em frente ###
motor_direito=50;
motor_esquerdo=50;
elif hat==(1,0):
### roda para a direita ###
motor_esquerdo=50;
motor_direito=-50;
elif hat==(0,-1):
### recua ###
motor_direito=-50;
motor_esquerdo=-50;
elif hat==(-1,0):
### roda para a esquerda ###
motor_esquerdo=-50;
motor_direito=50;
elif hat==(1,1):
### frente e roda para a direita ###
motor_esquerdo=50;
motor_direito=25;
elif hat==(-1,1):
### frente e roda para a esquerda ###
motor_esquerdo=25;
motor_direito=50;
elif hat==(-1,-1):
### recua e roda para a esquerda ###
motor_esquerdo=-50;
motor_direito=-25;
elif hat==(1,-1):
### recua e roda para a direita ###
motor_esquerdo=-25;
motor_direito=-50;
comando_motordir = "echo " + repr(motor_direito) + " > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp";
comando_motoresq = "echo " + repr(motor_esquerdo) + " > /sys/class/tacho-motor/tacho-motor1/duty_cycle_sp";
call(comando_motordir, shell=True);
call(comando_motoresq, shell=True);
# end while
except (KeyboardInterrupt, SystemExit):
print "Exiting...";
except Exception:
traceback.print_exc(file=sys.stdout);
call("echo 0 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp", shell=True);
call("echo 0 > /sys/class/tacho-motor/tacho-motor1/duty_cycle_sp", shell=True);
call("echo 0 > /sys/class/tacho-motor/tacho-motor0/run", shell=True);
call("echo 0 > /sys/class/tacho-motor/tacho-motor1/run", shell=True);
js.quit();
joystick.quit();
display.quit();
sys.exit(0);
if __name__ == "__main__":
main()
A qualidade das fotos tiradas pela webcam Logitech C170 não é má… desde que haja suficiente luz ambiente. Por isso lembrei-me de ligar LED’s Power Functions a uma das portas de saída ainda disponíveis para funcionar como «flashes» ao tirar a fotografia.
Infelizmente a versão actual do ev3dev ainda não permite o controlo individual das portas (foi aberto hoje um issue, depois de uma troca de ideias) por isso a única maneira é enganar o ev3dev fazendo-o acreditar que tem um motor.
Os motores e os sensores EV3 têm uma funcionalidade «Auto-ID» que permite ao EV3 identificar que dispositivo foi ligado a cada porta (género “Plug and Play”). Nos videos do utilizador “TecnicRobot” ele utiliza um par de resistências para que os seus dispositivos de saída pareçam ser motores EV3.
Para isso fiz um cabo semelhante a este (não tinha resistências de 1KΩ e 10 KΩ à mão mas como o que interessa é a proporção usei de 2.2KΩ e 22KΩ) e funciona.
(parece-me que é altura de fazer um cabo decente e dar uma arrumação aos cabos do AD4M4ST0R).
Durante a noite, numa sala com pouca iluminação (halogéneo)
Durante a manhã, no mesmo local com iluminação média (natural mas indirecta):
A terceira imagem foi tirada com um segundo par de LED’s Power Functions o que me levou na noite seguinte a acrescentar um terceiro par:
As 4 imagens correspondem a Duty Cycles de 0%, 33%, 67% e 100% (ou seja os LED’s apagados, o equivalente a um par aceso, o equivalente a dois pares acesos e os três pares acesos).
Assim que me for possível vou tentar medir a luminosidade ambiente com um EV3 Color Sensor (45506) para determinar automaticamente o Duty Cycle a aplicar aos LEDs antes de cada fotografia.
A ideia é utilizar um sensor de cor para medir a luminosidade de modo a acender os LEDs de iluminação apenas o necessário para garantir uma imagem razoável.
O sensor utilizado é um EV3 Color Sensor (45506). Na wiki do projecto ev3dev há 2 artigos com a informação suficiente:
Infelizmente a gama de valores lida pelo sensor deixa muito a desejar: no mesmo local na minha sala observei de ‘1’ (de noite com luz fraca) a ’17’ (numa tarde típica de Agosto sendo a sala virada a Sul embora não haja incidência directa no sensor). E com uma lanterna a apontar directamente ao sensor obtenho ’68’.
Tirei algumas fotos com vários valores de leitura e vários duty cycles aplicados a 3 pares de LEDs Power Functions para tentar elaborar uma regra (o rover e a minifig sempre no mesmo local com cerca de 15 cm entre a webcam e a minifig, a iluminação dos LEDs nunca alterou o valor medido pelo sensor e todas as fotos foram apenas reduzidas dos 640×480 originais para 160×120)
Brightness
Duty Cycle
(%)
0%
25%
33%
50%
66%
75%
100%
1
–
–
–
–
–
3
4
5
6
13
–
–
–
17
–
–
–
Com esta informação optei pela seguinte função ‘fuzzy logic’:
Apenas uma breve explicação do modo como o rover é controlado quando em modo ‘joystick’:
É utilizado apenas o joystick da direita, correspondente ao par de eixos 2 (horizontal) e 3 (vertical). A «potência» aplicada aos motores vai ser proporcional ao movimento do joystick portanto aos valores lidos nos eixos e que podem variar entre -1.0 e +1.0 sendo que no caso do eixo vertical estão invertidos (o sentido positivo é para baixo). Assim:
(x,y) = (axis2, -axis3)
Defini uma zona morta ao redor da posição central (10% portanto entre -10.0 e +10.0 para ambos os eixos) de modo a que pequenos toques no joytick sejam ignorados:
Além disso para evitar acelerações bruscas optei por dar mais importância às amplitudes menores que às maiores (como numa torneira em que se tem que rodar cada vez mais a torneira para se aumentando o caudal de água). Isso consegue-se aplicando uma função logarítmica:
f(x,y) = log10(100x,100y)
Não existe log10(0) mas isso já está prevenido a priori porque o centro está incluído na zona morta. O menor valor fora da zona morta será 0.1 e o maior valor será 1.0 [primeiro quadrante apenas]. Ora
log10(100 x 0.1) = 1
log10(100 x 1.0) = 2
Como os motores aceitam valores entre -100 e +100 basta aplicar um factor de escala de 50x para cobrir a gama toda. Mas no meu programa usei um factor de 25x apenas porque achei que o rover movia-se demasiado rápido [estou a pensar definir um botão do gamepad para comutar entre 25x e 50x para movimentos de precisão vs. corridas].
As curvas ocorrem quando o valor de x é não-nulo e nessas ocasiões reduzo o motor correspondente em 33% do valor de x (se quisermos curvas mais apertadas basta aumentar este valor).
O resto do código é apenas identificação dos quadrantes de modo a acertar os sinais dados aos motores.
Troquei as lagartas originais por um conjunto mais longo [e mais pesado] de modo a acomodar espaço para futuros acrescentos ao rover. Ainda precisam de uma afinação para reduzir algum atrito.
Aproveitei e passei os LEDs Power Functions para debaixo da webcam, arrumei um pouco os cabos e adicionei o sensor de cor.
Chegou finalmente a beteria EV3 por isso montei-a em definitivo, há um pequeno espaço à frente, por cima dos LEDs, para passar o cabo do carregador (a propósito: não é necessário comprar um carregador para a bateria EV3 se já tivermos um carregador de bateria Power Functions ou qualquer regulador DC de 10 a 12 V com ficha compatível… ou um adaptador feito por nós)
O programa de controlo por gamepad já permite acender os LEDs para tirar a foto – por enquanto em modo manual mas em breve de forma automática com o brilho dos LEDs determinado a priori pela medição da luminosidade ambiente a partir do sensor de cor.
Uma demonstração do movimento em modo «joytstick»:
A câmara utilizada no AD4MAST0R, uma webcam Logitech c170, não foi prevista para montagem em robots autónomos. Dois pontos que poderão ser vistos como vantajosos para o seu propósito original acabam por atrapalhar:
O clip é pouco útil, demasiado grande e não foi previsto como amovível
O cabo USB é longo (cerca de 1.2m) quando se podia ter colocado uma ficha no corpo da webcam para ser utilizada com um cabo USB do tamanho que se pretendesse
Felizmente não é difícil contornar estas limitações:
A execução dos procedimentos abaixo VIOLA a garantia do produto. Além disso estes procedimentos estão descritos para um género de leitores que os compreende – se não for esse o caso NÂO tente proceder a estas modificações sob risco de danificar de foram definitiva a sua webcam e o bus USB do seu EV3 ou PC.
Para remover o clip é necessária uma chave de relojoeiro (fenda ou Philips, desde que pequena). Também é conveniente uma chave de fendas maior (género busca-pólos) ou um canivete de lâmina fina mas forte.
desapertar o parafuso da metade do clip junto à webcam e remover a tampa
desapertar os 2 parafusos do corpo da webcam e destapar
desapertar os 2 parafusos que fixam o cabo e os 2 parafusos da placa de circuito impresso
soltar a placa de circuito impresso
por baixo desta há um parafuso que fixa o eixo de plástico que mantém o clip agarrado ao corpo da webcam: desaparafusar
através do furo deixado vago, tentar empurrar o eixo para fora até ser possível enfiar uma chave de fendas ou uma lâmina na ranhura entre a ponta do eixo e o corpo da webcam para poder puxar o parafuso para fora
voltar a montar a placa de circuito impresso, apertar os restantes parafusos, alinhar o microfone, tapar a webcam e apertar os parafusos
confirmar que a webcam ainda funciona 🙂
No final deste processo sobram o clip, a tampa do clip, o eixo e 2 parafusos
2. Redução do cabo
Bastou seguir o artigo “Connect USB with other devices by short Wire” do autor Indiana67 no site “Instructables”. A única diferença foi não ter tubo termoretráctil suficientemente largo, o que utilizei não consegui puxar para cima da zona cortada e por isso acabei enrolando fita de electricista preta. Feio mas igualmente funcional.
E confirmei novamente que ainda funciona 🙂
3. LEGO-lização da webcam
No lugar deixado vago pelo eixo de fixação ao clip pode-se montar um eixo LEGO Technic, basta alargar um pouco [e com cuidado] o furo e colar com uma cola resistente:
O eixo permite inúmeras possibilidades de montagem, comecei por esta: