Microblog : A very long article Wikipedia article on the orientation of toilet paper [7 jun à 22:52] [R]

Mercredi, 23 décembre 2015

Photo haute vitesse

Catégories : [ Bricolage/Arduino ]

hsphoto-ensemble

Cet appareil n'a pas de nom, mais il sert à controller un appareil photo et un flash pour prendre des photos d'objets qui tombent. Un rayon laser (récupéré d'un pointeur laser rouge bas de gamme) dont la présence est détectée par un phototrasistor sensible à la lumière visible est interrompu par l'objet qui tombe, et après un temps déterminé, le flash est déclenché.

Le code est disponible.

hsphoto-interface

L'appareil utilise un RBBB (compatible Arduino, mais dans un format plus compact) pour contrôler un écran LCD alphanumérique, l'appareil photo via sa télécommande par câble, et le flash via son sabot. Il permet aussi de règler le délai entre la détection de la chute de l'objet et la prise de la photo. On peut en outre règler la longueur de l'impulsion du flash (ce qui n'est pas très utile apparemment, étant donné que cette durée n'a pas l'air d'avoir d'influence sur la durée du flash, mais cette durée détermine aussi le délai entre le déclenchement du flash et la fermeture de l'obturateur de l'appareil photo). En outre, on peut choisir à quel moment l'obturateur sera ouvert (avant de faire tomber l'objet à photographier, au moment où celui-ci coupe le faisceau laser, ou le mode manuel où l'utilisateur a la responsabilité d'ouvrir l'obturateur), et l'envoi ou non d'une impulsion pour effectuer la mise au point (la télécommande filaire est conçue de sorte à ce que le signal de mise au point soit toujours envoyé avant le signal d'ouverture de l'obturateur, il se peut que l'appareil ne fonctionne pas correctement si le second n'est pas précédé du premier).

hsphoto-pcb

Le RBBB est alimenté par 4 batteries rechargeables NiMH, qui fournissent ensemble une tension maximale de 5,4 V, juste en dessous de la limite maximum du microcontrolleur (5,5 V). Ceci permet de se passer d'un régulteur de tension, à condition de ne pas utiliser de piles alcalines (qui produiraient une tension trop élevée, 6,6 V au maximum).

Une des difficultés a été que le laser tend à chauffer, ce qui diminue environ de moitié sa luminosité au bout de 30 s. À ce moment, le laser n'est alors plus assez puissant pour être détecté par le phototransitor. La seule solution est de ne pas laisser au laser le temps de chauffer.

hsphoto-cadre

Une autre difficulté a été la construction du cadre en bois qui porte le laser et le phototransistor : il n'est pas parfaitement plan (je voulais le rendre démontable et j'ai donc utilisé des angles en acier à visser, mais comme je n'ai pas réussi à visser les vis bien verticalement, elles ont déplacé légèrement les angles et tordu les quatre morceaux de bois). De plus, il n'est pas facile de percer un trou bien droit (pour recevoir le laser) et aligné avec un trou similaire (pour recevoir le phototransitor) sur le coté opposé du cadre.

hsphoto-laser

Pour aligner le laser sur le phototransistor, il faut donc tourner un peu le premier dans son logement jusqu'à ce que le point rouge atteigne le centre du phototransistor. L'appareil dispose d'ailleurs d'un mode de fonctionnement où le laser est allumé en permanence et où l'utilisateur peut voir si le phototransistor est correctement éclairé.

La dernière difficulté a été de me rendre compte que le temps de chute de l'objet (entre le moment où le laser est interrompu et le moment où la photo doit être prise) dépend de la vitesse de l'objet au moment où il passe dans le faisceau laser, donc de la hauteur (au dessus du faisceau) d'où l'objet a été laché. Pour obtenir des expériences répétables, il faut donc faire tomber l'objet à partir du support sur lequel il repose, et il faut donc que ce support soit à une distance connue du faisceau. Le support est donc un morceau de carton ondulé percé d'un trou assez grand pour laisser passer l'objet (mais pas trop grand pour que l'objet ne puisse pas tomber à coté du faiscea) posé sur le cadre en bois. La distance d entre le haut du carton et le faisceau, la hauteur de chute h du haut du carton jusq'à l'endroit où la photo est prise et le temps de chute t sont liés par l'équation suivante : t = √(2/g) × (√h - √d) où g est l'accélération de la pesanteur.

hsphoto_de_1 hsphoto_azrael hsphoto_bonhomme

[ Posté le 23 décembre 2015 à 23:45 | pas de commentaire | ]

Dimanche, 4 mai 2014

New Leffakone Timer

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino | TV/Leffakone ]

new_leffakone_timer

I finally built the timer for the new Leffakone. It is based on an Arduino Uno, which controls two reed relays and one LED. The reed relays can be activated with a very low current (10 mA), meaning that the Arduino can drive them directly from any I/O pin. The relays' contacts are connected in parallel to the power button and the reset button. The Arduino's serial-over-USB port is connected to one of the USB headers of the motherboard with a home-made cable, and the timer is set by software through this serial connection. All the wires coming from the computer case's front panel are connected to the circuit (to the 8-pin header protruding from the protoboard), and wires go from there to the motherboard's front-panel header (2 white wires for the power button, 2 grey wires for the reset button, and 2 blue+black wires for the power-on LED. The two boards are screwed on the bottom plate of the case of an old CD drive; for installation, I closed the case and put it into the computer as a regular CD drive.

While the timer is counting down, it blinks the computer case's HDD LED (which therefore is not anymore indicating the HDD activity).

When the timer expires, it closes the power button's relay for 500 ms. An optional watchdog timer would close the reset button's relay if the machine does not boot correctly i.e., if the timer is not reset within 30 s. This watchdog timer is currently disabled in the code, since the problems I have had with GRUB freezing on startup seem to be related to manually powering the device and switching the TV on shortly after. I'll enable it if it seems necessary. Here is the code for the Arduino.

The software client for the timer is written in Python and is very straightforward: send ASCII digits to the serial port, ending with a newline character. It interprets this number as a number of seconds, and starts counting down. When disconnecting the client from the serial port, the Arduino resets and forgets all about the timer value; I found out that setting the DTR line to False in the Python Serial object prevents this from happeining. I haven't however found out how to prevent a reset when connecting to the Arduino; this is less a problem, since when I connect to it, I want to reset the timer, and reseting the whole program does just that. It seems that it's the Linux driver that asserts the DTR line when opening the serial port; I haven't investigated further. It is worth noting that when the machine boots, it does not reset the Arduino.

Finally, the cristal in the Arduino is accurate to 99.5% which is not enough to guarantee that the timer will wake up the computer within a minute after a countdown of several days. I therefore apply a corrective factor to the time sent to the Arduino. The factor was estimated from a 15.5 hour countdown, which lasted about 90s more than it should have. Over a 7-days countdown, it would cause the timer to expire about 16 minutes too late.

[ Posté le 4 mai 2014 à 20:38 | pas de commentaire | ]

Samedi, 24 mars 2012

Task-Based JeeNode Communication

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino | Informatique ]

For my car heater controller I decided to use Alan Burlison's scheduler. I like it, because it leaves the main program file reasonnably short and allows to separate the code into multiple objects. I don't know if it makes the software more or less easy to write/maintain, but I find it fun to do it this way, and that's all that counts.

To implement 2-way communication between the JeeLink (master) and the JeeNode (slave) using Jean-Claude Wippler's RF12 library, I created a Listener object and a Speaker object that deal with receiving data and sending data respectively, while the Protocol object implements the higher-level protocol.

Here' how the slave's .pde file looks like. Notice how it contains only definitions and a bit of initialization, but no big mess of code?

#define NB_ELEMENTS(a) sizeof(a) / sizeof(a[0])
 
Speaker speaker;
Protocol protocol(&speaker);
Listener listener(&protocol);
 
Task * tasks[] = { &listener, &speaker };
TaskScheduler scheduler(tasks, NB_ELEMENTS(tasks));
 
void setup() {
  rf12_initialize(SLAVE_ID, RF12_868MHZ, HEATER_GROUP);
}
 
void loop() {
  scheduler.run(); // infinite loop
}
Here's a sample of the slave's Listener.
class Listener: public Task { // Task from Alan Burlison's scheduler
    public:
    Listener(Protocol * protocol):
      protocol(protocol)
      {};
 
    bool canRun(uint32_t now); // Taks's interface
    void run(uint32_t now);    // Task's interface
 
  private:
    Protocol * protocol;    // higher-level protocol handler
    uint8_t recv_buffer[BUFFER_LEN];
    uint8_t recv_buffer_len;
};
 
bool Listener::canRun(uint32_t now) {
  if (rf12_recvDone())
    return (rf12_crc == 0 &&  rf12_len <= BUFFER_LEN);
  return false;
}
 
void Listener::run(uint32_t now) {
  recv_buffer_len = rf12_len;
  memcpy((void *)recv_buffer, (void *)rf12_data, recv_buffer_len);
  if (rf12_hdr == (RF12_HDR_CTL | (MASTER_ID & RF12_HDR_MASK)))
    protocol->got_ack();
  else {
    if (RF12_WANTS_ACK) {
      rf12_sendStart(RF12_ACK_REPLY, 0, 0);
      rf12_sendWait(0);
    }
    protocol->handle(recv_buffer, recv_buffer_len);
  }
}

And there's the slave's Speaker. Note that the Spaker tries to send data only if its buffer_len is greater than zero. This prevents calling rf12_canSend() when it's not necessary (according to the RF12 driver, you must not call rf12_canSend() only if you intend to send data immediately after calling it). When the Protocol wants to send something, it needs to get the Speaker's buffer with get_buffer(), fill the buffer with data, and then call send(). Also, I implemented a retry mechanism in case no ACK has been received from the master.

class Speaker: public Task { // Task from Alan Burlison's scheduler
  public:
    Speaker();
    uint8_t* get_buffer();
    void send(uint8_t len, bool ack);
    void got_ack(); // called by the Protocol when it gets an ACK
    bool canRun(uint32_t now);  // Task interface
    void run(uint32_t now);     // Task interface
 
  private:
    uint8_t buffer[BUFFER_LEN];
    uint8_t buffer_len;
    bool with_ack;
    uint8_t retry_count;
    unsigned long next_retry_millis;
};
 
bool Speaker::canRun(uint32_t now) {
  if (buffer_len > 0 && retry_count > 0
                     && millis() > next_retry_millis)
    return rf12_canSend();
  return false;
}
 
void Speaker::run(uint32_t now) {
  if (with_ack && retry_count == 1) {
    buffer_len = 0;
  }
  uint8_t header = (with_ack ? RF12_HDR_ACK : 0)
                  | RF12_HDR_DST | MASTER_ID;
  rf12_sendStart(header, buffer, buffer_len);
  rf12_sendWait(0);
  if (with_ack) {
    retry_count  – ;
    next_retry_millis = millis() + SEND_RETRY_TIMEOUT;
  }
  else
    buffer_len = 0;
}
 
void Speaker::send(uint8_t len, bool ack) {
  with_ack = ack;
  buffer_len = len;
  retry_count = SEND_RETRY_COUNT + 1;
  next_retry_millis = millis();
}
 
void Speaker::got_ack() {
  buffer_len = 0;
}

The master's code is very similar, you can check it there.

[ Posté le 24 mars 2012 à 16:17 | pas de commentaire | ]

Jeudi, 22 mars 2012

Car Heater Controller

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino ]

heater_controller_2

Finnish winters are cold, and petrol engines don't like starting when it's very cold. That's why cars are often equipped with an electric heater that preheat's the cooling liquid for some time before starting the engine. The duration of this pre-heating depends on the temperature (in French). Moreover, since I don't leave home every morning at the same time, I don't want to start heating the car at the same time every day, even if the outside temperature doesn't change much from day to day. Hence this project of a remote-controlled switch for the car heater.

The system is composed of two Arduino-compatible parts: one master, connected to the home computer (always on), and one slave, in the garage. The master is a JeeLink and the slave is based on a JeeNode. Master and slave communicate with each other with a radio (868 MHz, a free Low-power_communication_device band in Europe).

The master

Not much to say about the master, the hardware is a standard JeeLink, which for the purpose of this project is really only a radio transceiver on a Serial-over-USB interface.

The slave

heater_controller_1

The electronic is very simple, and only a few components are needed. I paid special attention to selecting components that are specified to work from -40 °C (although I have no idea how well the device works at that temperature).

The slave is organised around a JeeNode (vertical, in the right-hand corner of the picture), and has the following three features.

It controls a relay (the black box above the orange PCB on the picture), which can be open or closed.

It measures the outside temperature with a DS18S20 sensor.

It measures the current flowing out of the relay using a current transformer (the black ring aroung the brown wire on the left side of the picture).

Moreover, it has a power supply (the black box on the lower left corner of the picture).

You can also notice that the mains cable (a 5 m, outdoors prolongation cord) has an earth wire that has not been severed. The live (brown) and neutral (blue) wires have been cut and connected to the relay. Power for the power supply is taken from the plug-side of the cable, before the relay (so it's always connected to the mains).

Power supply

The power comes from a compact switching power supply that converts 230 V AC into 12 V DC (maximum output power: 4 W). In case the power supply fails, the 1 A fuse (in the holder on the big red wire on the lower-left corner of the picture) should blow before the whole thing catches on fire. Also, although the power supply is designed to be placed on a PCB, I decided not to have any 230 VAC on the PCB, so I soldered the wires straight to its input pins, and isolated them with heat-shrink tube and added epoxy for strenght (the pins are not so strong, I don't want to break them once they are connected to the thick and not-so-flexible wires).

The relay requires 12 V, hence the output value for the power supply. The JeeNode requires a 3.3 V supply, and the onboard voltage regulator could take the 12 V, but would ouput only a low current (less than 100 mA). By adding a 5 V regulator (7805) to supply the JeeNode, the latter can get more current from its on-board regulator.

Relay

The relay (specified to switch up to 400 VAC and 30 A) requires 160 mA to be activated. It is therefore controlled via a BC337 transistor, which is strong enough to withstand the current. The base of the transistor is connected to one digital pin of the JeeNode via a 2 kΩ resistor, which allows to open or close the relay by applying a High or Low signal to that pin.

Temperature sensor
heater_controller_temperature_sensor

The DS18S20 transmits the temperture information digitally over a 1-Wire bus, and therefore requires really nothing more than a 4.7 kΩ pull-up resistor. It works quite happily with 3.3 V at the end of a 15 m cable (an old phone extension cord). Note that since I have three wires in the cable, I didn't even try to power the sensor with parasitic power (anyway, I read somewhere that it doesn't work well at 3.3 V). The Arduino OneWire library does all the work for you, all you need is to connect the data pin of the sensor to one digital input of the JeeNode.

Current sensor

Finally, the current transformer is placed around the live wire coming out of the relay. The design is based on a page at OpenEnergyMonitor that does not appear to exist anymore, but this one should give a good start.

Basically, the current transformer produces a current (not a voltage) that is proportional (depending on the number of turns, my transformer has 1012 turns) to the current flowing through the mains wire that goes through the transformer. A burden resistor (68 Ω in my case) across the two wires produces an AC voltage that is proportional to this current and varies between -1.65 and +1.65 V (corresponding to mains current between -23 and +23 A peak-to-peak). Then one wire of the transformer is connected to a voltage divider made of two 20 kΩ resistors (with a filtering 47 μF capacitor) and the other wire goes to one of the analog inputs of the JeeNode. This way, the analog input sees a voltage that varies between 0 and 3.3 V, which is within the tolerance of the device.

After that, the software samples the analog value 3000 times, applies a high-pass filter to remove the DC offset, and simple math computes the RMS current. After a bit of calibration (using a 60 W lamp, and 500 W halogen lamp, a 1400 W flat iron and a 2300 W electric kettle, and comparing my measurments against those of a wattmeter), I noticed that the reported current is quite accurate (to about 0.01 A, which is more than enough for my purposes).

Box
heater_controller_in_box

The PCB and the relay a screwed on a piece of plexiglas, and the whole device is placed in a project box to protect it from dust. Zip ties around the cables near the holes prevent the cables from being accidentally pulled out of the box.

Schematics
heater_controller

The schematics are available as a PNG picture, and in Eagle format. Note that since I used strip board to assemble the circuit, I haven't paid attention to choosing the right component packages, nor the right type of component. The Eagle schematics is therefore provided for information purposes only, generating a board from it is not going to produce correct results.

The Software

It's all available there. You can obtain it with git using the command
git clone http://weber.fi.eu.org/software/arduino/heater_controller/.git/

[ Posté le 22 mars 2012 à 23:23 | 1 commentaire | ]

Mercredi, 28 décembre 2011

Timelapse Controler

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino ]

timelapse_controller

The timelapse photography controller I helped a friend build is finally complete. He built the hardware, I wrote the software. The latter is uselessly complicated, but I wanted to have fun with C++ and multiple inheritance, so here it is. The device is controlled by a rotary encoder with an integrated push button and a 2x16 character LCD display. It also has a plug to connect it to the camera (via a 2-channel optocoupler) and is powered with 4 AA batteries.

The UI is composed of 4 screens:

  • a status screen, showing how many pictures have been taken so far, as well as the voltage of the batteries
  • a start/stop screen
  • a screen for setting the number of pictures
  • a screen for setting the time interval between the pictures.

Turning the knob moves from one screen to the other, while pressing its button activates the current screen (e.g., starting or stopping, or allowing to change the value of e.g., the time interval).

The last two screens are disabled when the timer is started, and re-enabled when it is stopped. Also, the screen is turned off after a 10s timeout, and switched back on when the button is pressed or the knob is rotated. This allows to reduce the power consumption from abuot 24 mA to 8 mA. This way, a set of 2000 mAh rechargeable batteries should last over 200 hours.

[ Posté le 28 décembre 2011 à 20:40 | pas de commentaire | ]

Vendredi, 2 décembre 2011

Don't Forget pinMode()

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino ]

I spent hours with a friend trying to solve the following problem: an LED and a 430R resistor are connected to the pin of an Arduino (actually an RBBB powered with 3.3 V). Using digitalWrite(pin, HIGH) it did light the LED, but it was very dim. What was more weird, is that the pin was showing only 1 V instead of 3.3 V. After two hours of scratching our heads, I looked up on Google and found the answer: “don't forget to call pinMode(pin, OUTPUT)…”

At boot time, the pins are set as inputs. digitalWrite(pin, HIGH) switches the internal pullup resistor (20K – 50K), which is enough to allows the pin to source a little bit of current at a quite low voltage. It was enough the dimly light the LED, but not enough to get the optocoupler (that was initially connected to the pin) to work properly.

[ Posté le 2 décembre 2011 à 16:38 | pas de commentaire | ]

Lundi, 15 août 2011

Hardware Random Number Generator

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino | Informatique ]

whitenoise

Software random number generators are usually so-called pseudo-random number generators, because they produce a deterministic sequence of numbers that have some of the properties of true random numbers. Obtaining genuinly random numbers howerver requires a non-deterministic processus as the source of randomness. Thermal noise in electronics or radioactive decay have been used, usually requiring an external device to be built and plugged to the computer.

Peter Knight's TrueRandom generates random bits by using the Arduino's ADC (with nothing connected to the analog input pin) to measure electronic noise. It flips the pin's internal pull-up resistor while the measure takes place to increase the amount of noise. The software then keeps only the least significant bit of the result, filters it using Von Neumann's whitening algorithm (read pairs of bits until they are of different values and return 0 (respectively 1) on a 01 (respectively 10) transition). There are several functions that generate different types of numbers based on those random bits.

I reused that code, modified it to allow using another pin than the Arduino's Analog0 and I made my own random number generator. I also wrote a Python script that reads the bits from the serial port, uses the SHA-1 hashing algorithm to distil the data (the raw data has about 6 bit of entropy per byte, distillation produces data with 7.999 bits of entropy per byte; based on the work of Jeff Connelly on IMOTP) and writes them to the standard output or into a file. On my Duemilanove, it can output about 1500 bits/s, while it outputs 1300 bits/s on a JeeLink. The latter makes it an easy-to-transport device that is reasonnably sturdy and fits in the pocket, even if its features (it contains a radio transceiver) are a bit overkill for the job (not to mention expensive).

I also adapted the core of the TrueRandom software to run on my ButtonBox (which is conveniently always connected to my desktop computer). There the output rate is a mere 300 bps, but it's still reasonnably fast for generating a few random numbers when needed (for example for generating one's own PasswordCard). The access to the ButtonBox is shared among multiple clients using button_box_server.py, so a modified Python script was used for obtaining the stream of random bits through the button_box_server.

I haven't had the patience to generate a few megabytes of random data to test the generator with the DieHarder test suite, but the output of Fourmilab's ent test tool looks reasonnable.

[ Posté le 15 août 2011 à 11:08 | 2 commentaires | ]

Lundi, 16 mai 2011

Tyco Slot-Car Controller A/D Conversion

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino ]

tyco_controller_adc

I hooked the Tyco slot-car controller to the Arduino's analog input with a 400 Ω pullup, and set the A/D converter's reference voltage to INTERNAL (meaning 1.1 V). The sampling rate is 100 Hz and the output values are between 0 and 1023. The movements are two successive slow squeezing-and-releasing of the trigger, followed by three quick squeeze-and-release.

  • In the lower picture (red) are the raw data.
  • In the second lower picture (green), the raw data is filtered by a 4th-order, low-pass Butterworth filter, with a 5 Hz cutoff frequency.
  • In the third lower picture (blue), a 32-levels quantization is applied to the raw data.
  • In the top picture (purple), the quantization is applied to the filtered data.

A value of 1023 (the maximum) indicates that the electrical contact is broken i.e., that the trigger is in the rest position or its maximum.

I have tried hardware filtering with capacitors (1 nF, 100 nF and 1μF), but the digital filter gives the best results. I don't doubt that more advanced hardware filters would have produced similar, if not better results, but they would have required more components, and if you can afford to do it in software, why bother with the extra hardware? Software filtering is amazing… The code for the software filter has been generated on this very useful website.

Additionally, conductive grease applied to the variable resistor may reduce quite much the noise (or shortcut the whole coil of wire…)

[ Posté le 16 mai 2011 à 21:56 | pas de commentaire | ]

Samedi, 7 mai 2011

Slot Car Speed Controller

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino ]

I just tested the first prototype of the speed controller for the Tyco slot cars. Currently, the Arduino reads the potentiometer with analogRead() and applies PWM (with analogWrite()) on the base of a BC547 transistor. The transistor acts as a driver for a FQP70N10 MOSFET which controls the motor. The MOSFET doesn't seem to heat at all (I selected this model for exactly that reason) and speed control works (i.e., I can drive the car on a simple ring circuit, down to quite low speed).

My initial idea was to drive the MOSFET directly with the Arduino, but I noticed after buying a pair of those that they it's not a logic-level MOSFET. Driving it with 5 V would theoretically work (I need about 1 A, which is well within the capabilities of the device), but the internal resistance would be much higher that the value touted on the datasheet, and thus dissipate more heat (exact figures for the resistance at 5 V are not available from the datasheet).

This was a proof of concept, and the concept is therefore proven, I can start working on measuring, with the Arduino, the current delivered to the motor.

[ Posté le 7 mai 2011 à 22:21 | pas de commentaire | ]

Lundi, 14 mars 2011

Arduino Workbench

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino ]

Arduino_workbench

Here's a mini-workbench for Arduino prototyping, made of 6.5 mm plywood.

The Arduino board stands on whatever-they-are-called threaded thinggies you use to screw the motherboard into the computer case without it touching the metal. Arduino screw holes are 3.2 mm in diameter, so I had to drill them to 3.5 mm. It survived the treatment.

The breadboard had an adhesive back, so this one was easy.

The LCD has one potentiometer (top) for contrast and one switch for the LED backlight (depending on the power source, backlight may consume too much current, so it can be switched off if needed). The connectors at the end of the ribbon cable are made from component legs and shrink tube.

The drawback is that now it takes much more space than it used too…

[ Posté le 14 mars 2011 à 22:29 | pas de commentaire | ]

Samedi, 19 février 2011

Arduino with Vim

Traduction: [ Google | Babelfish ]

Catégories : [ Bricolage/Arduino | Informatique ]

If you are used to Vim as a text editor, the Arduino IDE is terrible to use. After a little bit of fiddling, here are my tips to program an Arduino using Vim.

Makefile

To compile the Arduino software, I found the Makefile by Alan Burlison and I modified it to suit my needs. You can get the modified version and use it at your own risks.

It has been modified as follows:

  • Support for arduino 0022 only (but you can change the version number in the Makefile). Versions prior to 0018 are not supported.
  • Binaries are located in /usr/bin.
  • The board is by default atmega328.
  • The programming protocol is stk500v1 and the speed is 57600 bauds.
  • The terminal emulator is xterm and the serial communication software is picocom.
  • The serial port is /dev/ttyUSB0.

All these default values can be changed in the Makefile.master file. Moreover, the following changes have been made:

  • After killing the serial communication software, sleep for 1 second
  • Before starting the programmer, the DTR signal is triggered with stty to reset the board (programming would otherwise not be possible)
  • Warnings remain warnings (GCC's -Werror flag has been removed, because I had a weird warning that I don't know how to fix)
  • The sketch's .pde file is hardlinked into the build directory, and is #included in sketchname_pde.cpp instead of copied into it. This allows GCC to report the errors on the proper line of the .pde file as well as report the proper path for this file in its error messages (when compiling sketchname_pde.cpp, GCC is in the build directory; since it would include ../sketch.pde, the error messages relative to this file would point to a file name starting with ../, but since Vim is in the parent directory, the path to sketch.pde would be wrong and Vim's QuickFix fails to find the file).
  • Linking is made by gcc instead of g++ because of a bug in linking to libm (which is needed if you want to do floating point computations, so it links against it by default).
  • A vim: line has been appended to make Vim recognize the file as a Makefile

To use this Makefile, put Makefile.master into your sketchbook directory, and create in your sketch's directory a Makefile which contains include ../Makefile.master. If you want to add extra libraries (here RF12, GLCDlib and Ports), it looks like this:

LIBS = RF12 GLCDlib Ports
LIB_DIRS = $(addprefix ../libraries/,$(LIBS))
include ../Makefile.master

Typing make inside the directory where the Makefile resides builds the sketch. make upload uploads it, make monitor starts the serial communication software on the serial port and make upload_monitor does both sequentially. Finally, make clean cleans up the build directory created when buidling the sketch.

Arduino Syntax File for Vim

Get arduino.vim by Johannes Hoff and put it in your ˜/.vim/syntax/ directory. It will let Vim recognize .pde files are as arduino, turning on C++ syntax highlighting plus Arduino-specific keywords.

Tabs

Vim allows to open multiple tabs: run vim -p *.* in your sketch's directory, and it opens all the files (except the Makefile) in separate tabs. Use Ctrl-PgUp and Ctrl-PgDown to switch between tabs.

To close all tabs at once, you can use :tabd q, but this is tedious, so I made a shortcut: Add command Q tabd q to your .vimrc and you can close all the tabs at once using :Q. You can do the same with :w, :wq and :x if you want.

Type :help tab to learn more about tabs (especially, :tabe xyz opens file xyz in a new tab. I thought you'd be glad to know).

QuickFix

You can call make from within Vim by typing :make but that's tedious also. I added the following mappings to my .vimrc:
imap <F9> <ESC>:make<CR>
map <F9> :make<CR>

This lets F9 calls :make (whether you're in command mode or in insert mode). You may want to add set autowrite in your .vimrc so that your files are automatically written when you call make.

Now, at least in Debian, after the call to :make has completed, when you return to your file's screen Vim redirects you to the file that contains the first error in make's output. In my setup, this is a warning in a file belonging to Arduino's core, which I don't want to modify. I could of course press Ctrl-O to return to the file I was editing just before running :make, but that's too much work. What I wanted is to be able to let Vim jump to the files containing warnings and errors, but to force it to ignore system files. The solution is then to add to your ˜/.vimrc the following (all in one line, without spaces after the equal sign):

autocmd Filetype arduino set errorformatˆ=\%-G../libraries\%.\%#,\%-G../../libraries\%.\%#,%-G/space/mweber/tmp/arduino-0022\%.\%#

It requires some tuning, because your Arduino directory is probably not in /space/mweber/tmp/arduino-0022, but since you're smart, you have already understood how to adapt it to your setup.

Please note that to get this setup to work properly, you need to append // vim:ft=arduino to all of the .pde, .cpp and .h files belonging to your sketches, otherwise the Vim will not do the ignoring above. And for this to work, modelines must be enabled by adding set modeline to your ˜/.vimrc.

Finally, since you opened all your files in tabs already, tell Vim not to open the file containing a warning/error in the current tab, but rather in the tab that already contains the file. You do this by adding set switchbuf=usetab in your ˜/.vimrc.

In short, your ˜/.vimrc has now these extra lines:

command Q tabd q
command W tabd w
set modeline
set autowrite
set switchbuf=usetab
imap <F9> <ESC>:make<CR>
map <F9> :make<CR>
autocmd Filetype arduino set errorformatˆ=\%-G../libraries\%.\%#,\%-G../../libraries\%.\%#,%-G/space/mweber/tmp/arduino-0022\%.\%#

[ Posté le 19 février 2011 à 19:22 | 2 commentaires | ]

Lundi, 16 août 2010

Compte tours (prototype)

Catégories : [ Bricolage/Arduino ]

Compte_Tours_Proto

Le prototype de la partie électronique du compte-tours pour circuit auto est prêt. Le code source est disponible .

La diode IR et le phototransistor sur la droite permettent de simuler le passage de la voiture sur une piste. Le buzzer juste à coté donne le départ avec un signal sonore, signale un faux départ avec un autre signal sonore et la fin de la course avec un troisième. Les deux boutons au milieu permettent de choisir les options du menu.

Le menu propose trois options, une par ligne. Un des boutons permet de passer à la ligne suivante (et repart du haut une fois arrivé à la dernière ligne), l'autre permet d'activer l'option choisie. La première option permet de choisir le nombre de tours de la course ; la second permet alternativement de choisir la durée de la course (en minutes) ; la troisième démarre la course.

Durant la course, pour chacune des deux pistes, le nombre de tours parcourus est affiché, ainsi que le chronomètre du tour en cours, le chronomètre de la durée totale de la course et, après le premier tour, la durée du tour le plus court.

Lorsque le nombre de tours est atteint par un des participants, ses chronomètres sont arrêtés et le signal de fin de la course retentit. Lorsque l'autre participant parvient au nombre de tours choisi, ses chronomètres sont arrêtés à leur tour.

Lorsque la durée choisie est écoulée, les deux chronomètres sont arrêtés.

[ Posté le 16 août 2010 à 21:02 | 1 commentaire | ]

Jeudi, 12 août 2010

Oscilloscope rudimentaire

Catégories : [ Bricolage/Arduino ]

J'ai bricolé hier un script python/GTK qui représente de manière graphique les données produites par le programme-exemple AnalogInSerial. Le code source sans documentation se trouve . Le code est dans le domaine public.

arduino_oscilloscope_noise

L'entrée analogique n'étant reliée à rien, elle produit surtout du bruit, de fréquence régulière (trop lent pour être les 50 Hz du secteur, mais comme la fréquence d'échantillonage est de l'ordre de 70 Hz, il se peut que le signal soit mal échantilloné) et d'amplitude constante.

arduino_oscilloscope_up

Ce qui est plus surprenant, c'est que l'amplitude du bruit diminue lorsque l'Arduino est soulevé de la table.

arduino_oscilloscope_tap

L'amplitude augmente temporairement lorsqu'on tapote le connecteur (ici le circuit est posé sur la table).

arduino_oscilloscope_blow

La valeur moyenne lue augmente lorsqu'on souffle sur le connecteur (le circuit est en l'air), tandis que l'amplitude des oscillations diminue. Ensuite, la valeur moyenne diminue très progressivement (sur plusieurs secondes), avant de retrouver son niveau de départ.

[ Posté le 12 août 2010 à 22:46 | 4 commentaires | ]

Mercredi, 11 août 2010

Hello World LCD

Catégories : [ Bricolage/Arduino ]

Arduino_LCD_1

J'ai récupéré l'écran LCD (4 lignes de 20 caractères) de feu Poppikone et je l'ai branché sur l'Arduino. Le Hello World livré en exemple avec la bibiothèque LiquidCrystal fonctionne :)

[ Posté le 11 août 2010 à 23:51 | pas de commentaire | ]

Mardi, 24 novembre 2009

Détecteur IR

Catégories : [ Bricolage/Arduino ]

Le détecteur IR (QRB1134) ne fonctionne pas très bien pour détecter le déplacement de l'aiguille du compteur d'eau. Le fait qu'il y ait une couche de verre et que le compteur soit sous eau ne doit probablement pas faire partie des paramètres normaux de fonctionnement…

J'ai suivi le schéma à superdroidrobots.com pour le branchement, en ajoutant une LED rouge entre la résistance de 10 kΩ et le collecteur du phototransistor. L'Arduino n'a servi que comme source de tension stabilisée.

L'émetteur IR a une tension de polarisation de 1,7 V et supporte jusqu'à 40 mA, il nécessite donc une résistance de 83 Ω. Avec 110 Ω, on obtient 30 mA. J'ai utilisé deux résistances de 220 Ω en parallèle lors du deuxième test.

Il faudrait essayer en utilisant une entrée analogique de l'Arduino et observer les variations de tension au bornes du capteur pour voir si on arrive à détecter le passage de l'aiguille.

[ Posté le 24 novembre 2009 à 21:43 | pas de commentaire | ]

Lundi, 28 septembre 2009

Compteur d'eau

Catégories : [ Bricolage/Arduino ]

J'ai enfin essayé de détecter le passage de l'aiguille des décilitres du compteur d'eau en utilisant l'oscilloscope, mais sans succès. Je suppose que le verre diffuse trop les infrarouges, et que l'aiguille est trop petite pour être détectée. Le capteur voit facilement un trait de marqueur noir de 5 mm sur du papier blanc, et dans certaines conditions, un trait de 1,5 mm, mais est incapable de percevoir un trait de 0,5 mm.

compteur_d_eau_1

Ce que j'ai réussi à détecter en revanche, c'est la rotation d'une sorte d'hélice à 6 pales qui tourne lorsque de l'eau passe à travers le compteur. J'obtiens un signal oscillant entre 960 et 972 (sur l'échelle de 0 à 1024 de l'ADC de l'Arduino), mais il faudrait mesurer la fréquence pour connaître la vitesse de rotation de l'hélice, et ensuite trouver la relation entre la vitesse de rotation et le débit d'eau.

AJOUT: l'hélice semble faire 6 tours par litre d'eau.

compteur_d_eau_2

Il y a a priori suffisamment de points pour trouver la fréquence même si le débit d'eau augmente.

AJOUT: la fréquence d'échantillonage maximale par défaut est 9600 Hz (trouvé ). Le compteur ayant un débit maximum de 2500 L/h, ça fait 25 mouvement de pale (1/6 è de tour) par seconde. Si on compte 10 échantillons par mouvement de pale, il faut échantilloner à 250 Hz, ce qui est largement faisable. En pratique, je suppose qu'une fréquence plus faible devrait suffire aussi.

[ Posté le 28 septembre 2009 à 19:07 | 1 commentaire | ]