Go Down

Topic: 12 Bit Servo Resolution, frequency of 250-333Hz (Read 3472 times) previous topic - next topic

ssingh

For my project, I need extremely high servo resolution.  The servos I am working with have 12-bit resolution, and work with a frequency of 250-333Hz (http://www.savoxusa.com/Savox_SB2271SG_Digital_Servo_p/savsb2271sg.htm).  I assume this is somehow possible to achieve on the Due, but I don't see any documentation specifically how.  Can I use the analogWrite function in 12 bit mode, with the PWM frequency scaled down to fit within the 250-333Hz range? 

ssingh

Ok...... so I found another post that explains that in arduino PWM can't be used to control servo position (http://forum.arduino.cc/index.php?topic=14146.0).  The servo library uses something which could be called PPM.  Does that mean, then, that the servo library would have to be updated to handle 12 bit resolution?


ssingh

Thanks for the reply.  I actually just ordered one of those last night after I made my post, in case I couldn't get this to work on just the Due alone. It seems that it should be possible to get this work on the Due.  For various reasons, it would be great if I could have as few components involved as possible......

ssingh

Ok..... so maybe I'm answering my own question here, please tell me if I am correct.  My servo can receive up to 333hz signal.  So say I set the PWM signal to 333Hz at 12 bit resolution.  (Though I'm not sure I can get it exactly to 333hz as it seems the clock can be only divided in certain ways).  That would give me 4096 divisions of the a single wave at 333Hz?

So one cycle is: 3ms
If center pulse width is 1.5ms, then
analogWrite value of 2,047 would properly center my servo?

"mem" from the discussion I mentioned in my previous post says that using analogWrite to control servos would destroy the servo.  But don't see why.  I want to get approval from someone more knowledgable than me before I try this out!!


SurferTim

#5
Jul 24, 2015, 02:10 pm Last Edit: Jul 24, 2015, 02:52 pm by SurferTim
I haven't tested it, nor have I looked at the datasheet for your servo, but that sounds about right.

Why would using analogWrite destroy your servo? The only way you can destroy a standard servo is if you exceed the limits of the servo. To be safe with a standard servo, that would mean no shorter than a 1000us and no longer than a 2000us pulse.

edit: That means with the Adafruit unit, the best resolution you will be able to get will be about 10 bit resolution for the actual usable pulse width. Most servo potentiometers are not capable of matching that kind of resolution anyway.

On my Due, that unit has about 8 bit resolution at 60Hz, and that is great for my applications.

I forgot to mention the Adafruit servo library for that device uses the Wire1 I2C bus on the Due. Those are the two pins labelled SDA1 and SCL1 near the reset button and usb connectors.

ssingh

Well....... My Due and Adafruit servo driver came..... and I was excited to take advantage of the 12bit resolution..... but I found the pwm.h library (listed here: http://forum.arduino.cc/index.php?topic=117425.0) offers 16bit resolution on the Uno!  So I'm back to my old Uno and getting great results!  Whoever says you can't use the standard pwm on arduino to control servos doesn't know what they are talking about.  This library has something called pwmWriteHR which allows for the 16 bit resolution.  My project is now in action and working just as I imagined it should! Very happy :)  People here on this forum need to update their concept of what a servo motor can do these days and how it can be controlled........

SurferTim

#7
Jul 29, 2015, 02:41 am Last Edit: Jul 29, 2015, 03:14 am by SurferTim
What do you need 16 bit servo resolution for? Just curious. That is accuracy to 10 seconds of arc movement.

I've been thinking about it. How do you transfer that kind of accuracy to an external device without spending a fortune for precision gearing or linkage?

edit: If the servo is 12 bit resolution, that is 3 minutes arc movement per bit change. Can you even see that small of a movement on the servo output shaft?
 

ssingh

I'm building acoustic microtonal musical instruments, and the servos are adjusting the pitch.  I have a live autotune function built in, which I just got working yesterday! So excited about it :)  So really I can't get too precise.  I'm not sure how much resolution I'm actually getting with my setup, but using the 16bit input is significantly better than the approximately 10bit standard servo library.  I have a servo arm that extends 12cm over 70degrees, so little changes become bigger at that distance......  But it seems I will have to go for an industrial grade servo of some sort because the hobby servo, even though it is brushless, still makes a bit too much noise.

SurferTim

That sounds reasonable. Any servo that has tension on it is going to probably make a little noise to hold it's position.

gabrielislost

WHAT ARE U GUYS TALKING ABOUT/ HOW DO I USE ARDUINO+ A 12BIT PWM SHEILD TO PWN A 12BIT SERVO TY

MartinL

#11
Oct 11, 2016, 07:13 pm Last Edit: Oct 21, 2016, 02:40 pm by MartinL
It's possible to get up to 15-bit resolution at 333Hz with the PWM controller on the Due.

In the code below, set the duty-cycle update register 0 (REG_PWM_CDTYUPD0) as follows:

21000 to generate a 1ms pulse: servo minimum
31500 to generate a 1.5ms pusle : servo centre
42000 to generate a 2ms pulse: servo maximum

The following code outputs 333Hz, single slope PWM at a resolution of 15-bits on pin DAC1 (PWML0):

Code: [Select]
// Output 333Hz PWM at a resolution of 15 bits on pin DAC1 (PWML0)
void setup() {
  // PWM Set-up on pin: DAC1
  REG_PMC_PCER1 |= PMC_PCER1_PID36;                     // Enable PWM
  REG_PIOB_ABSR |= PIO_ABSR_P16;                        // Set PWM pin perhipheral type A or B, in this case B
  REG_PIOB_PDR |= PIO_PDR_P16;                          // Set PWM pin to an output
  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(4);      // Set the PWM clock rate to 21MHz (84MHz/4)
  REG_PWM_CMR0 = PWM_CMR_CPRE_CLKA;                     // Enable single slope PWM and set the clock source as CLKA
  REG_PWM_CPRD0 = 63063;                                // Set the PWM frequency 21MHz/(63063) = 333Hz
  REG_PWM_CDTY0 = 31500;                                // Set the PWM pulse width to 1.5ms - centre the servo
  REG_PWM_ENA = PWM_ENA_CHID0;                          // Enable the PWM channel     
}

void loop()
{
  //REG_PWM_CDTYUPD0 = 21000;                           // Duty cycle update register - set PWM pulse width to 1.0ms - servo minimum
  //delay(1000);                                        // Wait 1 second
  //REG_PWM_CDTYUPD0 = 42000;                           // Duty cycle update register - set PWM pulse width to 2.0ms - servo maximum
  //delay(1000);                                        // Wait 1 second
}

Although the PWM controller can be clocked at up to 84MHz, it's limited by its 16-bit counter registers.

Interestingly, the TC timer counter peripherals can only be clocked at up to 42MHz, but as their registers are 32-bits it would be possible to get 16-bits of resolution in total.

However, the PWM controller automatically updates the duty-cycle at the beginning of each cycle, to prevent gliches on your outputs. The TC peripherals don't have this functionality, so you'd have to use interrupts to load the duty-cycle (compare) register at the beginning of each cycle.

gabrielislost

i dont understand, can you be more pleasant to the noob here?: me,
i only want to use a 12bit servo motor ty

MartinL

#13
Oct 12, 2016, 09:46 am Last Edit: Oct 12, 2016, 12:25 pm by MartinL
Hi gabrielislost,

Are you looking to drive a more standard analogue servo at 50Hz?

The code below sets-up an analogue servo at 50Hz with 14-bit resolution, (it really doesn't matter if it's more than 12-bits), on the DAC1 pin. Conveniently, like the servo library writeMicroseconds() function, you just have to load the duty-cycle update register (REG_PWM_CDTYUPD0) with the pulsewidth in microseconds. So 1500 = servo centred, 1000 = servo minimum and 2000 = servo maximum.

Code: [Select]
// Output 50Hz PWM at a resolution of 14 bits on pin DAC1 (PWML0)
void setup() {
  // PWM Set-up on pin: DAC1
  REG_PMC_PCER1 |= PMC_PCER1_PID36;                     // Enable PWM
  REG_PIOB_ABSR |= PIO_ABSR_P16;                        // Set PWM pin perhipheral type A or B, in this case B
  REG_PIOB_PDR |= PIO_PDR_P16;                          // Set PWM pin to an output
  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42);     // Set the PWM clock rate to 2MHz (84MHz/42)
  REG_PWM_CMR0 = PWM_CMR_CALG | PWM_CMR_CPRE_CLKA;      // Enable dual slope PWM and set the clock source as CLKA
  REG_PWM_CPRD0 = 20000;                                // Set the PWM frequency 2MHz/(2 * 20000) = 50Hz
  REG_PWM_CDTY0 = 1500;                                 // Set the PWM duty cycle to 1500 - centre the servo
  REG_PWM_ENA = PWM_ENA_CHID0;                          // Enable the PWM channel     
}

void loop() {
  REG_PWM_CDTYUPD0 = 1000;                            // Duty cycle update register - set PWM pulse width to 1.0ms - servo minimum
  delay(1000);                                        // Wait 1 second
  REG_PWM_CDTYUPD0 = 1500;                            // Duty cycle update register - set PWM pulse width to 1.5ms - servo centre
  delay(1000);                                        // Wait 1 second
  REG_PWM_CDTYUPD0 = 2000;                            // Duty cycle update register - set PWM pulse width to 2.0ms - servo maximum
  delay(1000);                                        // Wait 1 second 
}

This code moves the servo between minimum, centre and maximum positions.

So for example to centre the servo you just need to insert the following line into your code:

Code: [Select]
REG_PWM_CDTYUPD0 = 1500;                            // Duty cycle update register - set PWM pulse width to 1.5ms - servo centre
The Due's hardware will do the rest of the work for you.

Alternatively, the forum member antodom has produced both PWM and TC libraries: https://github.com/antodom.

Go Up