Un BeetleBot est un petit robot autonome, facile à construire et assez marrant à regarder. Vous pouvez trouver pas mal de tutos pour en construire sur Youtube. Personnellement, j’ai suivi le tutoriel de makemagazine.
Photos
J’ai dû rajouter une batterie en plus car mes moteurs fonctionnent à 3V.
J’utilise tout simplement un LCD, un DS1307, et une plateforme Arduino pour créer une horloge LCD. Ayant déjà fait des tutoriels sur le LCD et le DS1307, je vais juste reprendre ces schémas.
L’écran à cristaux liquides (affichage à cristaux liquides ACL ou LCD pour : liquid crystal display, en anglais) est le principal composant des moniteurs plats. Il est utilisé principalement depuis la fin des années 1990 en noir et blanc puis en couleur depuis les débuts des années 2000 dans les téléphones portables, les ordinateurs personnels, les télévisions, les ordinateurs de bord pour les avions et les voitures. Son principal avantage est sa faible consommation d’énergie.
Un potentiomètre 10K (Pour faire varier la luminosité)
Une Breadboard
Des fils
Schéma
Attention au câblage des pins LED- et LED+ du LCD. Il faut bien les mettre sur une alimentation +5V et non un pin digital de l’Arduino mis a 5V.
Script Vous pouvez aussi utiliser tout les scripts disponibles sur le site d’Arduino.
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.setCursor(6,0);
// Print a message to the LCD.
lcd.print("Hello,");
lcd.setCursor(2,1);
// Print a message to the LCD.
lcd.print("my friend !");
}
void loop() {
// Turn off the display:
lcd.noDisplay();
delay(500);
// Turn on the display:
lcd.display();
delay(500);
}
Le circuit Dallas DS1307 (Datasheet) est une horloge temps réel (Real Time Clock), qui fournit secondes, minutes, heures, jours, dates, mois et années.
Le Dallas DS1307 est associé (entre les broches 1 et 2) à un quartz d’horlogerie de fréquence nominale 32,768 kHz.
Les années bissextiles sont prises en compte (jusqu’en 2100).
Le DS1307 s’interface avec un bus I2C, en configuration esclave :
Le DS1307 travaille dans le mode standard (fréquence d’horloge f SCL de 100 kHz)
L’adresse I2C (7 bits) du DS1307 est : 1 1 0 1 0 0 0
J’utilise un Arduino Mega pour l’initialiser via les ports I2C.
/*
Clock_DS1307.pde
Real Time Clock DS1307 avec Arduino Mega
Voir schéma de cablage sur http://samuel.goutenoir.com/archives/134
*/
#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>
int rtc[7];
void Set_Square_Wave(int rate){ // set the square wave output on pin 7 of the DS1307 chip
rate = rate + 144; // add 0x90 (dec 144) to rate
Wire.beginTransmission(0x68); // write the control register
Wire.send(0x07); // register address 07H)
Wire.send(rate); // 90H=1Hz, 91H=4kHz, 92H=8kHz, 93H=32kHz
Wire.endTransmission();
}
void setup()
{
Serial.begin(9600);
// Décommenter la partie suivante et mettez vos valeurs pour initialiser l'horloge
/*
RTC.stop();
RTC.set(DS1307_SEC,0); // Secondes
RTC.set(DS1307_MIN,59); // Minutes
RTC.set(DS1307_HR,20); // Heures
RTC.set(DS1307_DOW,4); // Jour de la semaine
RTC.set(DS1307_DATE,23); // Jour du mois
RTC.set(DS1307_MTH,12); // Mois
RTC.set(DS1307_YR,10); // Année
RTC.start();
*/
// Mettre une resistance de pull up entre pin 7 et Vbat
// 0=1hz, 1=4KHz, 2=8KHz, 3=32KHz
Set_Square_Wave(0); // 1Hz
}
void loop()
{
RTC.get(rtc,true);
for(int i=0; i<7; i++)
{
Serial.print(rtc[i]);
Serial.print(" ");
}
Serial.println();
delay(1000);
}
Ce qui suit est à mettre dans : Arduino/libraries/DS1307 (Respecter la casse)
extern "C" {
#include <../Wire/Wire.h>
}
#include "DS1307.h"
DS1307::DS1307()
{
Wire.begin();
}
DS1307 RTC=DS1307();
// PRIVATE FUNCTIONS
// Aquire data from the RTC chip in BCD format
// refresh the buffer
void DS1307::read(void)
{
// use the Wire lib to connect to tho rtc
// reset the resgiter pointer to zero
Wire.beginTransmission(DS1307_CTRL_ID);
Wire.send(0x00);
Wire.endTransmission();
// request the 7 bytes of data (secs, min, hr, dow, date. mth, yr)
Wire.requestFrom(DS1307_CTRL_ID, 7);
for(int i=0; i<7; i++)
{
// store data in raw bcd format
rtc_bcd[i]=Wire.receive();
}
}
// update the data on the IC from the bcd formatted data in the buffer
void DS1307::save(void)
{
Wire.beginTransmission(DS1307_CTRL_ID);
Wire.send(0x00); // reset register pointer
for(int i=0; i<7; i++)
{
Wire.send(rtc_bcd[i]);
}
Wire.endTransmission();
}
// PUBLIC FUNCTIONS
void DS1307::get(int *rtc, boolean refresh) // Aquire data from buffer and convert to int, refresh buffer if required
{
if(refresh) read();
for(int i=0;i<7;i++) // cycle through each component, create array of data
{
rtc[i]=get(i, 0);
}
}
int DS1307::get(int c, boolean refresh) // aquire individual RTC item from buffer, return as int, refresh buffer if required
{
if(refresh) read();
int v=-1;
switch(c)
{
case DS1307_SEC:
v=(10*((rtc_bcd[DS1307_SEC] & DS1307_HI_SEC)>>4))+(rtc_bcd[DS1307_SEC] & DS1307_LO_BCD);
break;
case DS1307_MIN:
v=(10*((rtc_bcd[DS1307_MIN] & DS1307_HI_MIN)>>4))+(rtc_bcd[DS1307_MIN] & DS1307_LO_BCD);
break;
case DS1307_HR:
v=(10*((rtc_bcd[DS1307_HR] & DS1307_HI_HR)>>4))+(rtc_bcd[DS1307_HR] & DS1307_LO_BCD);
break;
case DS1307_DOW:
v=rtc_bcd[DS1307_DOW] & DS1307_LO_DOW;
break;
case DS1307_DATE:
v=(10*((rtc_bcd[DS1307_DATE] & DS1307_HI_DATE)>>4))+(rtc_bcd[DS1307_DATE] & DS1307_LO_BCD);
break;
case DS1307_MTH:
v=(10*((rtc_bcd[DS1307_MTH] & DS1307_HI_MTH)>>4))+(rtc_bcd[DS1307_MTH] & DS1307_LO_BCD);
break;
case DS1307_YR:
v=(10*((rtc_bcd[DS1307_YR] & DS1307_HI_YR)>>4))+(rtc_bcd[DS1307_YR] & DS1307_LO_BCD)+DS1307_BASE_YR;
break;
} // end switch
return v;
}
void DS1307::set(int c, int v) // Update buffer, then update the chip
{
switch(c)
{
case DS1307_SEC:
if(v<60 && v>-1)
{
//preserve existing clock state (running/stopped)
int state=rtc_bcd[DS1307_SEC] & DS1307_CLOCKHALT;
rtc_bcd[DS1307_SEC]=state | ((v / 10)<<4) + (v % 10);
}
break;
case DS1307_MIN:
if(v<60 && v>-1)
{
rtc_bcd[DS1307_MIN]=((v / 10)<<4) + (v % 10);
}
break;
case DS1307_HR:
// TODO : AM/PM 12HR/24HR
if(v<24 && v>-1)
{
rtc_bcd[DS1307_HR]=((v / 10)<<4) + (v % 10);
}
break;
case DS1307_DOW:
if(v<8 && v>-1)
{
rtc_bcd[DS1307_DOW]=v;
}
break;
case DS1307_DATE:
if(v<32 && v>-1)
{
rtc_bcd[DS1307_DATE]=((v / 10)<<4) + (v % 10);
}
break;
case DS1307_MTH:
if(v<13 && v>-1)
{
rtc_bcd[DS1307_MTH]=((v / 10)<<4) + (v % 10);
}
break;
case DS1307_YR:
if(v<20 && v>-1)
{
rtc_bcd[DS1307_YR]=((v / 10)<<4) + (v % 10);
}
break;
} // end switch
save();
}
void DS1307::stop(void)
{
// set the ClockHalt bit high to stop the rtc
// this bit is part of the seconds byte
rtc_bcd[DS1307_SEC]=rtc_bcd[DS1307_SEC] | DS1307_CLOCKHALT;
save();
}
void DS1307::start(void)
{
// unset the ClockHalt bit to start the rtc
// TODO : preserve existing seconds
rtc_bcd[DS1307_SEC]=0;
save();
}
/*
DS1307.h - library for DS1307 rtc
*/
// ensure this library description is only included once
#ifndef DS1307_h
#define DS1307_h
// include types & constants of Wiring core API
#include
// include types & constants of Wire ic2 lib
#include <../Wire/Wire.h>
#define DS1307_SEC 0
#define DS1307_MIN 1
#define DS1307_HR 2
#define DS1307_DOW 3
#define DS1307_DATE 4
#define DS1307_MTH 5
#define DS1307_YR 6
#define DS1307_BASE_YR 2000
#define DS1307_CTRL_ID B1101000 //DS1307
// Define register bit masks
#define DS1307_CLOCKHALT B10000000
#define DS1307_LO_BCD B00001111
#define DS1307_HI_BCD B11110000
#define DS1307_HI_SEC B01110000
#define DS1307_HI_MIN B01110000
#define DS1307_HI_HR B00110000
#define DS1307_LO_DOW B00000111
#define DS1307_HI_DATE B00110000
#define DS1307_HI_MTH B00110000
#define DS1307_HI_YR B11110000
// library interface description
class DS1307
{
// user-accessible "public" interface
public:
DS1307();
void get(int *, boolean);
int get(int, boolean);
void set(int, int);
void start(void);
void stop(void);
// library-accessible "private" interface
private:
byte rtc_bcd[7]; // used prior to read/set ds1307 registers;
void read(void);
void save(void);
};
extern DS1307 RTC;
#endif
Normalement après avoir charger le programme et lancer l’interface serial, la led devrait se mettre à clignoter chaque seconde.
Si vous cherchez un bon éditeur de schéma électrique et de PCB pour arduino et le tout gratuit, ne cherchez plus, utilisez Fritzing.
Vraiment simple d’utilisation, il prend en charge l’autoroutage et l’exportation sous format PDF des Typons, ce qui permet de créer ses Typons avec une imprimante laser,…
Il est surtout approprié pour les utilisateurs d’Arduino.
Un condensateur est un composant électronique ou électrique élémentaire, constitué de deux armatures conductrices (appelées « électrodes ») en influence totale et séparées par un isolant polarisable (ou « diélectrique »). Sa propriété principale est de pouvoir stocker des charges électriques opposées sur ses armatures. La valeur absolue de ces charges est proportionnelle à la valeur absolue de la tension qui lui est appliquée. Le condensateur est caractérisé par le coefficient de proportionnalité entre charge et tension appelé capacité électrique et exprimée en farads (F).
Une diode électroluminescente, abrégée sous les sigles DEL ou LED (de l’anglais light-emitting diode), est un composant opto-électronique capable d’émettre de la lumière lorsqu’il est parcouru par un courant électrique. Une diode électroluminescente ne laisse passer le courant électrique que dans un seul sens (comme une diode classique) de plus elle produit un rayonnement monochromatique ou polychromatiqueincohérent à partir de la conversion d’énergie électrique lorsqu’un courant la traverse. Elle compte plusieurs dérivées, principalement, l’OLED, l’AMOLED ou le FOLED (pour flexible oled).
‘espace+j’ => Fais bouger le robot tout seul (rester appuyer)
‘espace+t’ et ‘espace+g’ => vont à des points prédéfinis
Script Ruby
if frame==1; setVar('base',0.5);end
if frame==1; setVar('epaule',0.5);end
if frame==1; setVar('coude',0.5);end
if frame==1; setVar('poignet',0.5);end
if frame==1; setVar('roulis',0.5);end
if frame==1; setVar('grip',0.0);end
if key('space')==0 then
if key('c')==1 ; delay(10000); setVar('base',(getVar('base')-0.005)); end
if key('c')==0 ; setVar('base',getVar('base')); end
if key('v')==1 ; setVar('base',(getVar('base')+0.005)); end
if key('v')==0 ; setVar('base',getVar('base')); end
if key('d')==1 ; setVar('epaule',(getVar('epaule')-0.005)); end
if key('d')==0 ; setVar('epaule',getVar('epaule')); end
if key('e')==1 ; setVar('epaule',(getVar('epaule')+0.005)); end
if key('e')==0 ; setVar('epaule',getVar('epaule')); end
if key('f')==1 ; setVar('coude',(getVar('coude')-0.005)); end
if key('f')==0 ; setVar('coude',getVar('coude')); end
if key('r')==1 ; setVar('coude',(getVar('coude')+0.005)); end
if key('r')==0 ; setVar('coude',getVar('coude')); end
if key('up')==1 ; setVar('poignet',(getVar('poignet')-0.005)); end
if key('up')==0 ; setVar('poignet',getVar('poignet')); end
if key('down')==1 ; setVar('poignet',(getVar('poignet')+0.005)); end
if key('down')==0 ; setVar('poignet',getVar('poignet')); end
if key('left')==1 ; setVar('roulis',(getVar('roulis')-0.005)); end
if key('left')==0 ; setVar('roulis',getVar('roulis')); end
if key('right')==1 ; setVar('roulis',(getVar('roulis')+0.005)); end
if key('right')==0 ; setVar('roulis',getVar('roulis')); end
if key('y')==1;
UI.messagebox( " base = #{getVar('base')}\n epaule = #{getVar('epaule')}\n coude = #{getVar('coude')}\n poignet = #{getVar('poignet')}\n roulis = #{getVar('roulis')}\n ");
end
else
if key('t')==1 ;
setVar('base',0.855);
setVar('epaule',0.48);
setVar('coude',0.375);
setVar('poignet',0.36);
end
if key('t')==0 ;
setVar('base',getVar('base'));
setVar('epaule',getVar('epaule'));
setVar('coude',getVar('coude'));
setVar('poignet',getVar('poignet'));
end
if key('g')==1 ;
setVar('base',0.855);
setVar('epaule',0.545);
setVar('coude',0.375);
setVar('poignet',0.36);
end
if key('g')==0 ;
setVar('base',getVar('base'));
setVar('epaule',getVar('epaule'));
setVar('coude',getVar('coude'));
setVar('poignet',getVar('poignet'));
end
if key('c')==1 ;
setVar('grip', 1.0);
end
if key('c')==0 ;
setVar('grip', getVar('grip'));
end
if key('o')==1 ;
setVar('grip', 0.0);
end
if key('o')==0 ;
setVar('grip', getVar('grip'));
end
if key('j')==1;
# appro chute
if frame==100 ;
setVar('base',0.855);
setVar('epaule',0.545);
setVar('coude',0.375);
setVar('poignet',0.36);
end
# move chute
if frame==200;
setVar('base',0.855);
setVar('epaule',0.48);
setVar('coude',0.375);
setVar('poignet',0.36);
end
# grip_close
if frame==250;
setVar('grip', 1.0);
end
# depart
if frame==300;
setVar('base',0.855);
setVar('epaule',0.545);
setVar('coude',0.375);
setVar('poignet',0.36);
end
# move perceuse
if frame==400;
setVar('base',0.585);
setVar('epaule',0.315);
setVar('coude',0.545);
setVar('poignet',0.36);
end
# move boite
if frame==550;
setVar('base',0.715);
setVar('epaule',0.22);
setVar('coude',0.68);
setVar('poignet',0.38);
end
# grip_open
if frame==600;
setVar('grip', 0.0);
end
# ready
if frame==650;
setVar('base',0.5);
setVar('epaule',0.5);
setVar('coude',0.5);
setVar('poignet',0.5);
end
end
if key('j')==0 ;
setVar('base',getVar('base'));
setVar('epaule',getVar('epaule'));
setVar('coude',getVar('coude'));
setVar('poignet',getVar('poignet'));
setVar('grip', getVar('grip'));
end
end
A la base, c’était un robot que je voulais faire, malheureusement je n’avais pas de quoi découper précisément mon châssis, d’où l’idée de créer une CNC qui me permettrait de découper ce que je veux et ainsi mettre en place d’autres projets.
Mais ayant plus grand yeux que grand ventre, je suis parti sur une CNC à grande échelle (environ 80x60cm), ma première et pas dernière erreur. En effet, plus la CNC est grande , plus les chances qu’elle soit précise sont faibles. Enfin bref, j’ai quand même réussi à la faire fonctionner tant bien que mal.
Vous pouvez trouver toutes les photos de la construction sur ma Galerie Picasa.
Création sous Sketchup :
Liste des composants
Récupération:
Arduino Mega (30€)
Roulements à billes
Dremel
Achat Castorama :
1 Aluminium Cornie 20x20x1,5 2m 8,05€
3 MDF 80x40x1,6 3×6,50€ = 19,50€
1 MDF 80x60x1,6 10,70€
3 Tige filetée acier 8mm 1m 3×1,00€ = 3,00€
1 Boulon Tete Fraisée x10 3,60€
1 Aluminium Cornie 15x15x1,5 2m 6,90€
1 Boulon Tete Fraisée x10 2,25€
2 10 Boulon 2,65€ = 5,30€
2 10 Boulon 4,15€ = 8,30€
Achat Sparkfun :
3 Moteur Pas a pas 3×14,95€ = 44,85€
3 EasyDriver Stepper 3×14,95€ = 44,85€
Total : 157,25€
Construction
Pour l’armature, j’ai utilisé du MDF, un bois très facile à découper et relativement beau (grain fin et lisse). Je n’avais pas à ma disposition d’outil tels qu’une scie sauteuse ou une perceuse à colonne. J’ai fait donc comme je pouvais pour percer et découper droit.
Pour le système de translation, j’ai utiliser des angles d’aluminium avec des roulements à billes :
Electronique
Pour contrôler les moteurs pas à pas, j’utilise des drivers spéciaux qui facilitent le contrôle.
Une grosse erreur à ne pas faire, que j’ai évidemment faite, c’est de vouloir souder tous les drivers à côté pour gagner de la place. Eh oui, si vous faites ça, les drivers vont s’envoyer des interférences entre eux et les moteurs ne marcheront pas correctement.
J’ai du donc découper la protoboard à la Dremel (non conseiller, t’as vite fait de déraper) pour séparer les drivers.
Logiciel
Schéma Windows only :
Sketchup => DXF => DXF2Gcode => Gcode => Python Script Gcode to Serial => Arduino Gcode Interpreter => Motor Driver => Motor
J’ai trouver une façon plus simple qui fonctionne sous tous les OS :
Blender => Blender Python script to Gcode => Python Script Gcode to Serial => Arduino Gcode Interpreter => Motor Driver => Motor
Démarche à suivre :
Il faut créer votre objet 2D/Relief sous Blender, l’exporter au format Gcode (.nc) grâce au script python inclus, uploader le Reprap firmware à l’Arduino, qui lui attendra des commandes en Gcode via le port sérial, et donc que vous lui enverrez avec le script Python « Gcode to Serial ».
#
# Pour envoyer un fichier Gcode à l'arduino, entrer dans un terminal : python nc2serial.py < mongcode.nc
#
# Ce script lit ligne par ligne le fichier gcode et l'envoie au port serial de l'arduino
#
# port_id exemples : "COM1" sous Windows, "/dev/ttyUSB0" sous Linux, "/dev/tty.usbserial-A700dGI sous Mac
#
import serial,sys,time
port_id = "/dev/tty.usbserial-A700dGI8"
baud = 38400
print "FLUSHING..."
#ser = serial.Serial(port=port_id, baudrate=baud, timeout=2)
#while True:
# response = ''
# response = ser.readline()
# print response.strip('\n')
# if response is '':
# break
#ser.close()
ser = serial.Serial(port=port_id, baudrate=baud, timeout=30)
for line in sys.stdin.readlines():
ser.write(line)
print line.strip('\n')
while True:
response = ser.readline()
print response
if response.strip() in ['ok','start']:
break
print "Serial closed"
ser.close()