​ ​ ​ ​ RC model boat, class project
Results 1 to 9 of 9

Thread: RC model boat, class project

  1. #1
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    856

    Default RC model boat, class project

    Hi all,

    My latest picaxe challenge below .

    I'm working on a class project we built with kids this year, where the outcome is a little radio controlled fishing boat. We built a number of boats and even had a competition for the school year-end in the local pond. Now, I want to sort out known problems and improve some things for the next year.

    One such improvement is adding backwards 'gears' for the ship. The code below works as expected in forward 'gears' - you can select a speed and steer left and right. However, if you select backwards 'gear', as soon as you move the rudder (inputs C.3;C.4) the pwm is thrown over to forward motor output, while keeping the duty cycle.

    I was suspecting some timer incompatibility, so I looked at SFRs of 14M2, but after trying them out (see the code) I can see nothing wrong. Any ideas?

    Code:
    'Ship control
    
    #picaxe 14m2
    #no_data
    
    'Flags
    Symbol dirflag = bit0
    
    'Byte variables
    Symbol RudderPos = b4
    Symbol Counter = b5
    
    'Word variables
    Symbol Speed = w13
    Symbol MainMotorDuty = w12
    
    'Constants
    Symbol SingleBtnDelay = 300
    Symbol DoubleBtnDelay = 500
    Symbol RudderRightMaxPos = 140
    Symbol RudderLeftMaxPos = 80
    Symbol ServoFullMoveDelay = 300
    Symbol ServoStep = 10
    Symbol MainMotorPeriod = 100
    Symbol MainMotorStep = 20
    Symbol MaxSpeed = 9                          '~3.0V motor voltage
    Symbol MinSpeed = 1                          '0.0V motor voltage
    Symbol SpeedStep = 1
    Symbol DirCtrlVal = 4
    Symbol SpeedSlope = 10
    
    init:
      input B.1            'Go forward BTN
      input B.2            'Go reverse BTN
      input C.3            'Steer left BTN
      input C.4            'Steer right BTN
      
      output B.3           'Navigation lights, red and grn
      output B.4           'Steering servo
      output B.5           'Front and rear mast lights, white
      output C.0           'Interior light and high beam
      output C.1           'Main engine PWM signal B
      output C.2           'Main engine PWM signal A
    
      low B.5 : low B.3 : low C.0 'Initialise all lights to OFF
      
      RudderPos = 110
      peeksfr %10111110, b1
      b0 = b1 | %10000000
      pwmout pwmdiv64, B.4, 220, RudderPos         'Initialise servo, set rudder to centre position, trimmer pot solution required
      pokesfr %10111110, b0   ;Bank 5 => 101; location 01E => 11110
      speed = DirCtrlVal   'corresponds to zero
      
    main:
      peeksfr %10111110, b2
      sertxd ("CCPTMRS: ",#b2,CR,LF)
      sertxd ("CCPTMRS: ",#bit23,#bit22,#bit21,#bit20,#bit19,#bit18,#bit17,#bit16,CR,LF)
      if pinC.4 = 0 then                                                'If steer right button pressed ...
      	pause SingleBtnDelay                                          '... ebounce the signal ...
      	if pinC.3 = 0 then                                               '... and check if this is not a two button command
      		pause DoubleBtnDelay                                      'In case it is, debounce buttons enough and ... 
      		toggle B.5                                                         '... toggle NAV lights ...
          toggle B.3
    ;  		pause DoubleBtnDelay                                      '... debounce some more
      	elseif RudderPos > RudderLeftMaxPos then        '... back to single button command steer right, limit max value ...
      	  RudderPos = RudderPos - ServoStep                 '... and move rudder servo a little
          peeksfr %10111110, b1
          b0 = b1 | %10000000
      	  pwmout pwmdiv64, B.4, 220, RudderPos
          pokesfr %10111110, b0   ;Bank 5 => 101; location 01E => 11110
      	endif
      	pause SingleBtnDelay                                          '... ebounce the signal ...
      endif
      if pinC.3 = 1 then                                                 'Same as above, but for the steer left button
      	pause SingleBtnDelay                                          '... ebounce the signal ...
      	if pinC.4 = 1 then
      		pause DoubleBtnDelay
      		toggle B.5
          toggle B.3
    ;  		pause DoubleBtnDelay
      	elseif RudderPos < RudderRightMaxPos then
      		RudderPos = RudderPos + ServoStep
          peeksfr %10111110, b1
          b0 = b1 | %10000000
      	  pwmout pwmdiv64, B.4, 220, RudderPos
          pokesfr %10111110, b0   ;Bank 5 => 101; location 01E => 11110
      	endif
      	pause SingleBtnDelay
      endif
    
      if pinB.1 = 1 then             'forward
      	pause SingleBtnDelay
      	pause SingleBtnDelay
      	if pinB.2 = 1 then
      		pause DoubleBtnDelay
      		toggle C.0
      		pause DoubleBtnDelay
        endif
      	if Speed < MaxSpeed then
     		  Speed = Speed + SpeedStep
        endif
        sertxd ("Speed: ",#Speed,CR,LF)
      	if Speed >= DirCtrlVal then
          Select case Speed
          case 4
        sertxd ("At 1st 4!",CR,LF)
            hpwm OFF
          case 5
            MainMotorDuty = 0
            for Counter = 1 to SpeedSlope
              MainMotorDuty = MainMotorDuty + 10;150
        		  hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
              pause 200
            next Counter
          case 6
            MainMotorDuty = 180;180
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          case 7
            MainMotorDuty = 220;220
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          case 8
            MainMotorDuty = 270;270
      		  hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          case 9
            MainMotorDuty = 330;330
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          endselect
        else
          Select case Speed
          case 1
            MainMotorDuty = 220;220
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, MainMotorPeriod, MainMotorDuty
          case 2
            MainMotorDuty = 180;180
            hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, MainMotorPeriod, MainMotorDuty
          case 3
            MainMotorDuty = 150;150
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, MainMotorPeriod, MainMotorDuty
          case 4
        sertxd ("At 2nd 4!",CR,LF)
            hpwm OFF
          endselect
      	endif
      endif
    
      if pinB.2 = 1 then
      	pause SingleBtnDelay
      	pause SingleBtnDelay
      	if pinB.1 = 1 then
      		pause DoubleBtnDelay
      		toggle C.0
      		pause DoubleBtnDelay
        endif
      	if Speed > MinSpeed then
      		Speed = Speed - SpeedStep
      	endif
        sertxd ("Speed: ",#Speed,CR,LF)
      	if Speed >= DirCtrlVal then
          Select case Speed
          case 4
        sertxd ("At 3rd 4!",CR,LF)
            hpwm OFF
          case 5
            MainMotorDuty = 150;150
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          case 6
            MainMotorDuty = 180;180
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          case 7
            MainMotorDuty = 220;220
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          case 8
            MainMotorDuty = 270;270
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          case 9
            MainMotorDuty = 330;330
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, MainMotorPeriod, MainMotorDuty
          endselect
      	else
          Select case Speed
          case 1
            MainMotorDuty = 220;220
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, MainMotorPeriod, MainMotorDuty
          case 2
            MainMotorDuty = 180;180
        		hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, MainMotorPeriod, MainMotorDuty
          case 3
            MainMotorDuty = 0
            for Counter = 1 to SpeedSlope
              MainMotorDuty = MainMotorDuty + 10;150
        		  hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, MainMotorPeriod, MainMotorDuty
              pause 200
            next Counter
          case 4
        sertxd ("At 4th 4!",CR,LF)
            hpwm OFF
          endselect
      	endif
      endif
    goto main

    Thank you for your time,

    Edmunds

  2. #2
    Technical Support
    Join Date
    Jan 1970
    Location
    UK
    Posts
    24,365

    Default

    Quote Originally Posted by edmunds View Post
    if you select backwards 'gear', as soon as you move the rudder (inputs C.3;C.4) the pwm is thrown over to forward motor output, while keeping the duty cycle.
    Not sure exactly what you mean by "the pwm is thrown over to forward motor output" and there's too much code to get an understanding of with a quick glance.

    Perhaps if you could describe what is happening and what should be happening that may make it easier to diagnose or debug, give a clue where to look.

    The only thing I can guess is that if you are using 0 to 100 for 0-100% forward and want something like 0 to -100 for 0-100% backwards, you may have to invert the duty in the reverse case.

  3. #3
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    856

    Default

    Quote Originally Posted by hippy View Post
    Not sure exactly what you mean by "the pwm is thrown over to forward motor output" and there's too much code to get an understanding of with a quick glance.
    Ok, fair enough, will try.


    There is a transmitter. Cheap 433mhz transmitter, HT12E encoder and 4 buttons. On pressing a button, this bursts out [address+] four bits corresponding to which buttons were pressed. The buttons in my case are forward, backward, left and right.

    There is a receiver. Cheap 433mhz receiver, HT12D decoder, picaxe14m2, cheap motor controller - basically a LD239-like thing, some transistors to drive higher current leds and some more. The RF receiver receives the 4 bit code, HT12D decodes it to 4 digital parallel outputs and feeds into picaxe. Picaxe figures out which buttons are pressed and makes the ship go forward, backward, left or right and coordinates some aux functions if two buttons are pressed at the same time.

    The remote control needs to be as proportional as is possible with four discrete buttons. Initial press on forward, should not blast the ship away with 100% power, but, say, 15% of the max power available. Same for the rudder - steer left a little, some more, even more, and a lot. Pressing backwards or right now, should move the power down a notch and move the rudder back one step. I hope this makes sense.

    The forward motion of the ship works - you can add speed by pressing forward button and make it slower by pressing backwards button. Also, while traveling forward, steering works perfectly fine - implemented with pwmout command, not a servo command. The forward motor motion is implemented with hpwm command in single mode with %0001. Backwards should be %0010. And it is. With all the speed increase and decrease - no problem. As long as you do not touch the left-right buttons.

    As soon as left or right rudder buttons are used while the main engine is running backwards [%0010], it is thrown to forward motion [%0001] with the same duty as was set for backward direction. I.e. in case

    Code:
            hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, 100, 180
    was apparently working correctly, on a steering command it is like a following command would be executed right after the rudder position change

    Code:
            hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, 100, 180
    .

    I have replicated the problem with LEDs on AXE091 dev board and as I wrote above, I have tried to remedy timer problems, but could not see anything wrong with it.

    I hope this makes more sense,

    Edmunds
    Last edited by edmunds; 19-06-2018 at 22:37.

  4. #4
    Technical Support
    Join Date
    Jan 1970
    Location
    UK
    Posts
    24,365

    Default

    Thanks. Your big picture description makes sense but doesn't entirely help a lot regarding how the code may be misbehaving.

    If it's doing the wrong thing it's most likely because the code has incorrectly got to the point where the code tells it to do the wrong thing. The problem is determining how it got there and the why behind that.

    It's trying to determine what the flow of code is which is the difficult part for me.

    Are inputs active low or active high ?

    Your speed control SELECT-CASE commands only seem to be executed when inputs are high, not continually; I'm not sure why. Why so many SELECT-CASE for speed control ? Is it simply executing the wrong one ?

    What's the PEEKSFR/POKESFR on %10111110 doing ? Could that be screwing with something ?

    What do the outputs you toggle do ?

    Do your SERTXD commands reveal something which is different to what it should be when you press the button and things go wrong ? Have you tried adding more SERTXD to trace exactly where the code is going when you push the button and it goes wrong ?

  5. #5
    Technical Support
    Join Date
    Jan 1970
    Location
    UK
    Posts
    24,365

    Default

    Having looked at the code, tried simulating, I am still struggling with it. I think the best course would be to refactor what you have, split it into at least three parts.

    Have one subroutine which updates desired speed, direction and rudder angle from the buttons, another subroutine which translates speed, direction and rudder angle to what should actually be output.

    Have each of those with their own variables ( desired and current ) with a third subroutine which gets executed between the two which converts desired speed, direction and rudder angle from the first routine, to what the output routine should output.

    Initially that middle routine can just copy desired to current, can later be improved to make change smoother.

    That way you can check that the button handler is producing correct desired values and the output routine is outputting how things should be for the input it's given. That makes it easier to tell where the issue lies. If both work individually then both should work together.

    As you are using an M2 it would be possible to make those three subroutines separate tasks which should make things even simpler.

  6. #6
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    856

    Default

    Thanks, Hippy!

    My clumsy code was not intended for efficiency analysis. Or not yet, at least .

    Anyway, you are right, lets take a step back. Or several.

    Can you help me understand why this works (as in there is a pwm output on C.2 AND B.4 after pressing a button connected to C.3)

    Code:
    #picaxe 14m2
    #no_data
    
    'Connect motor driver [or LEDs] to C.1 and C.2
    'Connect servo to B.4
    
    'Start the main engine backwards
    hpwm pwmdiv64, pwmsingle, pwmHHHH, %0001, 100, 150
    
    
    'Move the rudder on button press
    do
      if pinC.3 = 1 then
        pause 300              'debounce the button
        pwmout pwmdiv64, B.4, 220, 110
      endif
    loop
    , but this does not (as in there is pwm output on B.4, but it dissapears on C.1 after pressing a button connected to C.3)?

    Code:
    #picaxe 14m2
    #no_data
    
    'Connect motor driver [or LEDs] to C.1 and C.2
    'Connect servo to B.4
    
    'Start the main engine backwards
    hpwm pwmdiv64, pwmsingle, pwmHHHH, %0010, 100, 150
    
    
    'Move the rudder on button press
    do
      if pinC.3 = 1 then
        pause 300              'debounce the button
        pwmout pwmdiv64, B.4, 220, 110
      endif
    loop
    Thank you,

    Edmunds
    Last edited by edmunds; 21-06-2018 at 08:41.

  7. #7
    Technical Support
    Join Date
    Jan 1970
    Location
    UK
    Posts
    24,365

    Default

    Quote Originally Posted by edmunds View Post
    Can you help me understand why this works ... but this does not
    Not entirely but I do note that in PICAXE Manual 1 and in the online command descriptions for HPWM for Single Mode it says -

    Supported : 20X2, 28X1, 28X2, 28X2-3V, 40X2, 40X2-3V

    Not Supported: 14M, 14M2, 20M2, 28X2-5V, 40X1, 40X2-5V

    http://www.picaxe.com/BASIC-Commands...terfacing/hpwm

    It may be that you are trying to do something which the 14M2 simply doesn't provide for. I would have to investigate further but suspect that, as it doesn't work when it otherwise would be expected to, that is the issue.

    Added: The 14M2 supports four PWMOUT channels; C.0, C.2, B.2 and B.4 so you may be able to move your C.1 motor connection to C.0 and replace the HPWM with appropriate PWMOUT commands.
    Last edited by hippy; 21-06-2018 at 09:41.

  8. #8
    Technical Support
    Join Date
    Jan 1970
    Location
    UK
    Posts
    24,365

    Default

    When I was trying to refactr your code I arrived at this for the motor speed control ...

    Code:
    OutputSpeed:
      Select Case nowSpeed
        Case 9 : mtrBits = %0001 : mtrDuty = 330
        Case 8 : mtrBits = %0001 : mtrDuty = 270
        Case 7 : mtrBits = %0001 : mtrDuty = 220
        Case 6 : mtrBits = %0001 : mtrDuty = 180
        Case 5 : mtrBits = %0001 : mtrDuty = 150
        Case 4 :                   mtrDuty = 0
        Case 3 : mtrBits = %0010 : mtrDuty = 150
        Case 2 : mtrBits = %0010 : mtrDuty = 180
        Case 1 : mtrBits = %0010 : mtrDuty = 220
      End Select
      If mtrDuty = 0 Then
        HPwm OFF
      Else
        HPwm PWMDIV64, PWMSINGLE, PWMHHHH, mtrBits, PWMPERIOD, mtrDuty
      End If
      Return
    You could probably keep the SELECT-CASE the same then update the bottom part, which will use C.2/C.0 rather than C.2/C.1, untested ...

    Code:
     If mtrDuty = 0 Then
        PwmOut PWMDIV64, C.2, PWMPERIOD, 0
        PwmOut PWMDIV64, C.0, PWMPERIOD, 0
      ElseIf mtrBits = %0001 Then
        PwmOut PWMDIV64, C.0, PWMPERIOD, 0
        PwmOut PWMDIV64, C.2, PWMPERIOD, mtrDuty
      Else
        PwmOut PWMDIV64, C.2, PWMPERIOD, 0
        PwmOut PWMDIV64, C.0, PWMPERIOD, mtrDuty
      End If

  9. #9
    Senior Member
    Join Date
    Apr 2012
    Location
    Cēsis, Latvia
    Posts
    856

    Default

    Quote Originally Posted by hippy View Post
    Not entirely but I do note that in PICAXE Manual 1 and in the online command descriptions for HPWM for Single Mode it says -

    Supported : 20X2, 28X1, 28X2, 28X2-3V, 40X2, 40X2-3V

    Not Supported: 14M, 14M2, 20M2, 28X2-5V, 40X1, 40X2-5V

    http://www.picaxe.com/BASIC-Commands...terfacing/hpwm
    Thanks.

    Brr. I do remember checking the suitability of 14M2 and if it would support hpwm at all. But I must have missed the fine print. Such is life. I have quite a few PCBs made, so I have five options to choose from:

    1. Forget the reverse [just not cool ]
    2. Bridge and cut traces on PCBs [sort of tricky for students, but also not useless to practice]
    3. Re-do the PCBs [how to re-use the ones I have?]
    4. Use half-bridge mode (C.2=A; C.1=B) [was giving a lot more noise on the power supply than single mode, but I now have separate power supplies; testing needed]
    5. Trick picaxe into correctly operating hpwm on C.1 [just for fun, try to start (e)ccp modules without picaxe commands, using SFRs only]

    Thank you for your code solutions, too. No doubt, a much better looking program than the original .

    Edmunds

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •