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] <javascript:>> 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] <javascript:>.
> > To post to this group, send email to [email protected] 
> <javascript:>.
> > 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