Engine RPM (Part 4)

Part 1, 2, 3, 4

In this version of the arduino stroboscope, the standard micros() function is no longer used. Instead timer 1, an accurate 16 bits counter shall be exclusively used. As a consequence of the disabled timer 0 and timer 2, no interrupts will bother the output signal except the timer 1 interrupts themselves.

Timer 1 settings is extracted from the data acquisition engine from PlainDSP which proved to be very accurate within a wide range of frequencies.

void SetTimer(float rpm) 
/* Set acquisition parameters, full options */
{
	/* Compute frequency */
	float frequency = ((rpm * 16.0) / 60.0);
	/* Disable all interrupts */
	cli();
	/* Disable timers 0 and 2 in order to improve stability */
	TIMSK0 = 0x00; /* Disable timer/counter0 */
	TIMSK2 = 0x00; /* Disable timer/counter2 */
	/* Reset Timer/Counter1 control registers and Interrupt Mask Register */
	TCCR1A = 0x00; 
	TCCR1B = 0x00; 
	TIMSK1 = 0x00; 
	/* Compute clock timer prescaler */
	uint8_t preScalers[] = {0, 3, 6, 8, 10}; /* Log2 of prescalers */	
	uint8_t timerPrescaler = 0;
	uint32_t upperCount;
	do {
		upperCount = uint32_t(F_CPU / (frequency * (1 << preScalers[timerPrescaler]))) - 1 ;
		timerPrescaler += 1;
	} while ((upperCount & 0xFFFF0000) && (timerPrescaler < 5));	
	OCR1A = uint16_t(upperCount);
	TCCR1B |=  (1 << WGM12); /* Set Clear Timer on Compare Match (CTC) Mode (Mode 4) */
	TCCR1B |= timerPrescaler; /* Set timer prescaler */
	TIMSK1 |= (1 << OCIE1B); /* Enable timer1 interrupt  */
	sei(); /* Enable all interrupts */
}

ISR(TIMER1_COMPB_vect)
/* Invoked on completion of counting (Compare mode) */
{
	_counter += 1;
	_counter &= 0x0F;
	/* Flip LED state */
	if (_counter == _onTime) {
		PORTB &= ~_ledPinMask;
	} else if (!_counter) {
		PORTB |= _ledPinMask;
	}
	_synch = 1;
}

Timer 1 provides a stable time base for a sub counter of 4 bits. In other words each flash cycle can be decomposed in 16 basic steps. The reason for this lies in the need for adjusting the phase of the stroboscope. If the rotational speed of the object to monitor is strictly equal to the flash frequency of the arduino stroboscope, chances are that the flash will no spot on the target. You could either move the led in front of the target or leave the LED where it is and adjust the phase until the flash hits the target itself.

Adjusting the phase is pretty simple. It consists in add adding an extra count to the secondary counter. In trigonometric words, one more count results in 360/16= +22.5 degrees. If the target is 180° out of phase, 8 clicks on the phase button will be necessary to synchronize the light beam and the target.

Next is code section for the phase adjustment. Note that the counter is updated in a synchronized manner versus the base counter.

	_synch = 0;
	while(!_synch) ;
	if (Button()) {
		_counter += 1;
		_counter &= 0x0F;
		while(Button());
	}

A quick check with the oscilloscope shows a very stable and accurate signal. Ultimately, here comes the whole code

/*

	Accurate stroboscope,
	ATmega328 powered Arduino only
	Copyright (C) 2015 Didier Longueville

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
*/

const uint8_t _ledPinMask = ( 1 << PINB5); /* Defaults to digital pin 5 aka the LED pin */
const uint8_t _phaseBtnPinMask = (1 << PINB0); /* Defaults to digital pin 8 */ 
volatile uint8_t _counter = 0;
volatile uint8_t _onTime = 4; /* versus 16 */
volatile uint8_t _synch = 0;

void setup()
{
	InitStrobeLED();
	InitButton();
	SetTimer(4096.0); /* Set strobe frequency */
}

void loop()
{
	_synch = 0;
	while(!_synch) ;
	if (Button()) {
		_counter += 1;
		_counter &= 0x0F;
		while(Button());
	}
}

void SetTimer(float rpm) 
/* Set acquisition parameters, full options */
{
	/* Compute frequency */
	float frequency = ((rpm * 16.0) / 60.0);
	/* Disable all interrupts */
	cli();
	/* Disable timers 0 and 2 in order to improve stability */
	TIMSK0 = 0x00; /* Disable timer/counter0 */
	TIMSK2 = 0x00; /* Disable timer/counter2 */
	/* Reset Timer/Counter1 control registers and Interrupt Mask Register */
	TCCR1A = 0x00; 
	TCCR1B = 0x00; 
	TIMSK1 = 0x00; 
	/* Compute clock timer prescaler */
	uint8_t preScalers[] = {0, 3, 6, 8, 10}; /* Log2 of prescalers */	
	uint8_t timerPrescaler = 0;
	uint32_t upperCount;
	do {
		upperCount = uint32_t(F_CPU / (frequency * (1 << preScalers[timerPrescaler]))) - 1 ;
		timerPrescaler += 1;
	} while ((upperCount & 0xFFFF0000) && (timerPrescaler < 5));	
	OCR1A = uint16_t(upperCount);
	TCCR1B |=  (1 << WGM12); /* Set Clear Timer on Compare Match (CTC) Mode (Mode 4) */
	TCCR1B |= timerPrescaler; /* Set timer prescaler */
	TIMSK1 |= (1 << OCIE1B); /* Enable timer1 interrupt  */
	sei(); /* Enable all interrupts */
}

ISR(TIMER1_COMPB_vect)
/* Invoked on completion of counting (Compare mode) */
{
	_counter += 1;
	_counter &= 0x0F;
	/* Flip LED state */
	if (_counter == _onTime) {
		PORTB &= ~_ledPinMask;
	} else if (!_counter) {
		PORTB |= _ledPinMask;
	}
	_synch = 1;
}

void InitStrobeLED(void) 
{
	/* Make the pin an output pin */
	DDRB |= _ledPinMask;
	/* Turn the pin low */
	PORTB &= ~_ledPinMask;
}

void InitButton(void) 
{
	/* Make the pin an input pin */
	DDRB |= _phaseBtnPinMask;
	/* Bias pin */
	PORTB |= _phaseBtnPinMask;
}

uint8_t Button(void) 
{
	uint8_t res = 0;
	if ((~PINB & _phaseBtnPinMask) == _phaseBtnPinMask) {
		res = 1;
	}
	return(res);
}

 

 

 

Engine RPM (Part 3)

Part 1, 2, 3, 4

Previous posts on measuring engine RPM are featuring electronic interfaces with devices that sense the engine rotation. It is sometimes impossible to connect such sensor so that other techniques must be used in order to check and adjust an engine RPM. Today, we will use a contact-less technique featuring a light beam directed toward a reflecting target attached to the rotating device. The proposed application features the stroboscopic effect, well known by those who like to go dancing in clubs. A quick search on the net will give you plenty of information related to the principle of operation and examples of use of stroboscopes. In simple words, a flash light directed toward a moving object will decompose the motion of this object in successive snapshots. If this object has a periodical motion which is synchronized with the light beam, the target will look immobile. The least change in synchronization will result in a slow motion of the spotted target clockwise or counter-clockwise.

Building a stroboscope with Arduino is quite simple as we only need a bright LED and few lines of code. It is also a good programming exercise for improving the accuracy and usability of the measurement device.

In its simplest version, the stroboscope shall be able to measure speeds with an accuracy better than 2% between 1 and 6 000 rpm which degrades down to 4% at higher frequencies. The sketch is an extrapolation of the most famous “blink” sketch using microseconds as time base. Next lines of pseudo code illustrate a full flashing cycle:

  • Turn light ON
  • Wait for next change in light state
  • Turn light OFF
  • Wait for next change in light state

And here is the full sketch:

int32_t _interval, _onTime, _offTime;
const int16_t _onTimeRatio = 10; // %
int32_t _now, _lastTime;
const uint8_t _ledPinMask = (1 << PINB5);


void setup()
{
	InitLED();
	SetTimer(4100.0);
}

void loop()
{
	PORTB |= _ledPinMask;
	do {
		_now = micros();  
	} while ((_now - _lastTime) < _onTime);
	_lastTime = _now;

	PORTB &= ~_ledPinMask;
	do {
		_now = micros();  
	} while ((_now - _lastTime) < _offTime);
	_lastTime = _now;	
}

void SetTimer(float rpm)
{
	_interval = int32_t(1000000.0 * 60.0 / rpm); // in micros	
	_onTime = ((_interval * _onTimeRatio) / 100);
	if (_onTime < 1) { /* prevent null time */
		_onTime = 1;
	}
	_offTime = (_interval - _onTime);
	_lastTime = micros();
}

void InitLED(void) 
{
	/* Make the pin an output pin */
	DDRB |= _ledPinMask;
}

 

Pretty simple. The hardware section is even simpler as it consists in a white bright led and its biasing resistor.

20150620_174840

Checking the signal on a scope gives us some information about the signal accuracy and stability.

NewFile47

Do not take the figures as absolute values as in fact they are captured from an (slightly) unstable signal. These are extreme results and the instability is mainly due to the handling of the micros() function and to the activity of both timer 1 and timer 2 under standard operating conditions. Although this version will suffice in most cases (under 6000 rpm, so as to say 100 Hz) , an advanced version of the arduino stroboscope shall be considered in the next posts.

Next is a picture illustrating the use of the arduino based stroboscope. A simple piece of white adhesive tape sticks to the blades of a fan:

20150620_194852

And here is a short video illustrating the stroboscopic effect:

From the video, you can see that the spot light “disappears”. In fact, the stroboscope looses its synchronization due to the slight slips of fan speed. If the spot light looks like it goes clockwise, the actual speed is slower than expected. If the spot light looks like it goes counter-clockwise, the actual speed is faster than expected. In next versions, we will add some extra features for adjusting the proper synchronization…

Next post on same subject

Malware of the day

I used Filezilla happily for years until the last few days. For still uncertain reasons, the latest revision of FileZilla comes corrupted. While Filezilla used to propose frequent updates, I paid a light attention to the latest upgrade process, up to the point when additional screens intrigued me. As I also noticed that a “Source Forge” shortcut had beed installed on my desk I immediately canceled the installation and went on the Internet for some information. Too bad, my assumptions seem to be real : something wrong is happening with Filezilla. As I needed an FTP client badly, I tried to install a previous version of Filezilla but the application failed to work properly. Ooooooops. Time to perform a strong clean up !

Time also to find an alternative. A quick search on the Internet brought me a couple of freeware applications among which I choose the simple and already efficient “Core FTP LE/Lite” application. The look and feel is very close from FileZilla, it misses some refinements, but who cares about refinements from an application which brings malware to your computer ?

Publication of the day

We are glad to read that the PlainDSP kit is used in many, many different types of applications and many, many various places around the world.This publication, along with pending ones, bring the proof that open source based applications can be really powerful and regarded as serious games. Check this awesome insect detection based on wing flap sound sensing.

Permalien de l'image intégrée

Why wouldn’t you give PlainDSP a try ?

 

3D Printing (Part 7)

Part 1234567

After many hours of parts design and many rolls of ABS fused in our Makerbot Replicator 2x, it is time to write a little review on this nice printer, just be before it comes obsolete because of the new announced Makerbot products.

The Replicator 2x is doing what it was supposed to do. It is definitely an experimental printer which means that it is a good basis for printing all sorts of parts, but it suffers from uncontrolled performances which result in many printing failures and big need for improvements in part design and parameter settings.

The most critical aspect of the Makerbot 2x is the temperature control of the whole printer. I do not even care about the mod applied to the extruders thermocouple which is, to my opinion, a straight design error more than an uncontrolled function. Printing a simple ruler, 2 x 2 x 15 cm illustrates very well the major flaw. In most cases, this type of print will fail because of corner warping. This is very frustrating phenomenon because it happens  late in the printing process which means a loss of ABS and and a loss of time.

I read here an there many comments and suggested tricks to overcome this problem: Use this brand for acetone, use this type of Kapton tape, rub the Kapton with sand paper, do not rub the Kapton, change the heated bed temperature, spit on the Kapton tape (Oh nooo) …

I personally identified two causes for this defect. One is the heat balance of the part, the other is more mechanical. My assumption is that both causes have approximately the same weight. As the heat balance is pretty complex to handle and would require significant mods to the printer, I suggest that we concentrate on the second cause.

Here are few points to keep in mind while tweaking these warping issues:

  • ABS does not have sticking properties. If it would, it would not flow through the heated extruder, would it?
  • Acetone does not have sticking properties, neither Kapton
  • Putting the top cover on or off as no effect on the warping. Except that printing large flat surfaces with the cover on will lead to filament drive problems.

So how come my part stick on the heated Kapton coated bed?

The absence of air between the Kapton surface and the ABS film deposit (in other words, vacuum) is responsible for the “sticking” of the part on the bed. It is the atmospheric pressure which pulls the part on the Kapton surface. Thus the following thoughts and hints:

  • The larger the printed surface, the more the force as F= P.S where F is the force applied to the part (in N), P is the pressure (in Pa/m^2, with atmospheric pressure = ~100000 Pa) and S is the (contact) surface (in m^2). For example, the atmospheric pressure will exert a force on a printed part which contact surface is 10 cm^2 identical to a weight of 10 kg. Adding mouse ears to the part corner increases the contact surface and thus the pressure exert on the part.
  • The better the surface of the bed, the lesser the air leaks. Scratches on Kapton tape will create the so called capillary leaks. Poor bed and nozzle adjustments will also lead to multiple air leaks because the ABS will be deposit as rolls and not as a layer.

I am currently experimenting and testing heavily an alternative technique which really solves elegantly and efficiently this question. However, I am immensely curious to see the new Makerbot Replicator printer. From the pictures on their web site, I clearly see a fan which indicates that the heat balance within the printing chamber as been reworked, probably with the hep of the Stratasys R&D people…

3D_printer

The contribution of  Stratasys to Makerbot is clearly visible on the announced Makerbot Replicator Z18 !

 

 

Gamer Assembly 2015

Welcome to the Gamer Assembly 2015 in Poitiers / France!

Quai Lab was in charge of leading the Maker Space. We invited various contributors to the word of open source, open hardware and open knowledge. Here are a few snapshots from the grand opening of the gamer by Désiré KOUSSAWO:

ga_2015_2

Quai Lab is on stage with Sébastien BONNIFET representing the association!

 

 

ga_2015_1

 

This is a great time for Quai Lab which grew up so quickly and so nicely. More news coming…

 

Drive the Small Cox

We will be happy to welcome you at the Maker Space within the Gamer Assembly in Poitiers next week-end. Next is the command pad which will give you a chance to drive the sound driven robot!

 

                           
Forward
                           
Left
Stop
Right
                           
Backward
                           

Meet us at the Gamer Assembly

HL2 group is now the team behind Arduinoos. We are very much involved in the development of local and national initiatives in the world of open data, open software and open hardware. The team co-funded QuaiLab a very active FabLab which has been selected for managing a Maker Assembly aside the now famous Gamer Assy.

ga2015-logo

So, you are mostly invited to …

meet_us_gamer_assy_m

… at the Gamer Assy.

This amazing small robot has been extrapolated from an idea raised at QuaiLab, featuring an Arduino UNO, PlainDSP, a pair or servo-motors, a printed frame, two o’rings and a bunch of screws! The robot is driven by tones generated by a cell phone, or by instructions from Arduino IDE console and it can record and replay the recorded path. A detailed description of this project will come soon after the show.

 

 

Tips and tricks (Part 23)

Previous T&T

Although the situation is not very common, you may face like me the following situation: I needed to read analog signals applied to some of the 6 ports from an Arduino UNO. But some of the readings would use the Vcc reference (so as to say the analogReference(DEFAULT))  and some others would use the 1.1 V internal reference (so as to say the analogReference(INTERNAL)).

Jumping from one reference to another is not without risks of getting very confusing analog measurements. Arduino reference manual says:

After changing the analog reference, the first few readings from analogRead() may not be accurate.

Good point, however how much is “few”? If you drop an eye on the ATMEGA 328 Datasheet, you may read that: “the user must allow the (internal) reference to start up before the output is used…. … Refer to ”Internal Voltage Reference” on page 51 for details on the start-up time.”

So far so good. And well, I decided that I would do something special to make 100% sure that my readings are correct, whatever the operating conditions. The best way to do that would be to use a reference voltage, attach its output to a dedicated analog port and perform measurements as long as the gap between to consecutive measurement is not null. Although this option is bulletproof, it is expensive in terms of addtional components and commissioning of analog ports.

After some more reading in the ATMEGA data sheet, one can read at the MUX section that 6 among the the 14 theoretical ports are used by arduino, one (actually port 8) allows access to the chip temperature (the famous hidden thermometer) and another one (port 14) reads the internal 1.1 V! Hurray! We have a built in reference!

mux

Here is is the function that I wrote to perform the analog to digital startup. The comments in the code should suffice to explain the way it works.

void InitAdc(uint8_t ref)
{
	ADMUX = 0x00; /* Clear register */
	analogReference(ref); /* Set reference */
	analogRead(0); /* Read any channel once in order to set parameters */
	ADMUX |= 0x0E; /* Set channel 14 so as to say 1.1 V ref */
	const uint8_t ADSCmask = (1 << ADSC); /* Compute mask once to save time */
	/* Set comparison parameters */
	const uint8_t maxReadings = 100;
	const uint8_t maxDelta = 4;
	/* Local variables */
	uint8_t readings = 0; /* Readings prevent infinite looping */
	uint16_t lastReading = 0;
	uint16_t reading = 0;
	do {
		delay(1);
		readings += 1; /* Record readings */
		lastReading = reading; /* Record last reading */
		ADCSRA |= (ADSCmask | (1 << ADEN)); /* Start single conversion */
		while((ADCSRA & ADSCmask) == ADSCmask); /* Wait for conversion to complete */
		reading = (ADCL | (ADCH << 8)); /* Compute resulting adc counts */
	} while ((abs(reading - lastReading) > maxDelta) && (readings < maxReadings));		
}

HTH

 

 

Tips and Tricks (Part 22)

Previous Tip & Trick

Here is an update of the Electronics Pinout Sheets originally issued by Arduinoos and now edited by PlainDSP (same team behind the screen!)

elec_pinout_v4

HTH

Next Tip & Trick