Arduino
Kleerhangerbeest – o Robô Andarilho de Cabide de Arame controlado com Arduino
Versão fácil para Arduino e 2 servos do Coat Hanger Walking Robot, o Robô Andarilho de Cabide de Arame originalmente desenvolvido por Jerome Demers e Gareth Branwyn.
O nome kleerhangerbeest é holandês e significa bicho-cabide, tendo sido inspirado nos robôs eólicos chamados strandbeest (bicho-de-praia) de Theo Jansen – http://www.strandbeest.com/ .
Não parece com os “insetos” de Starship Troopers?
Veja o vídeo de efeito…
O chassis é feito em Meccano/Modelix. O resto é sucata que pode ser encontrada em qualquer lugar.
O código Processing para Arduino está em: https://github.com/awangenh/Minhas-Engenhocas/blob/master/Kleerhangerbeest2.ino
Usei um Freaduino ao invés de um Arduino para evitar ter de usar um protoboard em cima do robô. O Freaduino é excelente para coisas que usam servos e outros periféricos que ligam com um cabo sinal/VCC/GND por causa das saídas prontinhas que ele oferece para isso. O circuito é ultrasimples.:
O modelo do chassis está aqui embaixo (feito com VirtualMec):
Tentei manter o chasssis o mais simples possível. Os passos de montagem são esses abaixo:
A lista de peças (códigos da Meccano e não da Modelix) é essa:
Peça Qtdidade. 5 2 11 2 11a 2 37a 3 37b 13 90a 2 193 2 811 2
Depois de encaixados os servos, você pode fixá-los no lugar usando cantoneiras em “L” (aquelas pecinhas com formato em “L” com apenas dois furos, um redondo e o outro oblongo – código de peça Meccano = 12) fixadas com parafusos nos dois furos inferiores mais extremos do chassis.
Referências originais do Coat Hanger Walking Robot:
– http://www.instructables.com/id/How-to-build-the-one-motor-walker/
– http://www.technogumbo.com/projects/single-servo-walking-robot/
– https://www.youtube.com/watch?v=bxxmN2sQvjk
– https://solarbotics.com/product/abgchw/
– https://www.youtube.com/watch?v=L984o5mT9HI (com motor de rotacao continua)
O código Processing para Arduino está em: https://github.com/awangenh/Minhas-Engenhocas/blob/master/Kleerhangerbeest2.ino
Braço-Robô com 3 Graus de Liberdade programado em Scratch S4A utilizando Arduino e Meccano/Modelix
Um braço-robô com 3 graus de liberdade foi uma coisa que sempre me fascinou, inclusive pela sua suposta complexidade. Pensei e resolvi construir um que pudesse ser programado por qualquer criança usando a linguagem de programação visual para crianças Scratch. Aqui está o resultado.
Usei um Arduino Uno R3 com Firmata modificado para S4A e dois servos TowerPro SG90 para o manipulador e a 3ª junta e dois servos TowerPro 5010, mais fortes, para a 1ª e 2ª juntas. Os contrapesos são luvas de latão 3/4″ com rosca. Antes que eu esqueça: Tem um dirty hack no S4A: mudei o código Smalltalk e o código do Firmata para supoprtar 4 servos ao invés de dois…
Estou pensando em transportar para Snap! Scratch usando o servidor de comunicação s2a_fm de Alan Yorinks ao invés do S4A (Scratch for Arduino), que é bem limitado e só roda em Windows. Mas isso será outro post…
Aqui o programa no dialeto S4A (Scratch for Arduino) da Linguagem de Programação Visual Scratch originalmente desenvolvida pelo MIT:
Fiz um vídeo para mostrar algumas coisas:
O braço-robô foi construído utilizando-se peças de vários kits-clone de Meccano, incluindo-se aí peças originais Meccano vintage inglesas da década de 1940-50, como também peças do clone brasileiro Modelix. Abaixo algumas imagens:
Para quem quiser refazer, aqui o esquema, detalhando quais servos em cada saída digital. Lembre-se, o S4AFirmware.ino original só suporta servos nos pinos 11 e 12. Tem que modificar.
Microcontrolled Action Shooting Bike Helmet (Versão 0.1 Pré-Alfa)
Peguei a ideia de Jake Spurlock daqui http://makezine.com/projects/make-38-cameras-and-av/gopro-swivel-camera-mount/ e automatizei o processo de varredura para a captura.
Neste post a versão pré-alfa da Engenhoca. Vamos melhorar….
Aqui o detalhe do mecanismo de movimentação e da eletrônica de automação. Nesta versão o mecanismo de suporte é fixado diretamente ao eixo de nylon do servomotor. Para passear na Beira-Mar num domingo de manhã, como no filminho abaixo, é adequado. Se usar para MTB vai quebrar…
Veja aqui um vídeo…
Aqui o código Processing em um Sketch para o Arduino. É uma pequena variação do exemplo-padrão Sweep.ino.
SweepCamera.ino – Código em Processing para Arduino |
---|
#include Servo myservo; // create servo object to control a servo // a maximum of eight servo objects can be created int pos = 0; // variable to store the servo position void setup() { myservo.attach(9); // attaches the servo on pin 9 to the servo object } void loop() { myservo.write(pos); // tell servo to go to position in variable 'pos' delay(500); // added - stop at sideview before start sweeping for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees { // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(20); // waits 15ms for the servo to reach the position // changed to 20ms } delay(500); // added - stop at sideview before start sweeping for(pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees { myservo.write(pos); // tell servo to go to position in variable 'pos' delay(20); // waits 15ms for the servo to reach the position // changed to 20ms } } |
Carro-Robô que desvia de Obstáculos feito com Arduino e Meccano/Modelix
Este carro encontra seu caminho usando varredura por ultra-som (sonar). O transdutor de ultra-som montado sobre um servo emite pings para a frente, como um sonar de submarino. Sempre que o carro encontra um obstáculo a 20 cm, o ultra-som faz uma varredura para a esquerda e para a direita através do acionamento do servo que suporta o ultra-som: o caminho mais desimpedido é escolhido. O segundo servo (direção!) é então acionado e o carro faz uma curva nesta direção por alguns segundos e, então, continua reto.
Um goniômetro na roda (veja parte inferior direita da imagem acima) faz as vezes de conta-giros e monitora a velocidade do carro. Se o carro estiver em uma subida ou um tereno difícil que o lentifique (grama!), a ponte-H que controla o motor aumenta a corrente para o motor de forma a que ele ande mais rápido e tenha mais força. Quando a velocidade retorna ao normal, a corrente “de cruzeiro” é restituída. Se o carro chegar perto demais de um obstáculo, ele dá marcha a ré por alguns segundos antes de escolher um novo caminho: assim ele nunca fica entalado em um canto.
Esquema de conexões do Arduino:
Código em Processing para Arduino |
---|
#include <Servo.h> Servo us_servo; // create servo object to control the ultrasound servo Servo steering_servo; // create servo object to control the steering wheel servo int pos = 0; // variable to store the servo position int inputPin=4; // connect digital I/O 4 to the ECHO/Rx Pin int outputPin=5; // connect digital I/O 5 to the TRIG/TX Pin int greenLed=3; int redLed=7; // H-bridge pins int speedPin = 11; int directionPin = 12; //int relayPin=11; int us_echo, us_echo_dir, us_echo_esq; int min_distance = 45; // Distancia de echo considerado obstáculo int max_distance = 200; // Eco a partir do qual distancia é considerada infinita int tempo_curva = 2000; // Tempo durante o qual direção fica virada em curva /* ------ Variaveis e constantes do Conta-Giros ------- */ int dtPin = 2; // Se mudar pino, TEM que mudar a interrupção abaixo int interrupcaoContaGiros = 0; // TEM que ser 0 se dtPin = 2.... unsigned long ultimaMudanca = 0; // Tempo absoluto na ultima leitura do contagiros long intervalo = 0; const int altaVelocidade = 100; // Intervalo max. entre leituras para a velocidade ser considerada alta const int baixaVelocidade = 600; // Intervalo max. entre leituras para a velocidade ser considerada baixa int velocidade; /* -------------------------------------------------------*/ /*============================================== Analog motor control functions (employs H-bridge L298N) ==============================================*/ void praFrente() { Serial.print("Full speed forward\n"); digitalWrite(directionPin, HIGH); // Set direction as forward analogWrite(speedPin, 0); // Set the speed as full } void devagarPraFrente() { //Serial.print("Half speed forward\n"); digitalWrite(directionPin, HIGH); // Set direction as forward analogWrite(speedPin, 100); // Set the speed as half } void praTras() { Serial.print("Full speed backwards\n"); digitalWrite(directionPin, LOW ); // Set direction as reverse analogWrite(speedPin, 255); // Set the speed as full speed } void devagarPraTras() { Serial.print("Half speed backwards\n"); digitalWrite(directionPin, LOW ); // Set direction as reverse analogWrite(speedPin, 160); // Set the speed as half speed } void parar() { Serial.print("Stop\n"); analogWrite(speedPin, 0); // Set the speed to stop } /*============================================== Ultrassound pinging functions ==============================================*/ int ping() { int firstEcho; int secondEcho; int thirdEcho; int distance; int distance_cm; // first echo digitalWrite(outputPin, LOW); // send low pulse for 2μs delayMicroseconds(2); digitalWrite(outputPin, HIGH); // send high pulse for 10μs delayMicroseconds(15); digitalWrite(outputPin, LOW); // back to low pulse distance = pulseIn(inputPin, HIGH); // read echo value firstEcho= distance/29/2; // in cm // Serial.print(firstEcho); delay(50); // second echo digitalWrite(outputPin, LOW); // send low pulse for 2μs delayMicroseconds(2); digitalWrite(outputPin, HIGH); // send high pulse for 10μs delayMicroseconds(15); digitalWrite(outputPin, LOW); // back to low pulse distance = pulseIn(inputPin, HIGH); // read echo value secondEcho= distance/29/2; // in cm /* Serial.print(" "); Serial.print(secondEcho); */ delay(50); // third echo digitalWrite(outputPin, LOW); // send low pulse for 2μs delayMicroseconds(2); digitalWrite(outputPin, HIGH); // send high pulse for 10μs delayMicroseconds(15); digitalWrite(outputPin, LOW); // back to low pulse distance = pulseIn(inputPin, HIGH); // read echo value thirdEcho= distance/29/2; // in cm /* Serial.print(" "); Serial.println(thirdEcho); */ delay(50); if ((firstEcho < min_distance) && (secondEcho < min_distance) && (thirdEcho < min_distance)) { return((firstEcho + secondEcho + thirdEcho) / 3); } else { return(max_distance); } } void us_direita() { us_servo.write(45); delay (500); } void us_esquerda() { us_servo.write(135); delay (500); } // ATTENTION: Steering servo is mounted inverted in relation to the US servo void steering_direita() { steering_servo.write(135); delay (500); } void steering_esquerda() { steering_servo.write(45); delay (500); } /* ================================================ */ void reageObstaculo() /* Dá marcha a ré (por via das dúvidas) Troca para luz vermelha. Avalia distancias direita e esquerda. Escolhe caminho mais livre e faz curva. ================================================ */ { // Obstaculo! // Muda cores dos LEDs de indicação de modo digitalWrite(redLed, HIGH); digitalWrite(greenLed, LOW); // Para motor parar(); // Dar a re um pouco... devagarPraTras(); delay(1000); parar(); // Executa varredura sonar... // Move servo para direita us_direita(); // Pinga eco direito us_echo_dir = ping(); // Move servo para esquerda us_esquerda(); // Pinga eco esquerdo us_echo_esq = ping(); // Reseta posicao servo US us_servo.write(90); delay (1000); if (us_echo_esq > us_echo_dir) { steering_esquerda(); } else { steering_direita(); } // Faz a curva!!! // Liga motor (se já estiver ligado, continua ligado...) // digitalWrite(relayPin, HIGH); devagarPraFrente(); delay(tempo_curva); steering_servo.write(90); // steer straight ahead delay (1000); } /* ============================================== Rotinas de propriocepção do veículo Desenvolvidas para monitorar se o veículo está andando ou se parou/encalhou... Desenvolvidas para um goniômetro Keyes KY-40, que possui 5 saídas: GND, +, SW (chaveia ao apertar eixo), DT e CLK. Em nosso código conectamos 3: -/+ e DT a dtPin. Basta para avaliar velocidade quando não se deseja saber sentido. Necessita do artificio de programação feio de usar uma variável conta-giros global... ==============================================*/ /* ============================================== */ int avaliaVelocidade() /* Retorna 0, 1 ou 2, dependendo se: 0 -> Parou 1 -> Está lento (devemos acelerar - achou grama, tapete peludo ou inclinação?) 2 -> Velocidade nominal atingida.... ==============================================*/ { intervalo = millis() - ultimaMudanca; Serial.print(intervalo); if (intervalo > altaVelocidade) { if (intervalo > baixaVelocidade) { Serial.println(" -> parou..."); return(0); } else { Serial.println(" -> lento..."); return(1); } } else { Serial.println(" -> rapido..."); return(2); } } /* ============================================== */ void reageRotacao() /* Função chamada por interrupção sempre que o goniômetro apresenta uma leitura de rotação. ============================================== */ { ultimaMudanca = millis(); } /* ============================================== */ void inicializaContaGiros() /* ============================================== */ { ultimaMudanca = millis(); pinMode(dtPin, INPUT); attachInterrupt(interrupcaoContaGiros, reageRotacao, CHANGE); // encoder pin na interrupção 0 (dtPin = pin 2) } /*============================================== Funções Auxiliares ==============================================*/ void blinkRed() { digitalWrite(redLed, HIGH); delay(160); digitalWrite(redLed, LOW); delay(160); digitalWrite(redLed, HIGH); delay(160); digitalWrite(redLed, LOW); delay(160); digitalWrite(redLed, HIGH); delay(160); digitalWrite(redLed, LOW); } void blinkGreen() { digitalWrite(greenLed, HIGH); delay(160); digitalWrite(greenLed, LOW); delay(160); digitalWrite(greenLed, HIGH); delay(160); digitalWrite(greenLed, LOW); delay(160); digitalWrite(greenLed, HIGH); delay(160); digitalWrite(greenLed, LOW); } /*============================================== Main Setup ==============================================*/ void setup() { Serial.begin(9600); pinMode(inputPin, INPUT); pinMode(outputPin, OUTPUT); pinMode(greenLed, OUTPUT); pinMode(redLed, OUTPUT); // H-bridge pins pinMode(directionPin, OUTPUT); // Set Pin directionPin as output, this is the motor direction control //pinMode(relayPin, OUTPUT); // Servos initialization us_servo.attach(10); // attaches the servo on pin 10 to the servo object that does US scans steering_servo.attach(9); // attaches the servo on pin 9 to the steering wheel servo object // Inicialização da propriocepção inicializaContaGiros(); blinkGreen(); Serial.println("Partindo..."); } /*============================================== Main Loop ==============================================*/ void loop() { us_echo = ping(); if (us_echo == max_distance) { // Freie Fahrt! digitalWrite(redLed, LOW); digitalWrite(greenLed, HIGH); // Liga motor (se já estiver ligado, continua ligado...) // digitalWrite(relayPin, HIGH); devagarPraFrente(); } else { // Obstaculo! reageObstaculo(); } velocidade = avaliaVelocidade(); if (velocidade == 1) { //acelera praFrente(); blinkGreen(); //blinkGreen(); devagarPraFrente(); } if (velocidade == 0) { blinkRed(); //marcha a ré reageObstaculo(); } } |