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

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 | ]

Adresse de trackback

https://weber.fi.eu.org/blog/Informatique/task_based_jeenode_communication.trackback

Commentaires

Aucun 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 | ]

Jeudi, 15 mars 2012

Very big, very small

Traduction: [ Google | Babelfish ]

Catégories : [ Science ]

Scaling the solar system down to human sizes leads to more interesting comparisons. Let's assume the Earth is the size of a pin head (2 mm in diameter). We then have the following results:

  • A human being living on the surface of the pinhead would be 0.30 nm (the size of two dihydrogen molecules)
  • Mount Everest would be 1.4 μm tall (1/5 of the thickness of a strand of spider's web silk)
  • Geostationary satellites would orbit the pin head at 5 mm from its surface but the International Space Station would be at only 60 μm from the surface (the thickness of a hair)
  • A lightyear would be 1500 km long (the distance between Copenhagen, Denmark and Rome, Italy), so the closest star (Proxima Centauri) would be 6600 km away (distance between Paris, France and New Dehli, India, or between New York, USA and Berlin, Germany)
  • The Oort cloud would be 3000 km in diameter (the distance between Madrid, Spain and Helsinki, Finland, with the volley ball representing the Sun located somewhere near Cologne, Germany)
  • The diameter of the Milky Way (our galaxy) would be equivalent to the distance between the Sun and Earth
  • The whole universe would be 20·1012 km in diameter, that is 2 lightyears (diameter of the Oort cloud, or half the distance to Proxima Centauri)

[ Posté le 15 mars 2012 à 10:06 | pas de commentaire | ]

Adresse de trackback

https://weber.fi.eu.org/blog/Science/very_big_very_small.trackback

Commentaires

Aucun commentaire

Mercredi, 14 mars 2012

The Solar system is big!

Traduction: [ Google | Babelfish ]

Catégories : [ Science ]

http://www.aerospaceweb.org/question/astronomy/q0247.shtml

Aerospaceweb.org

The solar system is big, that's well known. But how big, exactly?

Let's assume the Sun is the size of a volleyball (about 21 cm in diameter). We would then have the following relative planet sizes and distances to the ball:

  • Mercury: 1 mm diameter (a small pin head), 9 m from the ball (a bus)
  • Venus: 2 mm diameter (a pin head), 16 m from the ball (a semi-trailer truck)
  • Earth: 2 mm diameter (a pin head), 23 m from the ball
  • Mars: 1 mm diameter (a small pin head), 35 m from the ball (a blue whale)
  • Jupiter: 22 mm diameter (a walnut), 120 m from the ball (maximum length of a football/soccer field)
  • Saturn: 19 mm diameter (a smaller walnut), 220 m from the ball (one TGV train)
  • Uranus: 8 mm diameter (a cherry's kernel), 460 m from the ball (a double TGV train)
  • Neptune: 8 mm diameter (a cherry's kernel), 700 m from the ball (length of the Avenue de l'opéra, Paris, France)

By comparison, the Moon would be 0.5 mm in diameter (a grain of sand) and 6 cm from the pin head (the length of the little finger).

[ Posté le 14 mars 2012 à 23:20 | pas de commentaire | ]

Adresse de trackback

https://weber.fi.eu.org/blog/Science/solar_system_is_big.trackback

Commentaires

Aucun commentaire

Vendredi, 9 mars 2012

Large Numbers

Traduction: [ Google | Babelfish ]

Catégories : [ Science ]

Googolplex

My daughter asked me yesterday what is the largest number I know. The answer was “a Googolplex”, which is 10googol with googol = 10100.

While you can write a googol on a sheet of paper (it's a one followed by 100 zeros), you cannot write a googolplex on paper. Or can you? how much paper do you need for that?

Let's assume you can write 10 000 digits on one sheet of A4 paper. You therefore need 1096 sheets of paper. One tree can produce 10 000 sheets of paper, and there are about 1012 trees on Earth. You'd need 1080 Earths to provide all the paper. Not going to work.

Now let's see if there's even enough matter in the universe to make all this paper: assuming that all the matter in the universe can be converted to paper, is there enough of it? Paper is made of cellulose, chains of D-glucose, the latter weighing 128 g/mol. So a 5 g sheet of A4 paper contains about 2.5·1022 molecules of linked D-glucose, each of which is made of 128 hadrons (protons and neutrons). A sheet of paper is therefore made of 3·1024 hadrons, which is almos the same thing as an atom of hydrogen. The universe contains roughly 1080 atoms, which translate roughly as 1056 sheets of paper. We'd need 1040 universes to make all the needed paper. Not going to work either.

That was a very big number.

[ Posté le 9 mars 2012 à 11:44 | 1 commentaire | ]

Adresse de trackback

https://weber.fi.eu.org/blog/Science/large_numbers.trackback

Commentaires