The initial pulse width is also set in ticks, so multiply the value by 2 in
your case.
Channels in your case are the 4 different ESC.
The rest of what you wrote is correct.
Just had a thought:
Why are you even bothering with the sequencer as opposed to using 4
PwmOutput? The latter has a much simpler API and is likely suitable for
your needs.
On Dec 26, 2014 2:46 AM, <[email protected]> wrote:

> Hi Ytai,
>
> Allow me to put in words how I understand the whole sequencer now, after
> reading your emails and the documentation a few more times:
>
> Here is how I believe the sequencer should be set in my case:
> final ChannelConfigPwmSpeed dcMotorNEConfig = new
> Sequencer.ChannelConfigPwmSpeed(
> Sequencer.Clock.CLK_2M, 20000, 1060, new DigitalOutput.Spec(2));
>
> I chose the 2MHz clock based on this documentation:
>  * A steps channel allows determining the clock rate on a per-cue basis.
> This often allows
>  * avoiding having to split cues, thus resulting in a less total cues and
> more efficient
>  * execution. The rule for choosing the correct clock is to always use the
> highest rate that
>  * will cause the resulting period to be <= 2^16. In other words, choose
> the highest available
>  * clock which is less than or equal to (2^16 / Tp) or (2^16 * Fp), where
> Tp is the desired
>  * period in seconds, or Fp is the desired frequency in Hz. For example,
> if we want to generate
>  * pulses at 51Hz, 65536 * Fp = 3.34MHz, so we should use the 2MHz clock,
> and the period value
>  * will be round(2MHz / 51Hz) = 39216. This result in an actual rate of
> 2MHz / 39216 ~=
>  * 50.9996[Hz]
>
> So, as I went for 100Hz, the closest clock rate to 6.55MHz is 2MHz. The
> period is calculated 2MHz/100Hz so the value of 20000 comes up.
>
> The 1060 value for the init Pulse Width is the one I take from the ESC
> specs and is set in microseconds.
> Is this right?
>
> What I don't grasp yet very well, even after I read:
> "The IOIO motor control API introduces the notion of channels. Each
> channel generates a single waveform of a given type, typically (but not
> always) driving a single output pin. On a given application, you would
> normally have multiple channels of different types, which are then
> controlled in synchronization to achieve a complex motion." it's still not
> very clear for me what a channel is.
> What confuses me the most is that we have to define both a clock frequency
> and a period. From my understanding of frequency, once you define it, let's
> say 2MHz, the period can be calculated automatically 1/2MHz =
> 0.5microseconds.
> What is the period that is defined per channel for?
> I assume it is for converting the channel clock frequency to the sequencer
> one. Is this right?
>
> Now, about sending the pulse width to the ESC.
> From our previous conversation I understood that the formula should be as
> such:
> // motorsPowers comes as values between 0 and 255
> // needs to be transformed to values from 0 to 1 by multiplying to 0.39f
> Math.round((1060.f + (800 * motorsPowers.nw * 0.39f)) * 2);
>
> The pulse width is sent in this case in ticks and not microseconds (while
> the initial pulse width when defining the channel is set in microseconds
> and not ticks), right?
> 1 tick = 1/2MHz = 0.5 microseconds so we need the multiplier by 2 so ESC
> gets the value converted to microseconds.
>
> The sequencer push should be, based on my understanding so far:
> sequencer_.push(cue_, 625);
> That will set a freq of 100Hz.
> 100Hz equals 10ms periods which means 625 ticks of 16 microseconds.
>
> Is my understanding correct?
> If yes, my next step will be to write a simple program with a slider that
> will control the ESC. Once I make that to work, I will return to my
> original code and make it work as well.
>
>
> On Thursday, December 25, 2014 8:06:22 PM UTC+2, Ytai wrote:
>>
>> Inline
>>
>> On Dec 25, 2014 1:27 AM, <[email protected]> wrote:
>> >
>> > Hi Ytai,
>> >
>> > Well, will try to go your approach. Most of the program you see there
>> is from open source projects we tried to patch together, but by now we
>> should be able to do a simple program that does as you suggest.
>> > A few questions based on your comments, if I may:
>> >
>> > - you say that our cues are 10 sequencer ticks. We've set it like this
>> as we thought that the smaller it is, the better. I understand now it is
>> not the best approach.
>> > But just to make sure: what is a tick? Here is what I understand now:
>> > 10 ticks = 16 microseconds
>> > the cue should be set to be the period of the input frequency of the
>> ESC. If our ESC has a 1KHz input PWM (according to specs), which means a
>> period of 1ms or 62.5 times of 16 microseconds.
>> > Does this mean the cue should be set to 625 ticks?
>> > Is this right or am I still far off?
>>
>> As documented on the wiki and the sequencer javadocs, a sequencer tick is
>> 16us. You cannot do fractional ticks. Also, not sure where you got 1KHz
>> from. I'm almost certain that your ESC, when operating in PWM input mode
>> will work with 50-100 Hz, as it is supposed to interface with standard
>> receivers etc. If you want to have faster control you'd have to use its I2C
>> or UART input modes, both possible with the IOIO. But the ultimate decision
>> on what should be your control rate has to do with how fast you actually
>> need to update it in order to match your system dynamics. Unless it is a
>> very small vehicle (which surely cannot carry a phone), 1KHz is an
>> overkill. I'd start with 100Hz and move to higher rates with I2C control if
>> proven insufficient.
>>
>> >
>> > If that is right, than it means the phone will send a new signal to the
>> ESC at each 625 ticks and it should set pulse widths of between 1060
>> microseconds and 1860 microseconds.
>> > Here is where I get stuck. 1060 microseconds is bigger than 1
>> millisecond. How can I send pulse widths that are larger than the period?
>>
>> Your understanding is correct. As above, I assert that the expected
>> period is 10ms-20ms.
>>
>> > Also, what do the 2MHz clock and period refer to?
>> > If the number of ticks in the sequencer push already sets the
>> frequency, what are these values for?
>>
>> As per the wiki and Javadocs, different channel types may have a
>> different clock frequency than the sequencer's. In your case you configured
>> it to 2MHz in your channel configuration. Higher rate means greater time
>> resolution, but smaller maximum pulse width, since there's a limit on the
>> maximum number of ticks for the pulse width of 65535. So in general, set
>> the channel clock so that it is as high as possible for your maximum pulse
>> width of about 2ms.
>>
>> >
>> > I am not even sure that this is the place where to ask these questions
>> as they are probably more related to our very basic knowledge on frequency
>> and devices than IOIO. Please let me know if you think we should check out
>> other forums.
>> >
>>
>> All your questions so far have been quite IOIO specific so this is an
>> appropriate place to ask them.
>>
>> > Believe it or not, we got to the magic number of 6111 by doing some
>> math, but later realized that our math was totally wrong however I was
>> baffled that it worked.
>> >
>> > We did go through the motor control page wiki, more than a few times.
>> Probably not having an engineering background doesn't help at all but we
>> went through a lot of material to try to get to the bottom of it and we
>> still don't understand a few things, or better said, the documentation
>> makes total sense to us, but we still find it difficult to convert it to
>> code.
>>
>> Let me know if there's anything I should change on the wiki to make it
>> easier to understand. Most of your questions are answered there, but maybe
>> not clearly enough.
>>
>> >
>> > On Thursday, December 25, 2014 12:52:46 AM UTC+2, Ytai wrote:
>> >>
>> >> First and most important, I think the way you're approaching debugging
>> is inefficient. You're using a long program where a lot of things can go
>> wrong to bring up some very low level functionality. A more effective
>> approach would be to write a very simple program to exercise one ESC and
>> make sure you got that one right. Only then move on to for motors with dumb
>> logic and only then to your actual business logic.
>> >> Concretely, a few things I've noticed:
>> >> - Your cues are super short: 10 sequencer ticks or 16 microseconds as
>> per your push method call. This makes no sense: why would you run your loop
>> at 60kHz? Your ESC probably can't handle more than 100Hz or so anyway, so
>> you're sending updates about 600 times faster than required and in practice
>> probably saturating the Android CPU or the IOIO MCU or the USB link.
>> >> - This magic 6111 number makes no sense. Unless you have a good reason
>> to have chosen it, I propose that you pick your constants according to
>> specs as opposed to trial and error. The latter is a sure recipe for
>> unreliable results and frustration.
>> >> - The code that calculates the PWM bandwidth seems to have some
>> inconsistency between what the comment says and what the code does. A
>> simple test program as suggested would convince you that the problem is not
>> in the low level ESC support code.
>> >>
>> >> BTW, have you seen the wiki page about motor control. It should make
>> the operation of the sequencer clear if it isn't already.
>> >>
>> >> Let me know if you need any more help.
>> >>
>> >> On Dec 24, 2014 1:31 AM, <[email protected]> wrote:
>> >>>
>> >>> Thank you Ytai,
>> >>>
>> >>> The BaseIOIOLooper starts at line 164: https://github.com/
>> cllaudiu/vespi/blob/master/vespidrone/src/ioio/rd/
>> vespidrone/QuadcopterActivity.java
>> >>> The loop is at line 230.
>> >>>
>> >>> The pulsewidth is set starting at line 243 like this:
>> >>> dcMotorNECue_.pulseWidth = mainController.getNEMotorsPowers();
>> >>>
>> >>> The values returned by mainController.getNEMotorsPowers(); are set
>> starting with line 260 in this file: https://github.com/
>> cllaudiu/vespi/blob/master/vespidrone/src/ioio/rd/
>> vespidrone/MainController.java
>> >>>
>> >>> I've also pasted the code here in case it is more convenient:
>> >>>
>> >>> class Looper extends BaseIOIOLooper {
>> >>> /** The on-board LED. */
>> >>>
>> >>> private Sequencer.ChannelCuePwmSpeed dcMotorNECue_ = new
>> ChannelCuePwmSpeed();
>> >>> private Sequencer.ChannelCuePwmSpeed dcMotorNWCue_ = new
>> ChannelCuePwmSpeed();
>> >>> private Sequencer.ChannelCuePwmSpeed dcMotorSECue_ = new
>> ChannelCuePwmSpeed();
>> >>> private Sequencer.ChannelCuePwmSpeed dcMotorSWCue_ = new
>> ChannelCuePwmSpeed();
>> >>>
>> >>> private Sequencer.ChannelCue[] cue_ = new Sequencer.ChannelCue[] {
>> dcMotorNECue_,dcMotorNWCue_,dcMotorSECue_,dcMotorSWCue_ };
>> >>> private Sequencer sequencer_;
>> >>>
>> >>> /**
>> >>> * Called every time a connection with IOIO has been established.
>> >>> * Typically used to open pins.
>> >>> *
>> >>> * @throws ConnectionLostException
>> >>> *             When IOIO connection is lost.
>> >>> * @throws InterruptedException
>> >>> *
>> >>> * @see ioio.lib.util.IOIOLooper#setup()
>> >>> */
>> >>> @Override
>> >>> protected void setup() throws ConnectionLostException,
>> InterruptedException {
>> >>> showVersions(ioio_, "IOIO connected!");
>> >>> enableUi(true);
>> >>> //led_ = ioio_.openDigitalOutput(0, true);
>> >>> final ChannelConfigPwmSpeed dcMotorNEConfig = new Sequencer.
>> ChannelConfigPwmSpeed(
>> >>> Sequencer.Clock.CLK_2M, 6111, 0, new DigitalOutput.Spec(2));
>> >>> final ChannelConfigPwmSpeed dcMotorNWConfig = new Sequencer.
>> ChannelConfigPwmSpeed(
>> >>> Sequencer.Clock.CLK_2M, 611, 0, new DigitalOutput.Spec(3));
>> >>> final ChannelConfigPwmSpeed dcMotorSEConfig = new Sequencer.
>> ChannelConfigPwmSpeed(
>> >>> Sequencer.Clock.CLK_2M, 6111, 0, new DigitalOutput.Spec(4));
>> >>> final ChannelConfigPwmSpeed dcMotorSWConfig = new Sequencer.
>> ChannelConfigPwmSpeed(
>> >>> Sequencer.Clock.CLK_2M, 6111, 0, new DigitalOutput.Spec(5));
>> >>>
>> >>> final ChannelConfig[] config = new ChannelConfig[] { dcMotorNEConfig,
>> dcMotorNWConfig,dcMotorSEConfig,dcMotorSWConfig };
>> >>> sequencer_= ioio_.openSequencer(config);
>> >>> sequencer_.waitEventType(Sequencer.Event.Type.STOPPED);
>> >>> while (sequencer_.available() > 0) {
>> >>> push();
>> >>> }
>> >>> sequencer_.start();
>> >>> }
>> >>>
>> >>> /**
>> >>> * Called repetitively while the IOIO is connected.
>> >>> *
>> >>> * @throws ConnectionLostException
>> >>> *             When IOIO connection is lost.
>> >>> * @throws InterruptedException
>> >>> * When the IOIO thread has been interrupted.
>> >>> *
>> >>> * @see ioio.lib.util.IOIOLooper#loop()
>> >>> */
>> >>> @Override
>> >>> public void loop() throws ConnectionLostException,
>> InterruptedException {
>> >>> //led_.write(!button_.isChecked());
>> >>> push();
>> >>> //servo_.setDutyCycle(0.05f + _varValue * 0.05f);
>> >>> //led_.setDutyCycle(0.05f + _varValue * 0.05f);
>> >>> //led_.setPulseWidth(1500);
>> >>> }
>> >>> private void push() throws ConnectionLostException,
>> InterruptedException {
>> >>> dcMotorNECue_.pulseWidth = mainController.getNEMotorsPowers();
>> >>> dcMotorNWCue_.pulseWidth = mainController.getNWMotorsPowers();
>> >>> dcMotorSECue_.pulseWidth = mainController.getSEMotorsPowers();
>> >>> dcMotorSWCue_.pulseWidth = mainController.getSWMotorsPowers();
>> >>> sequencer_.push(cue_, 10);
>> >>> }
>> >>>
>> >>>
>> >>>
>> >>>
>> >>> The motor pusleWidth is read from this code:
>> >>> // motorsPowers comes as values between 0 and 255
>> >>> // needs to be transformed to values from 0 to 1
>> >>> // Math.round((1060.f + (800 * motorsPowers.nw * 0.39f)) * 2);
>> >>>
>> >>> uno_varValue = Math.round(1060 + (motorsPowers.nw * 8));
>> >>> due_varValue = Math.round(1060 + (motorsPowers.ne * 8));
>> >>> tre_varValue = Math.round(1060 + (motorsPowers.sw * 8));
>> >>> qua_varValue = Math.round(1060 + (motorsPowers.se * 8));
>> >>>
>> >>> The above code works but as the numbers we've set make no real sense
>> to us we are not sure why it works and if it works at the optimal
>> parameters.
>> >>> Here is a video with it working: https://www.youtube.
>> com/watch?v=qXMKKL9BIT8
>> >>>
>> >>> Thank you very much for looking into this. We plan to actually write
>> an article after we get to the bottom of it as it will hopefully help
>> others as well.
>> >>> Claudiu
>> >>>
>> >>>
>> >>>
>> >>> On Wednesday, December 24, 2014 8:34:40 AM UTC+2, Ytai wrote:
>> >>>>
>> >>>> The multiplication by 2 is only valid for the 2MHz case, where each
>> tick is half a microsecond or each 2 ticks are one microsecond.
>> >>>> The ESC is likely not arming as result of sending the wrong pulse
>> width. Your example doesn't show how you set the pulse width. Also, you
>> seem to be setting the default pulse width to 0 instead of 1060us, which
>> means that every time you stall the sequencer you'd get 0, which the ESC is
>> likely to interpret as a fault.
>> >>>> If you send me the entire code in question (please reduce it to the
>> minimum that demonstrates your problem) I can probably help you find your
>> actual problems and save a few email round trips.
>> >>>>
>> >>>> On Dec 22, 2014 3:20 AM, <[email protected]> wrote:
>> >>>>>
>> >>>>> One more thing.
>> >>>>>
>> >>>>> If I switch to:
>> >>>>> new Sequencer.ChannelConfigPwmSpeed(Sequencer.Clock.CLK_250K, 750,
>> 0, new DigitalOutput.Spec(2));
>> >>>>> which would translate to the same input PWM freq as with the 2MHz
>> example, the ESC does not arm.
>> >>>>>
>> >>>>> I feel I am missing something basic but I am not sure what.
>> >>>>>
>> >>>>> Claudiu
>> >>>>>
>> >>>>> On Monday, December 22, 2014 12:54:19 PM UTC+2,
>> [email protected] wrote:
>> >>>>>>
>> >>>>>> Thank you Ytai for jumping in.
>> >>>>>>
>> >>>>>> Just tried the value of 40000. The ESC does not arm.
>> >>>>>> Also tried the value of 2000 (the ESC specs state the Input PWM is
>> 1KHz). Same behavior.
>> >>>>>>
>> >>>>>> When switching back to 6100 (it works with 6200 as well and any
>> value in between) things work again.
>> >>>>>> Does this mean that the ESC input PWM freq is at around 350Hz?
>> >>>>>> Do you have any idea how I could probe this?
>> >>>>>>
>> >>>>>> When you say we feed the pulse width in microseconds instead of
>> ticks, what do you mean?
>> >>>>>> The difference I see from your way of feeding the pulseWidth is
>> that you multiply by 2. Is this how it should be converted from
>> microseconds to ticks?
>> >>>>>> If we multiply by 2 like in your example, the ESC doesn't arm.
>> >>>>>>
>> >>>>>> Thank you,
>> >>>>>> Claudiu
>> >>>>>>
>> >>>>>> On Sunday, December 21, 2014 7:45:15 PM UTC+2, Ytai wrote:
>> >>>>>>>
>> >>>>>>> Is it possible that you're confusing the motor (output) PWM rate
>> with the control (input) PWM?
>> >>>>>>> Hobby ESC are almost universally 50Hz (20ms) input.
>> >>>>>>> You also used the wrong type of PWM channel and fed the pulse
>> width in microseconds instead of ticks.
>> >>>>>>>
>> >>>>>>>  So I imagine you should need something like:
>> >>>>>>>
>> >>>>>>> // 40000 ticks @ 2MHz == 20000us == 20ms
>> >>>>>>> // Also, the PWM rate corresponds to SPEED not POSITION
>> >>>>>>> new Sequencer.ChannelConfigPwmSpeed(Sequencer.Clock.CLK_2M,
>> 40000, 0, new DigitalOutput.Spec(2));
>> >>>>>>>
>> >>>>>>> ...
>> >>>>>>>
>> >>>>>>> // Then:
>> >>>>>>> ChannelCuePwmSpeed cue;
>> >>>>>>>
>> >>>>>>> ...
>> >>>>>>> float power = <value between 0 (stopped) and 1 (full speed)>;
>> >>>>>>> cue.pulseWidth = Math.round((1060.f + (800 * power)) * 2);
>> >>>>>>>
>> >>>>>>> On Sun, Dec 21, 2014 at 4:29 AM, <[email protected]>
>> wrote:
>> >>>>>>>>
>> >>>>>>>> Hello,
>> >>>>>>>>
>> >>>>>>>> I am having troubles understanding how the Sequencer works for
>> controlling a couple of ESCs.
>> >>>>>>>> The ESCs are Afro ESC from HobbyKing. Their manual can be here:
>> http://www.hobbyking.com/hobbyking/store/uploads/745353836X1335174X28.pdf
>> >>>>>>>> According to their specs: For PWM input, motor stop / arm below
>> 1060µs, full power at 1860µs.
>> >>>>>>>> That would be the pulse width for controllig the speed of the
>> motor, right?
>> >>>>>>>>
>> >>>>>>>> The code we have in our Android app to initiate the sequencer:
>> >>>>>>>> final ChannelConfigPwmPosition motorESC = new Sequencer.
>> ChannelConfigPwmPosition(
>> >>>>>>>> Sequencer.Clock.CLK_2M, 6120, 0, new DigitalOutput.Spec(2));
>> >>>>>>>>
>> >>>>>>>> the cue value is set to 10: sequencer_.push(cue_, 10);
>> >>>>>>>>
>> >>>>>>>> and the value that we send for the pulse width are generated as
>> follows:
>> >>>>>>>> uno_varValue = (int) (1060 + (motorsPowers.nw * 8));
>> >>>>>>>>
>> >>>>>>>> The motor is running with these values but I just can't
>> understand why.
>> >>>>>>>> Some of the questions we have:
>> >>>>>>>> - why only values around 6100 work for the period. The ESC
>> should have an input freq of 1 Khz (according to this:
>> http://www.hobbyking.com/hobbyking/store/__52338__Afro_
>> ESC_30Amp_Multi_rotor_Motor_Speed_Controller_SimonK_
>> Firmware_US_Warehouse_.html) though the manual says this:  The default
>> PWM frequency is 18kHz with 800 distinct steps, but may be adjusted to any
>> frequency.
>> >>>>>>>> - why only 2Mhz clock values worked. I was not able to make it
>> work with other values
>> >>>>>>>> - if the documentation says that 1860µs is the value for full
>> power, why I don't get full power when I send 1860(I can send up to 2500
>> and there is a clear change in the motor speed)
>> >>>>>>>>
>> >>>>>>>> The whole code can be found here: https://github.com/
>> cllaudiu/vespi/tree/master/vespidrone/src/ioio/rd/vespidrone
>> >>>>>>>>
>> >>>>>>>> We are trying to build a drone based on Android and we have some
>> stability issues at this stage. It flies but we find it hard to control it.
>> Before getting into PID tuning and other elements we want to make sure that
>> the Android - IOIO part works perfectly and that we understand what happens
>> there. Thank you for your time.
>> >>>>>>>>
>> >>>>>>>> --
>> >>>>>>>> You received this message because you are subscribed to the
>> Google Groups "ioio-users" group.
>> >>>>>>>> To unsubscribe from this group and stop receiving emails from
>> it, send an email to [email protected].
>> >>>>>>>> To post to this group, send email to [email protected].
>> >>>>>>>> Visit this group at http://groups.google.com/group/ioio-users.
>> >>>>>>>> For more options, visit https://groups.google.com/d/optout.
>> >>>>>
>> >>>>> --
>> >>>>> You received this message because you are subscribed to the Google
>> Groups "ioio-users" group.
>> >>>>> To unsubscribe from this group and stop receiving emails from it,
>> send an email to [email protected].
>> >>>>> To post to this group, send email to [email protected].
>> >>>>> Visit this group at http://groups.google.com/group/ioio-users.
>> >>>>> For more options, visit https://groups.google.com/d/optout.
>> >>>
>> >>> --
>> >>> You received this message because you are subscribed to the Google
>> Groups "ioio-users" group.
>> >>> To unsubscribe from this group and stop receiving emails from it,
>> send an email to [email protected].
>> >>> To post to this group, send email to [email protected].
>> >>> Visit this group at http://groups.google.com/group/ioio-users.
>> >>> For more options, visit https://groups.google.com/d/optout.
>> >
>> > --
>> > You received this message because you are subscribed to the Google
>> Groups "ioio-users" group.
>> > To unsubscribe from this group and stop receiving emails from it, send
>> an email to [email protected].
>> > To post to this group, send email to [email protected].
>> > Visit this group at http://groups.google.com/group/ioio-users.
>> > For more options, visit https://groups.google.com/d/optout.
>>
>  --
> You received this message because you are subscribed to the Google Groups
> "ioio-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/ioio-users.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"ioio-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/ioio-users.
For more options, visit https://groups.google.com/d/optout.

Reply via email to