Digispark as multiple servo driver.

Arduino projects on the go
MaxZ
Posts: 124
Joined: 31 Jan 2019, 11:48
Location: Boskoop, Netherlands

Re: Digispark as multiple servo driver.

Post by MaxZ » 10 Jul 2019, 08:44

I simplified the code somewhat (wiping out my error :oops: ;) ) and I have clocked the Digispark now at 16MHz. As predicted by Phil, the jitter is reduced:
Schermafbeelding 2019-07-10 om 09.31.24.png
Then I tried the direct port access, which gives about the same amount of jitter, but for some reason is slightly further off the 1.5 ms mark (1487-1495 vs 1491-1497). Nothing to worry about though :
Schermafbeelding 2019-07-10 om 09.31.39.png
Cheers,
Max.

MaxZ
Posts: 124
Joined: 31 Jan 2019, 11:48
Location: Boskoop, Netherlands

Re: Digispark as multiple servo driver.

Post by MaxZ » 10 Jul 2019, 15:42

Phil_G wrote:
10 Jul 2019, 14:55
Just as an experiment, put noInterrupts(); at the start
I think your jitters will disappear ;)

Error at compiling for ATtiny25/45/85

I also experimented with replacing the delays with a counter based on Micros(), but the jittering is still there :(

Cheers,
Max.

MaxZ
Posts: 124
Joined: 31 Jan 2019, 11:48
Location: Boskoop, Netherlands

Re: Digispark as multiple servo driver.

Post by MaxZ » 10 Jul 2019, 17:32

In file included from /Users/maxzuijdendorp/Library/Arduino15/packages/arduino/hardware/avr/1.6.23/cores/arduino/Arduino.h:30:0,
from sketch/Pulsetest.ino.cpp:1:
Pulsetest:1:1: error: expected ')' before '::' token
cli();
^
exit status 1
expected ')' before '::' token

MaxZ
Posts: 124
Joined: 31 Jan 2019, 11:48
Location: Boskoop, Netherlands

Re: Digispark as multiple servo driver.

Post by MaxZ » 10 Jul 2019, 21:01

Phil_G wrote:
10 Jul 2019, 20:11
Both noInterrupts() and cli() compile fine for me ?????
You're putting it in setup() Max?
No I did not apparently, but when I do put it in setup it indeed compiles without errors. But the result is not good, the pulse analyser hangs in the opening screen.

However, this seems to work well, producing a rock steady pulse length, albeit some 10% shorter than expected:
Schermafbeelding 2019-07-10 om 21.56.46.png
I am not sure what will happen when the micros() counter overflows.

Cheers,
Max.

User avatar
Phil_G
Posts: 267
Joined: 15 Feb 2018, 23:32
Contact:

Re: Digispark as multiple servo driver.

Post by Phil_G » 10 Jul 2019, 21:38

You keep moving the goalposts Max :D , I thought we were talking about your simple 1500uS generator example?
I would expect this latest iteration to chatter, if (currMicros-prevMicros >= pulselen) is a lengthy statement with lots of processing of longs within the pulse itself (32-bit arithmetic on an 8-bit processor takes a relatively long time to do). I'd suggest doing all the calculations first, rather than within the pulse.
MaxZ wrote:
10 Jul 2019, 21:01
... the pulse analyser hangs in the opening screen.
again, with "try cli()" I was referring to the simple 1500uS example you posted, sorry

MaxZ
Posts: 124
Joined: 31 Jan 2019, 11:48
Location: Boskoop, Netherlands

Re: Digispark as multiple servo driver.

Post by MaxZ » 10 Jul 2019, 21:51

We are talking about the 1500 us generator, but that is how I check the output, with the pulse analyser that you designed Phil. And I did try noInterrupts() and cli() with the sketch based on delayMicroseconds() and delay().

But there is no harm in investigating other routes, is there?

Cheers,
Max.

Martin
Posts: 272
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: Digispark as multiple servo driver.

Post by Martin » 10 Jul 2019, 22:28

You'll get the greatest accuracy by using timer interrupts yourself. The timers can be set to work some pins directly, but for other pins they can be set to call your own interrupt routine which then switches the pin immediately and then reconfigures the timer ready for the next interrupt.

It's more complicated, of course, and as the AtTiny micro timers can only count up to 256, you need to keep track of how many complete cycles are necessary, and then what's left over for the final count. It's further complicated by not being able to set a very small target count, because the timer will have counted past that before you finish setting it up - so if there are 266 counts remaining, rather than set the timer for 256 and then 10, you have to set it for, say, two counts of 133.

Best place to start, if you're interested, is to carefully read the Timer sections of the data sheet for the chip (which can be freely downloaded). People like Phil get their expertise by reading those data sheets over and over again, and then spending many many hours experimenting. It's not for everyone! :? :lol:

User avatar
Phil_G
Posts: 267
Joined: 15 Feb 2018, 23:32
Contact:

Re: Digispark as multiple servo driver.

Post by Phil_G » 15 Jul 2019, 22:50

MaxZ wrote:
07 Jul 2019, 11:13
Now that I have set up the Digispark programming, I started thinking of uses for it. I would like to experiment with onboard sequencers or mixers...
I did a very simple V-tail mixer Max, you could start with that:

Code: Select all

// 50:50 Vtail mixer for ATTiny85 such as the 16mhz DigiSpark board - Phil_G
#define Rxch1 0 // receiver channel connected to P0 (ATTiny physical pin 5) Set PCMSK to match
#define Rxch2 3 // receiver channel connected to P3 (ATTiny physical pin 2)
#define servo1 4    // servo 1 ATTiny physical pin 3
#define servo2 2    // servo 2 ATTiny physical pin 7
#define led 1       // DigiSpark internal LED on P1 (ATTiny physical pin 6)
volatile unsigned long timer_ch1, timer_ch2; // all timer variables are unsigned long
volatile int pulse_time1 = 1500, pulse_time2 = 1500, outpulse_time1 = 1500, outpulse_time2 = 1500, temp;
volatile byte ch1Was = 0, ch2Was = 0, sync = 0;

void setup()
{
  pinMode(led, OUTPUT);
  pinMode(servo1, OUTPUT);
  pinMode(servo2, OUTPUT);
  pinMode(Rxch1, INPUT);
  pinMode(Rxch2, INPUT);
  timer_ch1 = 0; timer_ch2 = 0;
  GIMSK = (1 << PCIE);   // Enable Pin Change Interrupts
  PCMSK = (1 << Rxch1) | (1 << Rxch2); // Enable interrupts for rx channel inputs
  sei();
}

void loop()
{
  while (sync == 0);
  sync = 0;
  delay(6);  // do the o/p pulses mid-frame, reduces jitter...
  cli();
  outpulse_time1 = pulse_time1; // do an atomic copy in the quickest way
  outpulse_time2 = pulse_time2;
  sei();
  outpulse_time1 /= 2; // then do arithmetic on the copies...
  outpulse_time2 /= 2;
  temp = outpulse_time2;
  outpulse_time2 = outpulse_time1 + 1500 - outpulse_time2;
  outpulse_time1 += temp;
  constrain(outpulse_time1, 850, 2150);
  constrain(outpulse_time2, 850, 2150);
  digitalWrite(servo1, 1); delayMicroseconds(outpulse_time1); digitalWrite(servo1, 0); // servo out on P4 sum
  digitalWrite(servo2, 1); delayMicroseconds(outpulse_time2); digitalWrite(servo2, 0); // servo out on P2 difference
}

ISR(PCINT0_vect)
{
  if (PINB & 0b00000001) { // Rx ch 1
    if (ch1Was == 0) {
      timer_ch1 = micros();
      ch1Was = 1;
    }
  } else {
    if (ch1Was == 1) {
      pulse_time1 = ((volatile int)micros() - timer_ch1);
      ch1Was = 0;
      sync = 1;
    }
  }
  if (PINB & 0b00001000) {  // Rx ch 2
    if (ch2Was == 0) {
      timer_ch2 = micros();
      ch2Was = 1;
    }
  } else {
    if (ch2Was == 1) {
      pulse_time2 = ((volatile int)micros() - timer_ch2);
      ch2Was = 0;
    }
  }
}


Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests