3D prints: USB housing

I had this cheap USB stick that I had to take apart in order to rework the connector soldering. Once the soldering works achieved, I had to think about a quick and dirty enclosure which resulted in this:

Two – almost – symmetrical parts. The top one has a bump and a small hole aligned with the LED, the bottom one has a carving which holds the PCB in place.

And here is the result

Link to the stl files

Back to main topic

3D prints: Coil

I have multiple projects in mind starting from a metal detector up to a NMR in field earth spectrometer which require one or more coils in various shapes and sizes. Here is the presentation of a double coil, 100 mm diameter, 5 mm thickness.

Here is a zoom on the back side of the coil showing the wire terminals. I used a adjustable female header

This is how it looks once wired to the driver

Next is the 3D view from FreeCad

And here is the link to the stl file

Back to main topic

Blog of the day

While tumbling on the web for something totally different, I found this very interesting post on SERVOMOTORS, STEPPER MOTORS AND ACTUATORS FOR MOTION.

Although, the illustrations are dated, I like very much the detailed, accurate and almost exhaustive description of magnetic actuators.

3D Printing (Part 11)

Part 123456789101112

3D printing is awesome. I am even wondering how I could live without it. I mean, in my professional, domestic and makers life. Before 3D print, I would have used wood, metallic wires, sheets of PVC or even cardboard to build parts in the quick and dirty mode. Just before 3D printing, I was also fan of the FIMO clay which is very convenient, comes in various colors, proved to be pretty strong after being baked for half an hour in a standard kitchen oven. However, the look and feel of the results looked very, very amateur… perfect for the artist, childish for the pro.

What did I print lately? This post shall link to my latest 3D works…


USB housing

Stevenson screen

Coming soon…

Stepper Motors (Part 9)

Part 12, 3, 4, 5, 6, 7, 8, 9

Let’s go back with an easier application. Still for my friend Valerio, the puppets magician, who built this adorable model-phonograph:

It is all wooden made and powered by… a stepper motor, using the electronics which has been described in previous post and showed again here

A switch is attached to the needle’s arm

The code had to match the following expectations:

  • The turn table should slowly start when the needle leaves its rest position
  • The turn table should reach its nominal speed and stay there has long as the needle is above  the record.
  • When the needle goes back to the rest position, then the turn table should slowly slowdown, down to a minimal speed and  then stop.
  • The turn table should re-accelerate if the needle goes to the rest position and back on top of “record”.

Here is the result of our long lasting fab-lab session…

Basic stepper motor driver
Used in the context of Valerio's magic phono
- At rest, the swicth is released the motor is stopped
- When the switch is activated, the motor starts and constantly gains speed up 
  to its nominal speed
- If the siwtch is released, whatever the speed of the motor, the motor is 
  slow down and stops
- If the switch is actived again while the motor has not stopped, the motor is 
  accelerated again up to its nominal speed
  Didier Longueville 2017

/* User defined variables */
/* Pins configuration */
const uint8_t _pinDir = 2;
const uint8_t _pinStep = 4;
const uint8_t _pinSwitch = 8;
/* Timing constants */
int16_t _pulsesWidthStop = 7000;
int16_t _pulsesWidthStart = 5000;
int16_t _pulsesWidthMaxSpeed = 2000;
uint8_t _pulsesIncrements = 3;
uint8_t _pulsesDecrements = 3;

/* Application variables */
/* Timing variables */
uint32_t _now;
uint32_t _lastTime;
/* motor state */
const uint8_t STOPPED = 0;
const uint8_t UNSTABLE = 1;
const uint8_t STABLE = 2;
uint8_t _motorState = STOPPED; 
/* switch state */
const uint8_t REST = LOW;
const uint8_t PLAY = HIGH;
uint8_t _switchState; 
/* Step pulses */
int16_t _pulsesInterval;

void setup(void)
	/* Configure pins */
	/* Direction */
	pinMode(_pinDir, OUTPUT);
	digitalWrite(_pinDir, LOW);
	/* Step */
	pinMode(_pinStep, OUTPUT);
	digitalWrite(_pinStep, LOW);
	/* Switch */
	pinMode(_pinSwitch, INPUT_PULLUP);

void loop(void)
	do {
		/* read switch state */
		_switchState = digitalRead(_pinSwitch);
		/* record now */
		_now = micros();
	} while ((_now - _lastTime) < _pulsesInterval);
	_lastTime = _now;
	/* Interpret switch state according to motor state */
	if (_switchState == REST) {
		if (_motorState != STOPPED) {
			/* Slow down motor speed by increasing intervals between pulses */
			_pulsesInterval += _pulsesIncrements;
			/* Force motor state */
			motorState = UNSTABLE;
			if (_pulsesInterval > _pulsesWidthStop) {
				/* motor has reached its minimal speed before stopping */
				_motorState = STOPPED;
	} else if (_switchState == PLAY) {
		if (_motorState == STOPPED) {
			/* Set default pulse width for motor start */
			_pulsesInterval = _pulsesWidthStart;
			/* Set motor state */
			_motorState = UNSTABLE;
		} else if (_motorState != STABLE) {
			/* Speed up motor by decreasing intervals between pulses */
			_pulsesInterval -= _pulsesDecrements;
			if (_pulsesInterval < _pulsesWidthMaxSpeed) {
				// Motor has reached its stationary speed
				_motorState = STABLE;
				_pulsesInterval = _pulsesWidthMaxSpeed;
	/* Send pulse */
	if (_motorState != STOPPED)	{
		/* generate positive pulse for at least 1 us */
		digitalWrite(_pinStep, HIGH);
		digitalWrite(_pinStep, LOW);		

For a change, it features standard pin control functions and standard timers for bit-bang control of pulses.

Are you interested in Valerio’s performances ? Here are his contact information:

Mue – Valerio Point
Association Mue Marionnettes
Mairie – 86600 Celle l’Evescault
+33 6 20 39 23 11


To blog or not to blog ?

Blogs are wonderful tools that are very convenient for sharing all sorts of information without the burden of writing code an spending time on site maintenance (Unless you want to fine tune your style, add fancy animations or perform advanced functions). This is an almost trivial statement for those who started publishing on the net a few years ago, but believe me, in the early 90’s, running a web site was not as easy as it is now. Starting from the installation an Internet connection which would require a bunch of ten 3.5″ floppy disks. In these years I was committed to invest this emerging media by my boss and I spent some time investigating the technical means as well as the way information could be shared.

Thanks to a pretty efficient telephone networks, the French PTT (Post Telegraph and Telephon administration) developed the Minitel, an innovative network of data terminals.


In the very beginning, the Minitel was mainly used for its Yellow Pages application. Soon followed by commercial applications and inevitably by X rated applications which turned the Minitel to the “Pink Minitel”. Internet emerged approximately at the same time and I seriously wondered whether or not Internet would soon or later turn to a “Pink Internet”. Would Internet be a good place for advertising serious business ? Would web sites be a convenient tool for sharing information ? I managed to meet a local pioneer in the Internet world and we had a long and very interesting talk. In the end, Sébastien Canevet told me “Well, Internet will look like what people will feed it with. The more the bul…it, the worst the Internet’s content. The better the content, the coolest the result”.

As a result of this clear statement, I built my first web site for my company as well as my first private web site. I do not pretend that what I published was top of best, a worldwide reference for the next four generations of webmasters, nope, just plain information, honest, usable and understandable by most. I did not deviate that much from my original vision on web sites and I hope that arduinoos reflects this claim. From the statistics that are recorded from some web sites that I run, this policy seems to be fair, well accepted and even popular. That’s good news for those who would like to start their own blog or web site. Here are a few guide lines that I may recommend to follow:

  • Choose an explicit name for this site and check the availability of the corresponding domain.
  • Register your domain and get your own storage area. Free space has never be so free !
  • Create a specific eMail addresses linked to the domain.
  • Create the structure of your blog: WordPress proves to be a fine one.
  • Create a visual signature: logo, banner, font, colors.
  • Create a contact page; you may also create a “who am I” page.
  • Create the first few posts. Each of these pages shall contain an explicit title, text, some illustrations (do not forget to give credit whenever applicable); use hyperlinks to create cross-referencing and add credibility.
  • Post publications periodically: every week, twice a month, monthly it is up to you. It is a good idea to keep a few posts on the back burner to achieve this goal.
  • Always approve comments from visitors. Use an authentication tool (so as to say a captcha) in order to prevent spam.
  • Using a counter and statistics plugin will help you to understand who is paying attention to your publications and what the like to see and read. These statistics will help you in focusing on specific matters or visitors.

And now a few words about the content. Write what you like, what you are (almost) sure about, what may be of some interest to others. Keep in mind that every day, every hour someone in the world is using Internet for the first time. I am almost sure that every hour, someone is told about arduino and is currently seeking for information on the net. This person is not looking for advanced information (he will shortly though!). All (s)he needs is a starting point which is usable, credible and fun. Achieving this goal requires more communication skills than technical background. Then you may decide to go for something more specialized, based on your qualification, experience or expertise. In this way your blog may gain reputation because of its artistic content, its technical content, its innovative applications, its informative content, …. the list is not exhaustive.

I also have a strong concern for publishing or not papers on how to… build a detonator, a weapon, … , all these sorts of things that would please the villains so much. In the end, it is good to feel that most clever girls and boys are good girls and good boys. Other wise, we could not live this world.

 So, get ready for new adventures, feel free to start your own communication spot and feed the internet with constructive matter.

Undocumented commands and functions

Long time ago as I was learning about George Boole  algebra I immediately though about using a (hidden) sequence of button presses to lock and unlock safes, doors, etc.  In addition to setting arbitrary sequences of button presses, I had the idea of taking into account the time spent on pressing each button which would have greatly improved the safety of the device. As I had so little to hide away from the villains eyes, my motivation faded away and so did the project for the unlimited door lock.

Although this approach looked very trivial, it is still a very valid approach to hiding specific functions or commands from ordinary users, vulgum pecus so as to say. As I was struggling with my ol’brave HP3050 printer (HP3050A  J611 Series to be precise), I tumbled on the web and found that undocumented functions were hidden and only available through a sequence of keystrokes (actually X sign , return sign, X sign twice and you’re done), just the good’ol way !

And that’s definitely the way I would approach the setting of parameters for any embedded system. To the cost of few pins and a bunch of bytes of code.

Stepper Motors (Part 8)

Part 12, 3, 4, 5, 6, 7, 8, 9

This post is about driving multiple stepper motors continuously sweeping various ranges of steps at various speeds. Each motor features a permanent sinusoidal motion (accelerated and decelerated). The complexity of the code lies in the next requirements: Each motor has its own sweeping frequency, its own full swing range (number of steps explored on each cycle). It must be possible to introduce a phase shift between each motor, they must stay synchronized over long periods of time and ultimately you may change the settings at any time.

That was a challenge ! The most confusing part of the project lies in the need for thinking in reverse mode. In this case, we do not have fixed intervals of time so we need to define how much time must elapse between to steps. Let’s put it differently: drawing a sin curve on a spreadsheet usually requires fixed time intervals on the x axis and computed ordinates for the y axis using this sort of formula: y = sin((x * frequency  * 2 * Pi())). Computing x from y requires the use of the inverse of sin function: sin^-1 = asin (arc sine).

The code below encapsulate the Interval function which is used for computing the time after which the next step will be issued by the stepper motor driver. Note that all direction pins are wire together whatever the number of drivers, while pulse must be directed to individual drivers (as per the _vStepPins vector)

#include <math.h>

const uint8_t DIR_CW = LOW;
const uint8_t DIR_CCW = HIGH;
const float _twoPi = 6.283185307179586476925286766559;

/* User settings. See explanations below */
/* _directionPin: this is the arduino pin to which the direction pins from the stepper drivers are
attached. Numbering is as per arduino standard pin namming convention */
const uint8_t _directionPin = 8;
/* _steppers: number of stepper motors. Check next vector contents accordingly */
const uint8_t _steppers = 4;
/* _vSteps: number of steps required to explore the full swing (half the _vBnFSteps) */
const uint16_t _vSteps[_steppers] = {200, 100, 50, 25};
/* _vStepPins: these are the arduino pins to which the step pins from the stepper drivers are 
attached. Numbering is as per arduino standard pin namming convention */
const uint8_t _vStepPins[_steppers] = {9, 10, 11, 12};  
/* _vFrequency; Frequency (in Hz) of sinusoidal motion. Each step interval is computed */
const float _vFrequency[_steppers] = {0.5, 1.0, 2.0, 4.0}; 
/* _vPhaseShift: Phase shift in ms versus the absolute start time which is identical for all tepper 
motors. This value is self constrained. if f = 1 Hz, the phase shift might range from 0 to 1000 ms. 
A 500ms value corresponds to 1 x Pi (so as to say half a cycle) phase shift. */
uint16_t _vPhaseShift[_steppers] = {0, 0, 0, 0}; 
/* Do not change next vectors and variables */
uint16_t _vBnFSteps[_steppers]; /* Twice the steps */
uint16_t _vHalfSteps[_steppers];  /* Half the steps */
int16_t _vStepsCounter[_steppers]; 
uint32_t _vNextStepTime[_steppers];
uint32_t _vLoopsCounter[_steppers];
uint32_t _vStartTime[_steppers];
const uint16_t _startTimeOffset = 100; /* In milli seconds */
const uint8_t _pulseDelay = 2; /* In micro seconds */

void setup(void)
	/* Console for diag */
	/* Direction pin */
	pinMode(_directionPin, OUTPUT);
	digitalWrite(_directionPin, DIR_CW); /* Set default direction */
	/* Step pins */
	for (uint8_t i = 0; i < _steppers; i++) {
		pinMode(_vStepPins[i], OUTPUT); /* Set direction */
		digitalWrite(_vStepPins[i], LOW); /* Set default state */
	uint32_t now = millis();
	for (uint8_t i = 0; i < _steppers; i++) {
		_vBnFSteps[i] = (_vSteps[i] << 1); /* Precalculate data */
		_vHalfSteps[i] = (_vSteps[i] >> 1); /* Precalculate data */
		_vStepsCounter[i] = 0; /* Reset steps counter */
		_vPhaseShift[i] %= uint16_t(1000.0 / _vFrequency[i]); /* Constrain phase shift */
		_vStartTime[i] = (now + _vPhaseShift[i]); /* Compute start time */
		_vStartTime[i] +=_startTimeOffset;
		_vNextStepTime[i] = (_vStartTime[i] + Interval(i)); /* Set next step time */
		_vLoopsCounter[i] = 0; /* Reset loop counter */

void loop(void)
	uint32_t now = millis();
	for (int8_t i = 0; i < _steppers; i++) {
		if (now > _vNextStepTime[i]) {
			/* Set direction */
			int8_t dir;
			if (_vStepsCounter[i] < _vSteps[i]) {
				dir = DIR_CW;
			} else {
				dir = DIR_CCW;
			digitalWrite(_directionPin, dir);
			/* Generate pulse */
			digitalWrite(_vStepPins[i], HIGH);
			delayMicroseconds(_pulseDelay); /* Minimal pulse delay */
			digitalWrite(_vStepPins[i], LOW);
			/* Increment step and constrain computed step value */
			_vStepsCounter[i] += 1; 
			if (_vStepsCounter[i] >= _vBnFSteps[i]) { 
				_vLoopsCounter[i] += 1; /* Increment loop counter */
				_vStepsCounter[i] = 0; /* Reset steps counter */
				_vNextStepTime[i] = (_vStartTime[i] + int32_t(_vLoopsCounter[i] * (1000.0 / _vFrequency[i])));
			} else {
				_vNextStepTime[i] = (now + Interval(i));

uint16_t Interval(uint16_t stepper)
	/* Compute next stepper time */
	int16_t i0 = ((_vStepsCounter[stepper] % _vSteps[stepper]) - _vHalfSteps[stepper]);
	int16_t i1 = (i0 + 1);
	float y0 = ((float)i0 / _vHalfSteps[stepper]);
	float y1 = ((float)i1 / _vHalfSteps[stepper]);
	int16_t result = (int16_t)(((asin(y1) - asin(y0)) * 1000.0) / (_twoPi * _vFrequency[stepper]));
	/* Returned value */

Next post on same subject

What a shame !

I recently reactivated my Facebook account in order to express my opinions during the last campaign for the election of the French Republic President. Well, I am not naive and I know by experience (I have been myself a candidate for the house of Parliament) that a campaign may be (very) trash. However, what struck me this time is how stupidity can spam the information shared by people from this “social” network. I deactivated my account right after reading and absolutely disgusting mess of slurs poured on Cedric Villani, one of the most brilliant minds of this time. How come absolute nerds write such bullshit on someone they do not really know, probably never heard and that will surely never ever read ? How come citizen can blame a scientist for his passion for spiders just because he pretends to represent the people from his place and share his vision on developing scientific culture  ?

I would not be surprise that none of these persons have the least idea about how computer protection works and how thankful they ought to be to the mathematicians who’s science is right behind our encryption algorithms. It is likely that without their help, we would all be naked in front of hackers these days.

This episode should remind us about the nasty declaration “Whenever I hear the word ‘culture’…I release the safety on my pistol!.”. How far are we from adding the word ‘science’ to the dictionary of rude men and women ?

Simple command parser (Part 2)

Part 1, 2

In the previous version, the command parser is using one single alpha character as an opcode while the argument is computed on the fly using simple arithmetic. In this version, the opcode is extended to (almost) any number of characters and the argument is stored in a vector which is then converted into integers or floats using the iota and itof functions. Please note that the use of itof leads to the same limitations than in the previous version. Also, because the opcode has no more fixed length, a separator must be used in between the opcode and the argument. The example given below makes use of either the ‘:’ character or a space character.

Next is a new set of opcodes. They are more explicit however they require more typing efforts.

const char OPC_NONE[] = "NONE";
const char OPC_BLINKS[] = "BLK";
const char OPC_ACTIVATED[] = "ACT";
const char OPC_ON_RATIO[] = "ONR";
const char OPC_PERIOD[] = "PER";
const char OPC_LST_PARAM[] = "LST";
const char OPC_RST_PARAM[] = "RST";
const char OPC_SAV_PARAM[] = "SAV";
const char OPC_ERROR[] = "ERR";

And here is parsing code

void ParseUartData(void)
	if (Serial.available() > 0) {
		/* As long as data is available from the com port */
		while (Serial.available() > 0) {
			/* Set variables to their default values */
			bool delimiterDetected = false;
			char vOpcode[8];
			uint8_t opcodeChars = 0;
			vOpcode[0] = '\0';
			char vArgument[12];
			uint8_t argumentChars = 0;
			/* While cr or nl characters are not met */
			while (true) {
				/* Read next char */
				char dataIn = Serial.read();
				/* Interpret character */
				if ((dataIn == 13) || (dataIn == 10)) {
				} else  if ((dataIn == ':') || (dataIn == ' ')) {
					/* Delimiter */
					delimiterDetected = true;
				} else if ((dataIn >= 'A') && (dataIn <= 'Z')) {
					/* Parse opcode */
					if (!delimiterDetected) {
						vOpcode[opcodeChars] = dataIn;
						opcodeChars += 1;
					} else {
						vOpcode[0] = '\0';
				} else if (((dataIn >= '0') && (dataIn <= '9')) || (dataIn == '.')) {
					/* Parse argument */
					if (delimiterDetected) {
						vArgument[argumentChars] = dataIn;
						argumentChars += 1;
					} else {
						vOpcode[0] = '\0';
				} else {
					/* Unexpected character */
					vOpcode[0] = '\0';
			/* Append termination characters */
			vArgument[argumentChars] = '\0';
			vOpcode[opcodeChars] = '\0';
			/* Convert vector */
			If the vector contains a decimal separator, only the integer part 
			of the floating point number is returned
			int32_t intArgument = atol(vArgument);
			/* The vector may not contain a decimal separator */
			float fltArgument = atof(vArgument);
			/* Parse opcodes */
			if (vOpcode[0] != '\0') {
				/* Uncomment for Debug */
				// Serial.print("opcode: ");
				// Serial.print(vOpcode);
				// Serial.print(", argument: ");
				// Serial.print(intArgument);
				// Serial.print(" (");
				// Serial.print(fltArgument, 6);
				// Serial.print(")");
				// Serial.println();	
				if (strcmp(OPC_ACTIVATED, vOpcode) == 0) {
					Serial.print("Turn led ");
					if (intArgument == 1) {
						*(_ledPort) |= _ledPinMask; 
					} else if (intArgument == 0) {
						*(_ledPort) &= ~_ledPinMask; 					
					_blinks = 0;		
				} else if (strcmp(OPC_BLINKS, vOpcode) == 0) {
					Serial.print("Blinks = ");
					_blinks = intArgument;
					/* Reset blink counter */
					_blinkCounter = 0;
				} else if (strcmp(OPC_ON_RATIO, vOpcode) == 0) {
					Serial.print("On/off ratio = ");
					Serial.println(fltArgument, 2);
					_onRatio = fltArgument;	
				} else if (strcmp(OPC_PERIOD, vOpcode) == 0) {
					Serial.print("Period = ");
					_period = intArgument;
				} else if (strcmp(OPC_LST_PARAM, vOpcode) == 0) {
				} else if (strcmp(OPC_RST_PARAM, vOpcode) == 0) {
					Serial.print("Reading parameters... ");
				} else if (strcmp(OPC_SAV_PARAM, vOpcode) == 0) {
					Serial.print("Saving parameters... ");
				} else if (strcmp(OPC_ERROR, vOpcode) == 0) {
					/* Report error */
				/* Update subsidiary variables */
				_onDuration = (_period * _onRatio);
				_offDuration = (_period - _onDuration);

You get the point now: variable length opcodes allow an almost unlimited choice of explicit commands which might be very useful in complex applications.

However, and once again, the aim of this series of post is to provide you with a simple yet powerful starting point with command parsing. Advanced application may require much more rugged transactions, including checksum or CRC (cyclic redundancy check) and data descriptors for example.