Close

Motor control: The timer interrupt driver

A project log for Building the Thor robot

Building a 6-axis robot based on the Thor robot. When size DOES matter!

Olaf BaeyensOlaf Baeyens 05/16/2017 at 20:200 Comments

The code developed for Thor is intended to make the robot move like a ballet dancer. I am not controlling 1 or 2 motors but SEVEN at a time and they must all move like ballet dancers because we are moving real big masses that has inertia. Or worse, has maybe fluids.

In order to have perfect control over acceleration and deceleration we need a predictable timing that is independent of anything else I do to calculate the next steps or check for user input.

The whole purpose of the robot is to move! All else is secondary except for an emergency button. ON top of that primary focus is the mass it has to transport. That mass is more massive than a standard top of a 3D printer. The motor execution workflow must take that into account.

The code to generate a timer interrupt on an Arduino Due (used by the Ultratronics v1.0 motherboard) was harder to find. It is different than an Arduino Uno/Mega.

The code below is what drives the output you see at the logic analyzer at 32767 Hz.

#define timerFrequency 32767

// Black magic
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
	pmc_set_writeprotect(false);
	pmc_enable_periph_clk((uint32_t)irq);
	TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
	uint32_t rc = VARIANT_MCK / 128 / frequency; //128 because we selected TIMER_CLOCK4 above
	TC_SetRA(tc, channel, rc / 2); //50% high, 50% low
	TC_SetRC(tc, channel, rc);
	TC_Start(tc, channel);
	tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPCS;
	tc->TC_CHANNEL[channel].TC_IDR = ~TC_IER_CPCS;
	NVIC_EnableIRQ(irq);
}

// This function is called every 1/40 sec.
void TC3_Handler() {
	// You must do TC_GetStatus to "accept" interrupt
	// As parameters use the first two parameters used in startTimer (TC1, 0 in this case)
	TC_GetStatus(TC1, 0);

	motorProcessor->ExecuteStep();
}

void setup() {
	// Start timer. Parameters are:

	// TC1 : timer counter. Can be TC0, TC1 or TC2
	// 0   : channel. Can be 0, 1 or 2
	// TC3_IRQn: irq number. See table.
	// 40  : frequency (in Hz)
	// The interrupt service routine is TC3_Handler. See table.

	startTimer(TC1, 0, TC3_IRQn, timerFrequency);
}

I have not figured out yet how to proceed from here,. Many ideas.

It is easy to say that I want to move the 7 motors as a ballet dancers, if your driving engine is a huge PC with tons of memory and 4 Ghz CPU. The challenge is to contain it to have as much possibilities cramped into a small memory space.

That is what made me decide to start with Thor,. It challenges me to do stuff that everyone else claim that it cannot be done. :-)


I already have some ideas:

Discussions