Shop OBEX P1 Docs P2 Docs Learn Events
Hall effect sensors (4 in a circle) — Parallax Forums

Hall effect sensors (4 in a circle)

mminasianmminasian Posts: 26
edited 2009-07-15 14:06 in Propeller 1
Hey guys, so I'm taking a new approach to my project. I've attached a picture which will hopefully describe what I'm trying to do. I have one magnet glued to the inside of a round shaft. I have four hall effect "digital switches" (resistor pulled up to 3.3v or whatever the voltage needs to be for an "on" state). They are spaced 90 degrees around the circle. The idea is to calculate angular speed every 90 degrees (somewhat unnecessary, I think one sensor + one magnet is enough) but then, I take the orders, I don't make them. Also, based on the last sensor hit, and the approximate speed, we can calculate the approximate location of the magnet at any given time. If those familiar with this type of application could chime in on my code, I would much appreciate advice/criticism etc. The sensors don't come until Monday so I can't test yet, I just wanted to see if there were any fatal errors in logic right off the bat. I think the code is decently commented, but let me know if it doesn't make sense.

var
  long pins, cntA, cntB, cntC, cntD, time, angular_speed, position, position2 
pub initialize                                   
  dira[noparse][[/noparse]22..25]~      '4 sensors, for use on pins 22-25
  pins := 22..25
  return pins
pub read
  repeat
    case ina[noparse][[/noparse]pins]
      1000 :            'pin 22 is on (magnet activated switch)
        position := 0   'gives the absolute 90 degree position for later on
        cntA := cnt     'store clk count
        waitpeq(1, 23, 0) 'wait until pin 23 is turned on
        cntB := cnt       'record new count
        time := (cntB - cntA) / 80_000_000  'number of counts over clk frequency
                                            'yields time in seconds for transition
      0100 :
        position := 90
        cntB := cnt
        waitpeq(1, 24, 0)
        cntC := cnt
        time := (cntC - cntB) / 80_000_000 
      0010 :
        position := 180
        cntC := cnt
        waitpeq(1, 25, 0)
        cntD := cnt
        time := (cntD - cntC) / 80_000_000 
      0001 :
        position := 270
        cntD := cnt
        waitpeq(1, 22, 0)
        cntA := cnt
        time := (cntA - cntD) / 80_000_000
    angular_speed = time / 90                'time divided by 90 degrees for angular velocity
        
pub get_position
   if position == 0   'check for last absolute 90 degree position rating
    position2 := 0 + (cnt - cntA)*angular_speed     'take the current count - the last known count to figure out how
                                'long it's been since it hit the last switch, multiply by speed and add
   if position == 90
    position2 := 90 + (cnt - cntB)*angular_speed
   if position == 180
    position2 := 180 + (cnt - cntC)*angular_speed
   if position == 270
    position2 := 270 + (cnt - cntD)*angular_speed
   if position2 > 359
    position2 := 0
  return position2
pub get_speed
  return angular_speed

768 x 1024 - 135K

Comments

  • mminasianmminasian Posts: 26
    edited 2009-07-10 18:25
    Also, MAX RPM is about 10K which is about 166 Hz spinning, and therefore with 4 sensors, I need 666Hz of resolution. I forgot the link to the sensors:

    http://www.hamlin.com/specsheets/55100 IssueAE.pdf
  • heaterheater Posts: 3,370
    edited 2009-07-10 18:43
    How do you know which way it's turning ?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • mminasianmminasian Posts: 26
    edited 2009-07-10 18:47
    mmmm good point, I don't really have track of that, presumably for now we are only going one direction, but I suppose that doesn't account for any odd mistakes. I suppose I could keep track of the last sensor hit using the "position" variable, and set up an if statement i each case. That certainly could get dicey though...
  • heaterheater Posts: 3,370
    edited 2009-07-10 20:27
    I was just thinking about the start up.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • mminasianmminasian Posts: 26
    edited 2009-07-10 21:47
    Its going on a vehicle, which should be moving forward, so I am making the assumption
  • Nick MuellerNick Mueller Posts: 815
    edited 2009-07-10 22:49
    I only had a short gimpse at your code, BUT:
    If the position is really important, you'll fail. smile.gif
    The reason is, that you forgot to consider the acceleration. You can only estimate the position after having read three pulses and by the difference in time calculate the acceleration. Even combistion engines get something like 30% difference in ONE SINGLE revolution. Even worse with high performance engines. (look at YouTube and listen the Renault F1 playing the Marseillaise).

    www.youtube.com/watch?v=N2zSfNpUxT8 OK, a bit crude. But it must be OK, they are the French. wink.gif

    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO

    Post Edited (Nick Mueller) : 7/10/2009 10:55:59 PM GMT
  • SamMishalSamMishal Posts: 468
    edited 2009-07-11 11:13
    MMinasion,

    There are a few SYNTAX and Semantic problems with your program.

    Pressing F9 will actually compile the program but without downloading to the propeller
    and would work even if you do not have a propeller even connected to the PC.

    This way you can find some of the Syntax problems.

    The semantic problems are another thing and you need to run the program to find them
    but here is a list:

    1- You are not defining the Clock parameters and so on in the Con section
    2- the line Pins := 22..25· does not work.......Syntax problem
    ··· what you need here is to use constants. Also the statement Return pins does not work.....SPIN does not use this syntax to return
    ··· a result from the function. You can either use Result := pins.......or you can define your function with a named return
    ··· like this
    ······· Pub Initialize : pins
    ···and then when you want to return a value you say
    ······· pins := some value
    ··
    ·· but any way the syntax pins:= 22..25··· is an error in the first place and using a constant to define the first pin in the
    ·· sequence is the way to go

    3- in the case statement case ina[noparse][[/noparse]pins] again will not work......
    ··· if you have defined a constant (or variable) you can say case ina[noparse][[/noparse]Pin0..Pin0+3] or case ina[noparse][[/noparse]Pin0+3..Pin0]
    ··· where Pin0 is the first pin number in the sequence.

    4- binary numbers like the ones you use in the case statement must have % in front of them
    ·· when you say 1000 then that would be taken as one thousand by the compiler. But if you say··
    ·· %1000 then it becomes binary.

    5- You case statements are confused....%0100 would be Pin 23 not pin 24 also %0010 is 24 not 25 and %0001 would be 25 not 22
    ··· so you WaitPeq statements are using the wrong pin numbers for the cases.

    6- the line···· angular_speed = time / 90·····is an error you need to use the := operator

    7- in your case statement you are assuming the FIXED Pin numbers even though your intent was to have
    ··· them change according to the definition at the top.....use the Constant

    8- In the getposition method you should really use an array so instead of CNTA then CNTB etc.
    ··· it would be better to have Cntr[noparse][[/noparse]4] and use Cntr[noparse][[/noparse]0], Cntr[noparse][[/noparse]1] etc.
    ··· This way your GetPosition method would be written more efficiently like
    ··· ··· x := position/90
    ······· position2 := x*90+(cnt-Cntr[noparse][[/noparse]x])*angular_speed
    ··· instead of all the if-statements.

    9- When you calculate the time using······ time := (cntA - cntD) / 80_000_000
    ··· there are two problems
    ····· a- you are assuming clock speed.....it is better to use ClkFreq
    ····· b- CntA is smaller than CntD.....so you are going to get a negative time


    These are the few I could find

    Also I forgot.....most Hall effect sensors are Analog.....you may need a comparator
    unless the sensors you bought are digital.....check that out..

    Regards

    Sam

    ····

    Post Edited (SamMishal) : 7/11/2009 11:24:58 AM GMT
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-07-11 11:27
    I didn't look at the program, however the idea of a magnetic encoder is a neat idea. I believe Allegro Microsystems has some off the shelf ICs that take care of the particulars and spit out the data. Check out the product on their web site, maybe it can provide some inspiration (or be an option for you).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
    www.tdswieter.com
  • mminasianmminasian Posts: 26
    edited 2009-07-13 22:12
    @ Sam: Many thanks for all of your suggestions, I have implemented them, along with Nick's acceleration point below. I think is a little more up to standard. I was waiting to compile the other program until the sensors came in (tomorrow). I ended up using the hamlin sensors from digikey:


    http://www.hamlin.com/specsheets/55100%20IssueAE.pdf


    I am using the three wire "Digital Switch version." I will have resistors to pull the output to 3.3 V. I don't think I need a comparator?

    Updated code, I think this is more along the right track.

    ALSO: I couldn't find the matching magnets to go with the hall effect, so I called Hamlin, and told them about my project and they were more than happy to drop 5 of them in the mail to me free of charge! Great service.

    var
      long pins, cntr, time, time2, angular_speed, angular_speed2, angular_acceleration,  position, position2
      byte x
    con
      #22 Pin1, Pin2, Pin3, Pin4
    pub initialize                                   
      dira[noparse][[/noparse]Pin1..Pin4]~      '4 sensors, for use on pins 22-25
    
    pub read
      repeat
        time2 := time
        case ina[noparse][[/noparse]Pin1..Pin4]
          %1000 :            'pin 22 is on (magnet activated switch)
            position := 0   'gives the absolute 90 degree position for later on
            cntr[noparse][[/noparse]0] := cnt     'store clk count
            waitpeq(1, Pin2, 0) 'wait until pin 23 is turned on
            cntr  := cnt       'record new count
            time := (cntr - cntr[noparse][[/noparse]0]) / _CLKFREQ  'number of counts over clk frequency
                                                'yields time in seconds for transition
          %0100 :
            position := 90
            cntr  := cnt
            waitpeq(1, Pin3, 0)
            cntr  := cnt
            time := (cntr - cntr) / _CLKFREQ 
          %0010 :
            position := 180
            cntr  := cnt
            waitpeq(1, Pin4, 0)
            cntr  := cnt
            time := (cntr - cntr) / _CLKFREQ 
          %0001 :
            position := 270
            cntr  := cnt
            waitpeq(1, Pin1, 0)
            cntr[noparse][[/noparse]0] := cnt
            time := (cntr[noparse][[/noparse]0] - cntr) / _CLKFREQ
        angular_speed2 := angular_speed
        angular_speed := time / 90               'time divided by 90 degrees for angular velocity
        angular_acceleration := (angular_speed - angular_speed2) / (time + time_2)
        
            
    pub get_position [img]http://forums.parallax.com/images/smilies/tongue.gif[/img]osition2
       x := position / 90
       position2 := 90*x + (cnt - cntr[noparse][[/noparse]x])*angular_speed + (angular_acceleration / 2) * (cnt - cntr[noparse][[/noparse]x]) * (cnt-cntr[noparse][[/noparse]x]) 
       if position2 > 359
        position2 := 0
    pub get_speed
      Result := ((angular_speed + angular_speed2) / 2)
     
    pub get_acceleration :angular_acceleration
    
    
    



    (for whatever reason the cntr index isn't showing up on this post!, the logic is standard though and should be correct)

    Also, Sam in reference to Point number 9, I don't believe the clock will be negative, as you can see that before that time statement, I have set the cntr[noparse][[/noparse]0] to a point in time past cntr. Also, in reference to point number 5, the case statements checks once it has achieved a state, and then I am waiting until it gets to the next position, hence the pins are staggered by one.

    Clock speed is set in the main program.

    Thanks again to all as always. I can't wait to test this out!

    Post Edited (mminasian) : 7/13/2009 10:18:19 PM GMT

  • SamMishalSamMishal Posts: 468
    edited 2009-07-13 23:05
    hi mminasian,
    Just a few problems....
    1- You have not defined the array Cntr.....you just defined one variable called Cntr but then you are using
    ······ Cntr[noparse][[/noparse]0] and also later when you use Cntr[noparse][[/noparse]x] you do not have the array.....
    ··· Also I do not understand what you are trying to do with the Cntr[noparse]/noparse any way but it definately is not going to give
    ··· you the right results the way you have done it especially with the lines I have highlighted in red.

    ··· See the code below with the lines in RED being problem lines.

    2- WaitPeq(1,PinX,0) ..... is a problem ......you need to use
    ··· waitPeq( |< Pinx, |< Pinx , 0)·· .....

    ··· the first parameter of WaitPEQ is the state is for each bit in the 32 bits for each pin and the
    ··· second is a Mask......so you need to put the 1 in the right bit corresponding to the pin and so in the mask too.
    ··· you can use the |< operator or the << operator to shift the 1 t o create the state and mask.....read about WaitPEQ in the
    ··· manual.

    3- the line
    ····· ····angular_acceleration·:=·(angular_speed·-·angular_speed2)·/·(time·+·time_2)
    ··· don't you need to subtract not add....you want Delta time no??

    4- It is better to use ClkFreq instead of _ClkFreq......if you have the Propeller manual.....read the section
    ··· Titled _ClkFreq vs ClkFreq on page 66.....it explains why it is better to use the ClkFreq function

    var
      long pins, [color=red]cntr[/color], time, time2, angular_speed, angular_speed2, angular_acceleration,  position, position2
      byte x
    con
      #22 Pin1, Pin2, Pin3, Pin4
    pub initialize                                   
      dira[noparse][[/noparse]Pin1..Pin4]~      '4 sensors, for use on pins 22-25
    
    pub read
      repeat
        time2 := time
        case ina[noparse][[/noparse]Pin1..Pin4]
          %1000 :            'pin 22 is on (magnet activated switch)
            position := 0   'gives the absolute 90 degree position for later on
            cntr[noparse][[/noparse]0] := cnt     'store clk count
            [color=red]waitpeq(1, Pin2, 0)[/color] 'wait until pin 23 is turned on
            [color=red]cntr [/color][color=red] := cnt[/color]       'record new count
            time := [color=red](cntr[/color][color=red] - cntr[noparse][[/noparse]0])[/color] / [color=red]_[/color]CLKFREQ  'number of counts over clk frequency
                                                'yields time in seconds for transition
          %0100 :
            position := 90
            [color=red]cntr[/color]  := cnt
            [color=red]waitpeq(1, Pin3, 0)
    [/color]        [color=red]cntr [/color][color=red] := cnt[/color]
            time := [color=red](cntr[/color][color=red] - cntr[/color][color=red])[/color] / [color=red]_[/color]CLKFREQ 
          %0010 :
            position := 180
            [color=red]cntr[/color]  := cnt
            [color=red]waitpeq(1, Pin4, 0)
            cntr [/color][color=red] := cnt[/color]
            time := [color=red](cntr[/color][color=red] - cntr[/color][color=red])[/color] / [color=red]_[/color]CLKFREQ 
          %0001 :
            position := 270
            [color=red]cntr [/color] := cnt
            [color=red]waitpeq(1, Pin1, 0)[/color]
            [color=red]cntr[noparse][[/noparse]0][/color] := cnt
            time := ([color=red]cntr[noparse][[/noparse]0] - cntr[/color]) / [color=red]_[/color]CLKFREQ
        angular_speed2 := angular_speed
        angular_speed := time / 90               'time divided by 90 degrees for angular velocity
        angular_acceleration := (angular_speed - angular_speed2) / ([color=red]time + time_2[/color])
        
            
    pub get_position[color=red] osition2
    [/color]   x := position / 90
       position2 := 90*x + (cnt - cntr[noparse][[/noparse]x])*angular_speed + (angular_acceleration / 2) * (cnt - cntr[noparse][[/noparse]x]) * (cnt-cntr[noparse][[/noparse]x]) 
       if position2 > 359
        position2 := 0
    pub get_speed
      Result := ((angular_speed + angular_speed2) / 2)
     
    pub get_acceleration :angular_acceleration
    
    


    ···

    Post Edited (SamMishal) : 7/13/2009 11:11:54 PM GMT
  • Nick MuellerNick Mueller Posts: 815
    edited 2009-07-13 23:28
    @mminasian:

    I do not know what exact positions you need. I initially (or in the middle) thought that you do need to know 5 distinct positions that do not change with RPM. I guess you need them for getting the motor to run or better to start running.
    If it is so that you need 5 fixed position use 5 damned sensors and not 4. You will have big jerks when you start the motor and you need 1/2 a revolution and then will only get a *wild* guess about the position.

    Edit:
    With your software, you'll only get a position when the motor is running. Each case statement will wait 'till hell frezes over in the waitpeq-statement.


    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO

    Post Edited (Nick Mueller) : 7/14/2009 12:13:55 AM GMT
  • mminasianmminasian Posts: 26
    edited 2009-07-14 01:00
    @Nick Good call, I will have a startup mode...this is a secondary object not the primary. I am doing something different than before, there are only 4 fixed positions now, I'm taking a completely different tac on it than I did in the other posts.

    @Sam Like I said for whatever reason the forum isn't posting my code correctly. It isn't showing the indices properly, this is what I am actually doing:

    e.g.
    var
    long cntr, time, time2, angular_speed, angular_speed2, angular_acceleration, position2

    %0100 :
    position := 1
    cntr := cnt
    waitpeq(1, Pin3, 0)
    cntr := cnt
    time := (cntr - cntr) / CLKFREQ

    Etc. The stupid code formatting on the forum is editing those out.


    Also, the time is the amount over two different sets of 90 degrees. The delta T is the amount over the total of both time ranges.

    I will look into fixing my WaitPEQ statements as well. Thanks guys!

    EDIT: The index is STILL not showing in the code, the forum seems to use it to change font size???
  • Nick MuellerNick Mueller Posts: 815
    edited 2009-07-14 01:34
    > EDIT: The index is STILL not showing in the code, the forum seems to use it to change font size???

    Use the code-tag and pay attention to have a space after every [noparse][[/noparse]

    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO
  • SamMishalSamMishal Posts: 468
    edited 2009-07-15 11:28
    SamMishal·said...
    Also the statement Return pins does not work.....SPIN does not use this syntax to return
    oops.......This is one of these rare occasions where I am not so right blush.giflol.gif·
    See the manual page 196 it says it all.......proof of my fallibility after all.....I have to revise
    my whole outlook on life and the meaning of my existence......I thought that only other people
    make mistakes.....well well....I am not a god after all· ·tongue.gif

    Samnono.gif
  • JonnyMacJonnyMac Posts: 9,197
    edited 2009-07-15 14:06
    Shouldn't you use the absolute operator in your differential time calculation?

    %0100 : position := 1
            cntrstart := cnt
            waitpeq(1, Pin3, 0)
            cntrend := cnt
            time := ||(cntrend - cntrstart) / CLKFREQ
    
Sign In or Register to comment.