User avatar
Bigcat123
Posts: 230
Joined: Thu Aug 23, 2012 2:41 pm

Electronic Speed Controller - Needs Servo Signal - help!

Sun Sep 18, 2016 1:02 pm

Hi folks,

So I have an ESC (electronic speed controller) that is hooked up to a big lipo and a nice brushless motor. The instructions that came with the ESC and motor are horrendously vague. Anyway I know that it requires a servo signal to control it and the general rule is that an ESC wants the following:

1) 50Hz PWM servo input signal...
2) ... that can vary its pulse width from 1ms to 2ms. (1ms = motor off, 2ms = motor fully on, 1.5ms = half power)

Now I am trying to do this in Python and really really struggling. I can't seem to find any piece of software that will allow me to just put in those details. ie: pulse PWM at 1ms. Can anyone provide any help? I was using the PWM pin 18, but also have an Adafruit 12 bit servo controller just in case.

Any help would be really appreciated!
Just a beginner sharing his experiences on his way to geek nirvana...

User avatar
Laurens-wuyts
Posts: 716
Joined: Wed Aug 21, 2013 7:35 pm
Location: Belgium
Contact: Website

Re: Electronic Speed Controller - Needs Servo Signal - help!

Sun Sep 18, 2016 1:06 pm

Have a look at joan's pigpio.
It can create servo signals.

Laurens

BMS Doug
Posts: 3824
Joined: Thu Mar 27, 2014 2:42 pm
Location: London, UK

Re: Electronic Speed Controller - Needs Servo Signal - help!

Sun Sep 18, 2016 1:55 pm

Laurens-wuyts wrote:Have a look at joan's pigpio.
It can create servo signals.

Laurens
Agreed, pigpio is excellent, run the pigpio demon and then call it from python.
Doug.
Building Management Systems Engineer.

User avatar
Bigcat123
Posts: 230
Joined: Thu Aug 23, 2012 2:41 pm

Re: Electronic Speed Controller - Needs Servo Signal - help!

Sun Sep 18, 2016 2:02 pm

I had never come across it before - but now looking at it! Looks fantastic and just what I need. In particular, I am studying from the demo code that Joan has provided for the Adafruit 12 channel servo driver I have - it has a killer set_pulse_width function. Just trying to run it, but having some issues with the following error. I have also installed Adafruit_PCA9685, so I guess I have the correct library?

Any ideas?

Error

Code: Select all

Traceback (most recent call last):
  File "other_trial.py", line 110, in <module>
    pwm = PCA9685.PWM(pi) # defaults to bus 1, address 0x40
AttributeError: 'module' object has no attribute 'PWM'
Actual Python Code (Joan's)

Code: Select all

#!/usr/bin/env python

# PCA9685.py
# 2016-01-31
# Public Domain

import time

import pigpio

class PWM:

   """
   This class provides an interface to the I2C PCA9685 PWM chip.

   The chip provides 16 PWM channels.

   All channels use the same frequency which may be set in the
   range 24 to 1526 Hz.

   If used to drive servos the frequency should normally be set
   in the range 50 to 60 Hz.

   The duty cycle for each channel may be independently set
   between 0 and 100%.

   It is also possible to specify the desired pulse width in
   microseconds rather than the duty cycle.  This may be more
   convenient when the chip is used to drive servos.

   The chip has 12 bit resolution, i.e. there are 4096 steps
   between off and full on.
   """

   _MODE1         = 0x00
   _MODE2         = 0x01
   _SUBADR1       = 0x02
   _SUBADR2       = 0x03
   _SUBADR3       = 0x04
   _PRESCALE      = 0xFE
   _LED0_ON_L     = 0x06
   _LED0_ON_H     = 0x07
   _LED0_OFF_L    = 0x08
   _LED0_OFF_H    = 0x09
   _ALL_LED_ON_L  = 0xFA
   _ALL_LED_ON_H  = 0xFB
   _ALL_LED_OFF_L = 0xFC
   _ALL_LED_OFF_H = 0xFD

   _RESTART = 1<<7
   _AI      = 1<<5
   _SLEEP   = 1<<4
   _ALLCALL = 1<<0

   _OCH    = 1<<3
   _OUTDRV = 1<<2

   def __init__(self, pi, bus=1, address=0x40):

      self.pi = pi
      self.bus = bus
      self.address = address

      self.h = pi.i2c_open(bus, address)

      self._write_reg(self._MODE1, self._AI | self._ALLCALL)
      self._write_reg(self._MODE2, self._OCH | self._OUTDRV)

      time.sleep(0.0005)

      mode = self._read_reg(self._MODE1)
      self._write_reg(self._MODE1, mode & ~self._SLEEP)

      time.sleep(0.0005)

      self.set_duty_cycle(-1, 0)
      self.set_frequency(200)

   def get_frequency(self):

      "Returns the PWM frequency."

      return self._frequency

   def set_frequency(self, frequency):

      "Sets the PWM frequency."

      prescale = int(round(25000000.0 / (4096.0 * frequency)) - 1)

      if prescale < 3:
         prescale = 3
      elif prescale > 255:
         prescale = 255

      mode = self._read_reg(self._MODE1);
      self._write_reg(self._MODE1, (mode & ~self._SLEEP) | self._SLEEP)
      self._write_reg(self._PRESCALE, prescale)
      self._write_reg(self._MODE1, mode)

      time.sleep(0.0005)

      self._write_reg(self._MODE1, mode | self._RESTART)

      self._frequency = (25000000.0 / 4096.0) / (prescale + 1)
      self._pulse_width = (1000000.0 / self._frequency)

   def set_duty_cycle(self, channel, percent):

      "Sets the duty cycle for a channel.  Use -1 for all channels."

      steps = int(round(percent * (4096.0 / 100.0)))

      if steps < 0:
         on = 0
         off = 4096
      elif steps > 4095:
         on = 4096
         off = 0
      else:
         on = 0
         off = steps

      if (channel >= 0) and (channel <= 15):
         self.pi.i2c_write_i2c_block_data(self.h, self._LED0_ON_L+4*channel,
            [on & 0xFF, on >> 8, off & 0xFF, off >> 8])

      else:
         self.pi.i2c_write_i2c_block_data(self.h, self._ALL_LED_ON_L,
            [on & 0xFF, on >> 8, off & 0xFF, off >> 8])

   def set_pulse_width(self, channel, width):

      "Sets the pulse width for a channel.  Use -1 for all channels."

      self.set_duty_cycle(channel, (float(width) / self._pulse_width) * 100.0)

   def cancel(self):

      "Switches all PWM channels off and releases resources."

      self.set_duty_cycle(-1, 0)
      self.pi.i2c_close(self.h)

   def _write_reg(self, reg, byte):
      self.pi.i2c_write_byte_data(self.h, reg, byte)

   def _read_reg(self, reg):
      return self.pi.i2c_read_byte_data(self.h, reg)

if __name__ == "__main__":

   import time

   import PCA9685
   import pigpio

   pi = pigpio.pi()

   if not pi.connected:
      exit(0)

   pwm = PCA9685.PWM(pi) # defaults to bus 1, address 0x40

   pwm.set_frequency(50) # suitable for servos

   for dc in range(5, 11):
       pwm.set_duty_cycle(-1, dc) # -1 for all channels
       time.sleep(1)

   for pw in range(1000, 2050, 50):
       pwm.set_pulse_width(-1, pw) # -1 for all channels
       time.sleep(1)

   pwm.cancel()

   pi.stop()
Just a beginner sharing his experiences on his way to geek nirvana...

User avatar
joan
Posts: 14179
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Electronic Speed Controller - Needs Servo Signal - help!

Sun Sep 18, 2016 2:53 pm

The file PCA9685.py must be on the Python path. It's simplest if you have the file in your local directory.

Could you show the result of "ls * -l" in your local directory?

The Python file is a replacement for the Adafruit PCA9685 library.

Return to “Automation, sensing and robotics”