Infrared motor control

WhiteSpace

Well-known member
Following on from this post https://picaxeforum.co.uk/threads/bar-graph-display-on-ssd1306-oled.31765/ in which I described getting the OLED display to show the left and right motor control levels as bar graphs, I've now added IROUT to the first board (28x2) and set up a second breadboard with a second Picaxe (a 20M2 this time) to test for the motor remote control. I'm using a Vishay TSAL6200 IR LED and a TSOP4838. The IR LED has a red LED running off the same transistor so that I can see what's happening. The receiver drives a red (left) and green (right) LED for the same reason - in the final version there will be 2 motors instead of the LEDs. Turning the pots on the transmitter changes the speed of flashing of the receiver indicator LEDs. The LEDs on the transmitter and receiver seem to flash at the same speed. I'm just wondering whether there are any better ways of doing this or code shortcuts - the OLED now seems to catch up rather more slowly with the pot position.

The transmitter code looks like this:

Rich (BB code):
RightControl:
readadc B.4, b15; this uses a pot to give analogue control
let b4 = b15/5
Rich (BB code):
let b5 = b4 + 52  ; adds 52, to give a new figure for the b4 stored RightPot reading of between 52 and 103
      
      ; Left 0-20, 21-30, 31-51; Right 52-72, 73-82, 83-103
            
Transmit:   
      
      for b8 = 1 to 10
            irout IRLed,1,b3  ; sends the LeftPot figure via infrared led
            pause 45
      next b8
      
      for b8 = 1 to 10
            irout IRLed,1,b5  ; sends the RightPot figure via infrared led
            pause 45
      next b8
            
goto LeftControl; back to check for the next motor signal
The figures for the two pots are sent by the same IR LED, because I assume that i can't have two LEDs transmitting at the same time. So to differentiate between L and R I add 52 to the figure obtained from the R pot reading, after dividing by 5. Manual 2 at page 130 recommends sending the signal 10 times at 45ms apart. Presumably that slows things down quite significantly. Is it necessary? Are there any quicker solutions - can the 45ms be reduced at all?

At the receiving end, the code looks like this:

Rich (BB code):
;picaxe 20M2

setfreq m8

main: ; Reminder - signals from IRIN are: Left 0-20, 21-30, 31-51; Right 52-72, 73-82, 83-103

SYMBOL RedLeftLED = B.5
SYMBOL GreenRightLED = B.6

CheckLEDs: ;flashes left and right LEDS 3 times to show that they are working

For b1 = 1 to 3
      High RedLeftLED
      pause 500
      Low RedLeftLED
      pause 500
Next b1

For b1 = 1 to 3
      High GreenRightLED
      pause 500
      Low GreenRightLED
      pause 500
next b1

FlashLEDs:

irin C.3,b0 ;reads the figure (0 to 127) from TSOP4838 and puts it in b0

if b0 >= 0 and b0 < 52 then let b5 = 102/b0 ; the range 0-51 is the left motor.  Dividing 102 by b0 gives a simple indiactor that the speed control is carrying through to this board - if b0 is 1 (full rev), the LED will flash every 102ms.  If b0 is 51, LED will flash every 2ms
elseif b0 >= 52 and b0 < 103 then let b6 = 204/b0; the range 52-102 is the right motor.  As above
endif

For b1 = 1 to 5
      High RedLeftLED
      pause b5
      Low RedLeftLED
      High GreenRightLED
      pause b6
      Low GreenRightLED
Next b1

Goto FlashLEDs

End
I would welcome any improvements! Thanks very much
 

inglewoodpete

Senior Member
Your concern appears to be that the OLED is now slow to update. However, there does not appear to be any code posted for driving the OLED. I'm assuming that the OLED is part of the receiver circuitry/code, so it would be best to post all the receiver code, so members can see any loops or delays that could be preventing prompt responses.
 

WhiteSpace

Well-known member
Thanks Inglewoodpete. Yes, the OLED (which is at the transmitter end, to provide a graphic display of the position of the motor control) now seems much slower to update, so I'm wondering if the business of transmitting the code via IROUT, and particularly the delay caused by sending the IROUT code 10 times with a 45ms delay in between each one - half a second for each transmission cycle if I understand correctly - is slowing it down so that the motor control pots may have been turned some distance before the transmitter catches up. The very short receiver code as it currently stands is above (next stage is to convert the IRIN codes to PWM and direction to send on to a pair of H-bridge drivers, which is coming along well).

The OLED code is more or less the same as the one I posted in the earlier thread. It was working very quickly, with the bars inc'ing and dec'ing sequentially across the whole movement of the pot in a couple of seconds.

It looks as though I can't post the code here in full - there's a limit of 1000 characters, so it's here in a couple of parts and I've attached a full version. It's running on a 28x2. Would it help to increase the frequency so that it cranks through the process more quickly, for example?

This is the first part (leaving out the OLED set-up which is standard). I've also attach a photo in case it helps to visualise it.

Rich (BB code):
; put the components of the bar display into memory
; dividing line

put 90, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 ; = single divider bar at the bottom of the lower row.  There are also 3 clear bytes below the line, because otherwise a press of the stop button or turning the control knob to the stop position results in uncleared orphan bars in the lower half


;bars above the line (forward gear)
put 100, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00; 1 bar.  This now displays as 6 bytes, starting from the top.  The dividing line is the bottom bit of the 3rd byte down.  The 4th to 6th bytes go below the axis.  They are necessary in order to clear the bars below the line in the event that the pot is turned so quickly that the intermediate bars are not displayed and are then left as orphans.  
put 106, 0x00, 0x80, 0xBB, 0x00, 0x00, 0x00; 2 bars
put 112, 0x00, 0xB8, 0xBB, 0x00, 0x00, 0x00; 3 bars 
put 118, 0x80, 0xBB, 0xBB, 0x00, 0x00, 0x00; 4 bars 
put 124, 0xB8, 0xBB, 0xBB, 0x00, 0x00, 0x00; 5 bars

; bars below the line (reverse gear) (because the 3rd byte has the dividing line as its bottom bit 0x80) and then 3 bytes below the line:
put 130, 0x00, 0x00, 0x80, 0x0E, 0x00, 0x00;1 bar
put 136, 0x00, 0x00, 0x80, 0xEE, 0x00, 0x00; 2 bars
put 142, 0x00, 0x00, 0x80, 0xEE, 0x0E, 0x00 ;3 bars 
put 148, 0x00, 0x00, 0x80, 0xEE, 0xEE, 0x00;4 bars 
put 154, 0x00, 0x00, 0x80, 0xEE, 0xEE, 0x0E;5 bars


gosub ClearDisplay

DisplayLine:; this displays the axis line across the middle of the screen, above or below which the bars are displayed

row = 3
col = 24
gosub setposition

for b10 = 1 to 7
hi2cout (0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80)    ;this does a row of 1 pixels
next b10


LeftControl:
readadc B.3, b14; this uses a pot to give analogue control
let b3 = b14/5

RightControl:
readadc B.4, b15; this uses a pot to give analogue control
let b4 = b15/5
23439
 

WhiteSpace

Well-known member
And the next part of the code:

Rich (BB code):
SetUpLeftMotor:
            
; Reminder - motor options are: 0-20 (backwards), 21-30 (stop - the stop position needs to be fairly wide; when narrowed down to eg. 24-26 it was difficult to find the stop position), 31-51 (forward);

if b3 >= 21 and b3 < 31 then
      ptr = 90; if left motor control is "stop", so only the axis line is displayed. 
      elseif b3 >= 31 AND b3 < 35 then ptr = 100 ; 1 bar, slow forward         
      elseif b3 >= 35 AND b3 < 39 then ptr = 106
      elseif b3 >= 39 AND b3 < 43 then ptr = 112
      elseif b3 >= 43 AND b3 < 47 then ptr = 118
      elseif b3 >= 47 AND b3 <= 51 then ptr = 124 ; 5 bars, full forward
      elseif b3 >= 17 AND b3 < 21 then ptr = 130 ; 1 bar, slow reverse
      elseif b3 >= 13 AND b3 < 17 then ptr = 136
      elseif b3 >= 9 AND b3 < 13 then ptr = 142
      elseif b3 >= 5 AND b3 < 9 then ptr = 148
      elseif b3 >= 0 AND b3 < 5 then ptr = 154 ;5 bars, full reverse
endif

gosub DisplayLeftMotor


SetUpRightMotor:

if b4 >= 21 and b4 < 31 then
      ptr = 90; if right motor control is "stop"
      elseif b4 >= 31 AND b4 < 35 then ptr = 100 ; 1 bar, slow forward         
      elseif b4 >= 35 AND b4 < 39 then ptr = 106
      elseif b4 >= 39 AND b4 < 43 then ptr = 112
      elseif b4 >= 43 AND b4 < 47 then ptr = 118
      elseif b4 >= 47 AND b4 <= 51 then ptr = 124 ; 5 bars, full forward
      elseif b4 >= 17 AND b4 < 21 then ptr = 130 ; 1 bar, slow reverse
      elseif b4 >= 13 AND b4 < 17 then ptr = 136
      elseif b4 >= 9 AND b4 < 13 then ptr = 142
      elseif b4 >= 5 AND b4 < 9 then ptr = 148
      elseif b4 >= 0 AND b4 < 5 then ptr = 154 ;5 bars, full reverse
endif

gosub DisplayRightMotor

let b5 = b4 + 52  ; adds 52, to give a new figure for the b4 stored RightPot reading of between 52 and 103
      
      ; Left 0-20, 21-30, 31-51; Right 52-72, 73-82, 83-103
            
Transmit:   
      
      for b8 = 1 to 10
            irout IRLed,1,b3  ; sends the LeftPot figure via infrared led
            pause 45
      next b8
      
      for b8 = 1 to 10
            irout IRLed,1,b5  ; sends the RightPot figure via infrared led
            pause 45
      next b8
            
goto LeftControl; back to check for the next motor signal

end
 

WhiteSpace

Well-known member
And then the subroutines that actually build the display (again in order to stay within the character limit, I have only posted the subroutine for the left motor display):

Rich (BB code):
DisplayLeftMotor:
 
row = 1
col = 0 
Gosub SetPosition; the major change here is that instead of writing the bars as 2 blocks of 12 columns, it writes the bars as a single 24-column block, which is about 50% faster.

hi2cout (0x40,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr) ; this does the top row
      inc row; then move down a row.
      gosub SetPosition
      inc ptr
            
hi2cout (0x40,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr)
      inc row; then move down a row.
      gosub SetPosition
      inc ptr

hi2cout (0x40,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr)
      inc row; then move down a row.
      gosub SetPosition
      inc ptr     
      
hi2cout (0x40,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr) ; this does the top row
      inc row; then move down a row.
      gosub SetPosition
      inc ptr
            
hi2cout (0x40,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr)
      inc row; then move down a row.
      gosub SetPosition
      inc ptr

hi2cout (0x40,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr,@ptr)
            
return
I don't see any easy way of shortening the loop - each transmission and display cycle loops from just before the end back to LeftControl: which reads the pots with READADC. It then has to set up the bit pointer for scratchpad and then display and then transmit. I don't see that any of this can be left out, but I'm very new to Picaxe so I'm sure there must be some ingenious solution that I haven't thought of. If anyone is able to take a quick look and make any quick suggestions I'm very happy to go away and experiment. In any event I'll try increasing the frequency, checking whether I can rearrange the steps so that they work more quickly and I'll also take a closer look at the timing of the IROUT command and the TSOP4838 datasheet to see whether I can cut some delay there. Thanks very much.
 

Attachments

WhiteSpace

Well-known member
I've done a couple of things that seems to have made a bit of a difference:

1. Changed the code so that unless there is movement on one of the pots, the code loops back to wait for any change. So it won't cycle through the IR transmission sequence if there is nothing new to transmit (if I understand correctly, the PWM on the receiver end will continue until there is a new instructions, so there's no need to keep transmitting the motor speed and direction if there's no change.

Rich (BB code):
let b16 = 25
let b17 = 25

LeftControl:
readadc B.3, b14; this uses a pot to give analogue control
let b3 = b14/5

RightControl:
readadc B.4, b15; this uses a pot to give analogue control
let b4 = b15/5

if b3 = b16 and b4 = b17 then goto LeftControl
And then at the end of the display/transmission sequence:

Rich (BB code):
let b16 = b3
let b17 = b4

goto LeftControl; back to check for the next motor signal

end
The intention is that the last bit of code sets b16 and b17 to the current values of b3 and b4 taken from the pots. Then the code loops back to LeftControl and checks the pot values. If they are unchanged from b16 and b17, it keeps looping back until there is a change.

2. The other improvement to the code is reducing the number of repetitions of the transmission sequence from 10 to 5, and cutting the delay between repetitions from 45ms to 21ms. The description here: http://picprojects.org.uk/projects/sirc/sonysirc.pdf suggests that the SONY sequence repeats at a 45ms interval, from start to start. So allowing the maximum duration for a code sequence: 2.4ms start bit plus 12 x a maximum of 1.8ms (1.2ms "1" bit plus 0.6ms pause) = 24.6ms. Add 21ms for a total sequence (bits plus gap) of 45ms. The reduction in the number of repetitions and the reduction in the delay reduces the total transmission time from 20 x 66ms = 1.32 seconds to 10 x 45ms = 450ms

Rich (BB code):
Transmit:   
      
      for b8 = 1 to 5
            irout IRLed,1,b3  ; sends the LeftPot figure via infrared led
            pause 21
      next b8
      
      for b8 = 1 to 5
            irout IRLed,1,b5  ; sends the RightPot figure via infrared led
            pause 21
next b8
It's still not perfect - it may be that just the 2nd modification is enough. I'll give it some more thought.
 

inglewoodpete

Senior Member
@WhiteSpace - You can double the execution speed of those decision blocks by rearranging your code:
Rich (BB code):
If b4 < 5 Then       ;5 bars, full reverse
   ptr = 154
ElseIf b4 < 9 Then
   ptr = 148
ElseIf b4 < 13 Then
   ptr = 142
ElseIf b4 < 17 Then
   ptr = 136
ElseIf b4 < 21 Then
   ptr = 130         ; 1 bar, slow reverse
ElseIf b4 < 31 Then
   ptr = 90          ; if right motor control is "stop"
ElseIf b4 < 35 Then
   ptr = 100         ; 1 bar, slow forward
ElseIf b4 < 39 Then
   ptr = 106
ElseIf b4 < 43 Then
   ptr = 112
ElseIf b4 < 47 Then
   ptr = 118
Else
   ptr = 124         ; 5 bars, full forward
EndIf
 

WhiteSpace

Well-known member
Thanks @inglewoodpete . I’ll give that a try. Is that because the code after AND is not necessary because if the value is below the lower figure it will have been caught by the preceding “if”. So in the second line of your suggested code, there’s no need to include >= 5 because if less than 5 it would have been caught by the first line? Ingenious! Thanks again.
 

hippy

Technical Support
Staff member
And that IF-ELSEIF sequence can be compacted by using a SELECT-CASE ...
Code:
Select Case b4
  Case < 5  : ptr = 154  ; 5 bars, full reverse
  Case < 9  : ptr = 148
  Case < 13 : ptr = 142
  Case < 17 : ptr = 136
  Case < 21 : ptr = 130  ; 1 bar, slow reverse
  Case < 31 : ptr = 90   ; if right motor control is "stop"
  Case < 35 : ptr = 100  ; 1 bar, slow forward
  Case < 39 : ptr = 106
  Case < 43 : ptr = 112
  Case < 47 : ptr = 118
  Else      : ptr = 124  ; 5 bars, full forward
End Select
On transmitting IR multiple times; that's not strictly necessary but depends on whether the receiver is ready for it and will respond immediately. The transmitting multiple times is a recommendation to better ensure that anything sent is received.

The recommendation is mainly because televisions may miss data, want to see the same data a number of times before actioning a command. That makes them less at risk of something which isn't a command directed at it being mistaken as a command.

AV equipment may face a barrage of IR for other equipment so they usually aren't as responsive as one can make a PICAXE system. It's better to validate a command and delay a few milliseconds than annoy the user by being overly responsive.
 

WhiteSpace

Well-known member
Great, thanks. I certainly had to stop testing my transmitter yesterday evening when it kept changing the TV channel! I’ll make these changes and then next step is to add the H-Bridge and motor.
 

inglewoodpete

Senior Member
Thanks @inglewoodpete . I’ll give that a try. Is that because the code after AND is not necessary because if the value is below the lower figure it will have been caught by the preceding “if”. So in the second line of your suggested code, there’s no need to include >= 5 because if less than 5 it would have been caught by the first line? Ingenious! Thanks again.
The key to "ElseIf" is the word Else, meaning otherwise, so your "AND b4..." becomes redundant.
 

WhiteSpace

Well-known member
The project is coming along well - I've now got 2 motors working at the receiver end, with PWM and direction controlled via infrared from the signals generated by the two pots. I'll post more details of the circuits and codes shortly, once I've sorted out some bugs. But for now I have a quick question. At the receiver end I have two TSOP4838 receivers, connected to pins C.6 and C.7. The intention was to have one facing one way and the other in the opposite direction to ensure good reception, although they seem to be very sensitive - even with cardboard tubes over them they receive the signal. For now, they are both pointing in the same direction. I have been unplugging them in turn to try to resolve some jerkiness in the motors - wondering whether the signals from the receivers were interfering with each other. I've discovered that although on the hardware side I have unplugged the IR receiver plugged into pin C.6, and on the code side rem'd out the IRIN to pin C.7, somehow the signal is getting through from physical pin C.7 to code pin C.6. Here's the code

Rich (BB code):
init:

      SYMBOL TSOPinput = C.7
      SYMBOL TSOPinput2 = C.6
...

Rich (BB code):
Main:; Reminder - signals from IR are: Left 0-20, 21-30, 31-51; Right 52-72, 73-82, 83-103

      ;irin TSOPinput,b0     
      ;reads the figure (0 to 127) from TSOP and puts it in b0 - temporarily rem'd out 
      irin TSOPinput2,b0; reads the figure (0 to 127) from the second TSOP (facing in the opposite direction) and puts it in b0.         
      ;Hopefully there will not be any conflict.
      debug

      If b0 < 52 then
            High RedLED
            pause 25
            Low RedLed

      Elseif b0 >=52 and b0 < 104 then
            High GreenLED
            pause 25
            Low GreenLED
And then it goes on to the motor stuff. There are cases for each motor and each direction. This is just one of them:

Rich (BB code):
      Endif

      Select Case b0
            
      Case < 21 ; depending on the value of b0, various things happen.  L Rev
                  let b1 = 20-b0    ;reverses the value of b0 so that figures run from 0 to 20 as pot is turned anticlockwise.  Figure is
                  ;copied to b1 because otherwise when this section of code ends the modified b0 figure becomes the new b0 and sends the
                  ;program off to the wrong case
                  let w7 = b1*51    ;multiplies by 51 to give figure of 0 to 1020
                  if w7 >= 1010 then let w7 = 1023 ;ensures full on PWM, ie 1023 if pot turned fully anticlockwise
                  endif
                  pwmduty LeftPWM,w7; this sends PWM signal from pin C.2 to the left motor at duty cycle from 0 to 1023
                  low LeftDirection

Is there some special characteristic of IRIN that means that it receives even from a pin other than the designated one? Or am I missing something else? Thanks very much.
 

WhiteSpace

Well-known member
I think I’ve worked out what was causing some of the anomalies in the IRIN code – I hadn’t fully appreciated the timeout issue, so I think the programme was waiting for an IR signal. I’ve now added a timeout but there’s still some work to be done if I want to be able to have two IRIN signals (not sure yet if they will be necessary or whether the receiver will pick up signals even if pointing away from the transmitter). Having tested the transmitter and receiver, I first added one motor, H-Bridge and driver, and then a second, initially running test code, then the instructions from the transmitter. After a certain amount of trial and error, I’ve got both motors working. There’s still the occasional jump in motor speed, and the odd unexpected reversal of direction. I think it may partly be due to not originally having included the 4.7k pull-up resistor on the output from the IR receiver - now corrected.

I wasn’t sure how well the receiver would differentiate between the signals for the two motors – whether one would dominate the other. I have green and red LEDs on the receiver board to show left and right signals arriving via IRIN, and they alternate very nicely. I’ve posted both sets of code. I’ve used the same Select Case approach in the receiver that Hippy suggested for the transmitter – it makes things a lot easier than on my first version. If I can work out how to post a short video I’ll do so.

23454


I’ve created a diagram showing how the motor control code design flows through from two pots that read from 0 to 255 to a single stream of IR transmission and then splits back into two sets of motor controls with direction and speed for each.

I’m sure others have come up with better implementations, but I couldn’t find anything here so perhaps it will be of interest to anyone else looking to do something similar. The approach could be adapted to push buttons like on a TV remote.

The receiver/motor hardware consists of a 6x 1.4v AA rechargeable battery pack, regulated to 5V for the Picaxe 20M2, IR receivers and motor drivers, with 2 motors running off the full 8.4V. The 2 driver chips are TC4469: http://ww1.microchip.com/downloads/en/DeviceDoc/21425C.pdf . I can’t remember now why I chose them - I originally started to plan this a few years ago and then had to put it on one side for a while. The circuit is based on this one originally contained in a Microchip development note, which doesn’t seem to be available any more.

23455

I’ve copied it exactly, except that instead of the 555 chip, the Picaxe provides a PWM signal (pulled down to ground as recommended in the manual) and direction to each TC4469. The MOSFETs are NDP6020P for the top rail and STP36NF06L for the bottom rail. The motors are these: https://www.ebay.co.uk/itm/25mm-6V-12V-24V-DC-8-800-RPM-High-Torque-Gear-Box-Motor-Reducer-Reversible-25GA/362665118195?hash=item54708689f3:m:mGQxv24VJ6Qa4MneZCh-OWA. I was told that the rated current is 300mA, stall current 2.1A and stall torque 3kg.cm. I originally chose them because they have almost identical ratings to the most powerful Lego motors which seem to be able to drive decent sized vehicles.

The 4 P-channel MOSFETs get very hot. I burnt my finger on one of them. I had read elsewhere that the PWM period should be set quite high so as to fall outside the audible range. I had originally set mine to 10KHz. But some posts on this forum (including one by Inglewoodpete the other day here: https://picaxeforum.co.uk/threads/whats-wrong-with-this-simple-set-up.31799/#post-330065) suggest that the period should be set much lower so that the MOSFETs spend less time switching and getting hot. I’ve now set the period to 1KHz. Any suggestions on PWM period or otherwise to reduce the MOSFET heat would be very welcome.

Next steps, once I have resolved the IRIN code issue, and before attaching the motors to some real load, are an entirely gratuitous laser proximity sensor and more importantly the implementation of current sensing to provide a stall cutout. The circuit diagram shows a low side resistor with a filter. Presumably with Picaxe this would just go to readADC. I assume there’s a way of calculating the required value that would indicate a stall current (is it just by Ohm’s law 2A * 0.18 Ohms = 0.36V and then 0.36V/8.4V = 11/256 (value of readADC) or have I completely misunderstood)? Perhaps I just need to stall the motor and note the readADC value?
 

Attachments

WhiteSpace

Well-known member
I think I've solved the multiple IRIN issue - I had inspiration while sleeping, although it then took several attempts to get it right. I'm not sure exactly what was happening, but I think there was some kind of conflict between the two sets of IRIN data, and sometimes the programme wouldn't receive the second set of IRIN data because it was waiting for the first and vice versa. What I have done now is to use the timeout on both IRIN commands. If the first IRIN command doesn't receive a good transmission, it jumps to check the second TSOP4838. If no signal there, it loops back. In both cases if there is a good signal, it flashes an LED (currently red or green to show which TSOP the signal came from) and then goes on to do the maths to convert the IRIN command into motor L or R, direction and PWM. I've tested it by masking and unmasking the TSOP receivers and as intended the LEDs show the signal from the first TSOP taking precedence and the second TSOP providing the signal only where the first is masked.

Here's the key piece of code. It's fairly heavily commented, partly for my own benefit and partly in case it's of any help to anyone else:

Rich (BB code):
ReadTSOPinput1:; Reminder - signals from IR are: Left 0-20, 21-30, 31-51; Right 52-72, 73-82, 83-103
      let b10 = 104; this allows a check of whether first TSOP receives a code
      irin [45, ReadTSOPinput2],TSOPinput1,IRINvalue       
      ;reads the figure (0 to 127) from first TSOP and puts it in b0; 45ms timeout allows time for 2 transmission cycles (21ms in total) from the transmitter to check for missed signal; if timeout, then goes to second TSOP to check for signal there
      let b10 = IRINvalue
      if b10 < 104 then
            goto FlashConfirmTSOP1; so if there is a good code from the first TSOP, it jumps straight to flash LEDs then does the maths and avoids a conflicting signal from the second TSOP   
      endif

ReadTSOPinput2:
            
      irin [70, ReadTSOPinput1], TSOPinput2,b0; if the first TSOP doesn't get a good code, this looks for a code on the second TSOP; reads the figure (0 to 127) and puts it in b0. If no good code on this one after 70ms (3 cycles) either, loops straight back to check on the first TSOP
      goto FlashConfirmTSOP2
      
FlashConfirmTSOP1:;Red LED flashes once if the signal is from TSOP1     
      
            High RedLED
            pause 50
            Low RedLed
      
            Goto MotorControls
      
FlashConfirmTSOP2: ;Green LED flash once if the signal is from TSOP2   
      
            High GreenLED
            pause 50
            Low GreenLED
      
            Goto MotorControls

      MotorControls:
      
      Select Case IRINvalue
 

hippy

Technical Support
Staff member
Your code seems to be a little convoluted if it's just trying to take commands from one or the other sensors. I would try running this which should work on your hardware. It doesn't actual set PWM but does report what is being received ...
Code:
#Picaxe 20M2
#Terminal 4800
#No_data

SYMBOL TSOPinput1 = C.7 : SYMBOL TSOPinput1pin = pinC.7
SYMBOL TSOPinput2 = C.6 : SYMBOL TSOPinput2pin = pinC.6

SYMBOL RedLED     = B.5
SYMBOL GreenLED   = B.7	

SYMBOL IRINvalue  = b0

Do
  Gosub ReadTSOPinput
Loop

ReadTSOPinput:
  If TSOPinput1pin = 0 Then ReadTSOPinput1
  If TSOPinput2pin = 0 Then ReadTSOPinput2
FailTSOPinput:
  Return

ReadTSOPinput1:
  irin [70, FailTSOPinput],TSOPinput1,IRINvalue       
  High RedLED
  pause 50
  Low RedLED
  Goto MotorControls

ReadTSOPinput2:
  irin [70, FailTSOPinput],TSOPinput2,IRINvalue       
  High GreenLED
  pause 50
  Low GreenLed
  Goto MotorControls

MotorControls:
  SerTxd( "Received ", #IRINvalue, CR, LF )
  Return
You could change the "[70, FailTSOPinput]" of ReadTSOPinput1 to be "[70, ReadTSOPinput2]" but I'm not sure it would help.

Any "I think it's on this, but if this doesn't work, I'll try it on that" mechanism can get complicated. If it doesn't work on 1 then trying 2 and having that not work should take it back to 1 but that can easily end up being a circular trap.

This is what I would try if the above isn't that great ...
Code:
#Picaxe 20M2
#Terminal 4800
#No_data

SYMBOL TSOPinput1 = C.7 : SYMBOL TSOPinput1pin = pinC.7
SYMBOL TSOPinput2 = C.6 : SYMBOL TSOPinput2pin = pinC.6

SYMBOL RedLED     = B.5
SYMBOL GreenLED   = B.7	

SYMBOL IRINvalue  = b0

Do
  Gosub ReadTSOPinput
Loop

ReadTSOPinput:
  If TSOPinput1pin = 0 Then ReadTSOPinput1
  If TSOPinput2pin = 0 Then ReadTSOPinput2
FailTSOPinput:
  Return

ReadTSOPinput1:
  irin [70, FailTSOPinput1],TSOPinput1,IRINvalue       
  High RedLED
  pause 50
  Low RedLED
  Goto MotorControls
FailTSOPinput1:
  irin [70, FailTSOPinput],TSOPinput2,IRINvalue       
  High GreenLED
  pause 50
  Low GreenLed
  Goto MotorControls

ReadTSOPinput2:
  irin [70, FailTSOPinput2],TSOPinput2,IRINvalue       
  High GreenLED
  pause 50
  Low GreenLed
  Goto MotorControls
FailTSOPinput2:
  irin [70, FailTSOPinput],TSOPinput1,IRINvalue       
  High RedLED
  pause 50
  Low RedLED
  Goto MotorControls

MotorControls:
  SerTxd( "Received ", #IRINvalue, CR, LF )
  Return
 

WhiteSpace

Well-known member
Thanks @hippy . I’ll give this a try. Would you mind explaining the difference between these two please?
“SYMBOL TSOPinput1 = C.7” and
“SYMBOL TSOPinput1pin = pinC.7”
And can you also explain this please:
SerTxd( "Received ", #IRINvalue, CR, LF )
I understand that SerTxd displays the “received” message and the value of IRIN on my PC screen when I’m connected to the Picaxe, but I don’t understand CR, LF. I couldn’t make sense of the manual.
Thanks again
 

lbenson

Senior Member
CR, LF are the predefined symbols for the ASCII Carriage Return and Line Feed characters, hex 0x13 and 0x10. At the end of a SERTXD command, they will result in the next SERTXD output beginning on the next line.

“SYMBOL TSOPinput1 = C.7” provides a symbolic name for a pin which you can use in, for instance, HIGH or LOW or PWM commands.

“SYMBOL TSOPinput1pin = pinC.7” provides a symbolic name which can be used in a statement which reads the value (0 or 1) of an input pin, e.g.,
IF TSOPinput1pin = 1 THEN . . .

It's confusing that you have to use different symbols for input or output, but part of that requirement is that "C.7" resolves to a number--15--and it wouldn't make sense and wouldn't be what you intend if you were to write a statement which the interpreter decodes as "IF 15 = 1 THEN".

If in the simulator, you run the following line, it will result in C.7 blinking:

DO: HIGH 15: PAUSE 500: LOW 15: PAUSE 500: LOOP
 

lbenson

Senior Member
I'm sorry but I mislead you about CR and LF. They represent the +decimal+ values 13 and 10 respectively, not hex.
 

WhiteSpace

Well-known member
Made a bit more progress over the last few days. First, an important but very simple refinement, to idiot-proof the motor controls, so that on start-up the motors don't turn at all until the motor controls are set to "stop" and then moved on from there. This stops the vehicle from launching itself off a table when it is switched on if I have left the transmitter with one or both of the motor controls set to something other than "stop." This is the relevant part of the code:

Rich (BB code):
MotorsSafe: ;a loop to send stop signals to left and right motors on power up, until pots are returned to centre
      
      pwmduty LeftPWM, 0
      pwmduty RightPWM, 0
      
      do until IRINvalue > 20 AND IRINvalue < 31; left motor stop position
      Gosub ReadTSOPinputs
      loop

      do until IRINvalue > 72 AND IRINvalue < 83 ; right motor stop position
      Gosub ReadTSOPinputs
      loop
      
MotorsActive:

      Gosub ReadTSOPinputs
I've also put in a current sensor resistor below the low side of the H-Bridge. The resistor is 0.18R. I've put a 10k resistor between the top of that resistor and the relevant Picaxe pin, which is set to Readadc10. I'm not sure whether the additional resistor is necessary - some circuits show it and some don't, so better safe than sorry.

My understanding of the current sense resistor is as follows. The reading on the serial terminal is 0 when both motors are stopped. It's 50 when the motor to which the current sense resistor is connected is turning, and strangely 22 when the other motor is turning (at the moment I have current sensing on only one motor, until I work it out). So I=V/R. 50/1024 x battery voltage 7.6V = 0.37V, then 0.37V/0.18r = 2.1A. I think that must be wrong, because the usual motor current is 330mA and the stall current is a little over 2A. Have I got the calculation right? Have I missed something? I'm also not sure why the resistor is showing a current when the "other" motor is turning. Any explanations would be gratefully received.

Meanwhile the hardware is coming on well. I've put a flyback diode (1N5817 Schottky diode) across each of the MOSFETs because I read that as well as protecting the MOSFETs it reduces heating by diverting reverse current away from the MOSFET body diodes. I haven't yet tested whether they do in fact reduce the heat. And I have wired the motors, attached them to a test bed/mounting and soldered a 220nF capacitor across the terminals. After I found on a previous project that the motor tags were a bit feeble and snapped off, I've reinforced everything with epoxy:
23504

23505
 

WhiteSpace

Well-known member
Well now I'm thoroughly confused. I put my multimeter onto one of the motors running directly from the battery pack, so just battery, motor, meter, battery, and it showed 2A with the motor turning, so not the 330mA that the supplier stated as the rated current. You may say that I should probably have done this sooner, and you'd be right of course. I need to go and understand rated v. stall current rather better, and whether there is any relationship between either of them and the current used by a motor turning without much load. I also need to go and read about current in parallel circuits, which is why I expect I'm getting a current reading on the motor 1 circuit when only motor 2 is turning. Oh well, this is teaching me a lot about electronics!
 

hippy

Technical Support
Staff member
Setting aside what currents you are actually getting, because it's just a case of twiddling the numbers below -
Code:
M+ ------.
         |
        / \
       ( O ) Motor
        \ /
         |
         }------> Vsense
        .|.
   0R18 |_|
         |
0V ------^------- 0V
Vsense = Imotor * 0.18

So, when 2A is running through the motor, and also through the 0.18R, the Vsense should be about 0.36V.

A READADC10 reading of Vsense will give an Nadc reading of -

Nadc = Vsense * 1024 / Vpsu

So assuming a PICAXE V+ (Vpsu) of 5V, a Vsense of 0.36V should give an Nadc reading of about 73.

If it were 330mA when not stalled, that should give a Vsense of 0.06V, an Nadc reading of about 12.

You could convert that Nadc reading back to a mV value of Vsense but I am not sure it would serve any useful purpose. If looking at detecting a stall you could simply use Nadc ...
Code:
Do
  ... motor handling ...
  ReadAdc10 VSENSE_PIN, Nadc
  If Nadc > 73 Then
    ... over 2A ...
  End If
Loop
Putting a 10K in series with the ADC input will protect the pin if the pin is ever accidentally set as an output, and also protect the input should the Vsense ever go above 5V.

I would include it unless it proves to be problematic.
 
Last edited:

hippy

Technical Support
Staff member
One thing to bear in mind, when PWM controlling the motor, is that it is switching current on and off. That also means current through your 0.18R is also present and not present.

You might want to add a capacitor across Vsense or the ADC input pin, repeat the READADC10 if it ever delivers a near zero reading, or average the readings.
 
Last edited:

WhiteSpace

Well-known member
Thanks very much @hippy. Your diagram reflects what I've done. However, the top of the upper MOSFETs in the H-Bridges connects to the unregulated power supply at 7 or 8V or so. The Picaxe and control circuits run at a regulated 5V. Does that mean that I shouldn't connect the Vsense in that way? Or simply that the 10k resistor is in fact essential? Presumably the readadc is comparing the Vsense with the 5V Picaxe supply and not the 7V or 8V motor supply? That will be the source of one of my errors - I had done the maths on the basis that the Vsense was being calculated by reference to 7.6V. Thanks for the code suggestion too - that's sort of where I had got to, which is always reassuring. That still doesn't explain the current readings on the motor - I've contacted the supplier to find out what the stall current should be so that I can set Nadc accordingly. Finally, is ReadADC12 in your post a typo? I had understood that it was ReadADC10. Or have I missed something?
 

hippy

Technical Support
Staff member
Presumably the readadc is comparing the Vsense with the 5V Picaxe supply and not the 7V or 8V motor supply?
That is correct. Vsense will be measured relative to the PICAXE V+ not the voltage going into the motor.

As the Vsense voltage should be less than 5V during normal operation the 10K isn't essential. You would need to have 40A-plus through the motor to raise Vsense to 5V. If that happens you probably have more to worry about than over-voltage on a PICAXE pin. But it's still sensible to add it to protect the PICAXE pin.

Finally, is ReadADC12 in your post a typo?
Indeed it is. I have corrected the previous posts.
 

WhiteSpace

Well-known member
Oh of course, because all that’s going to Vsense is the Vsense voltage, not the full 7V or 8V at the top of the H-Bridge. I have a lot to learn! Thanks again.
 

hippy

Technical Support
Staff member
You could convert that Nadc reading back to a mV value of Vsense but I am not sure it would serve any useful purpose.
On the other hand, converting Vsense into mA current might be useful though rounding errors would come into play there ...

Vsense = Imotor * 0.18
Nadc = Vsense * 1024 / Vpsu

Nadc = Imotor * 0.18 * 1024 / Vpsu

Imotor = Nadc * Vpsu / ( 0.18 * 1024 )

mA = Nadc * Vpsu * 1000 / ( 0.18 * 1024 )
mA = Nadc * 5 * 1000 / ( 0.18 * 1024 )
mA = Nadc * 5000 / 184.32

mA = Nadc * 27

That value might be useful for monitoring or diagnosis even if Nadc is what's being used in the over-current detection code.
 

AllyCat

Senior Member
Hi,
I've contacted the supplier to find out what the stall current should be so that I can set Nadc accordingly.
You can estimate the stall current by simply measuring the dc resistance of the motor (with a multimeter) and applying Ohm's Law for the supply voltage. There is little difference between a (dc commutator) motor and a generator: When a motor is spinning it generates a "back emf", which reduces the effective voltage across the coil(s) and thus lowers the current.

As indicated by hippy, the 1024 ADC value corresponds to the Reference voltage which can't be higher than the default (5 v.) supply voltage. The ADC sensitivity can be increased by lowering the Reference to one of the internal FVR levels: For measuring currents, FVR1024 can be used, which will give a resolution of 1 mV, or about 5 mA with your resistor, i.e. a full-scale of about 5 Amps. But in practice, your "in circuit" resistance may be rather higher than 0.18 ohms, taking into account wiring and connection series resistances, etc., which could partly explain your calculated higher-than-expected currents.

* In principle, the inductance of the motor should smooth (i.e. low-pass filter) the current flow, through the motor, but it appears that your resistor is measuring the pulsed (PWM) current from the power supply (depending on exactly how the "flywheel" diodes are located), so it is essential to include a voltage filter as well. A capacitor directly across 0.18 ohms would need to be gigantic; much better to include the 10 k resistor and put the capacitor directly on the PICaxe pins, where it can have an approximately 50,000 times smaller capacitance, for the same effect. ;)

* EDITED, because in a PWM system, the currents in the Motor, FET(s), Flywheel Diode(s) and Power Supply (Battery) are potentially all different. So the "equivalent circuit" in #25 may be a misleading over-simplification.

Cheers, Alan.
 
Last edited:

WhiteSpace

Well-known member
Thanks for the suggestion @AllyCat. I measured the resistance across the motor terminals. I took 10 readings for each, moving the motor a little between each measurement, and then averaged them. There was a significant difference between the two: the left motor came in at 9.35R and the right motor at 4.88R. That would equate to a stall current of left just over 800mA and right 1.6A. I was then trying to work out how this difference would affect the ReadADC calculations and calculated the Vsense as if the two resistors (motor and sense) were a voltage divider, although I'm not sure how that relates to current. I reached the following conclusion:

Left: 7.7V x (0.18R/(0.18 + 9.35R)) = 0.019V, which equates to 20 ReadADC10
Right: 7.7 x (0.18R/(0.18 + 4.88R)) = 0.036V, which equates to 37 ReadADC10

I'm not sure what if anything this calculation demonstrates.

When I measured the actual ReadADC10 off the two motors, I got the following readings:
Both motors full ahead: Left 23; Right 42 (which is very similar to the predicted readings - I'm not sure if that is coincidence or exactly what it should be, or at proportionate to the difference in resistance).
Left stop, right full ahead: Left 1; Right 76
Right stop, left full ahead: 42, Right 1

I'm not entirely sure why the current going through the right motor varies between 76/1024 x 5V = 0.37V ; 0.37V/0.18R = 2A (which ought to be the stall current, whereas in fact the motor was turning with a couple of cogs and no load) when the left motor is stopped and 42/1024 x 5V = 0.21V; 0.21V/0.18R = 1.1A when the left motor is also running.

I've got a couple more motors that I will wire up and try (I think I would prefer to have two comparable motors), and I'll do some more reading around current in parallel circuits.
 
Last edited:

hippy

Technical Support
Staff member
All your readings and calculations seem consistent for two very unmatched motors, one with about twice the resistance of the other. I am not sure why they would be so unmatched.
 

AllyCat

Senior Member
Hi,
I'll do some more reading around current in parallel circuits.
Calculating the currents in parallel circuits is "easy", you can just add them in the same way that you can add Voltage drops (or resistances) in series circuits. I'm talking "dc" of course, things get much more complicated with ac voltages and ac components such as capacitors and inductors.

So you have two H-bridges (one for each motor) but with only one (0.18 ohm) resistor in the "earth" side of both of them? As indicated before, I'd use a low pass filter of around 10k + 100 nF to the ADC input of the PICaxe (i.e. capacitor between input and ground). The problem is that you have rather a lot of "unknowns". The first is why the two motors show such different resistances; are they different versions, or perhaps is one "faulty" ? Another is that you cannot actually "turn off" the motors, you can only set around a 50% duty cycle and hope that the (average dc) voltages on each side of the bridge are similar (i.e. half the supply rail) so that little current flows through the motor.

I'm concerned that you said that one of the "FETs" got too hot to touch, that's not right and may have caused some damage. IMHO, with your present circuit you should be using an absolute maximum PWM frequency of 500 Hz, and preferably 100 Hz. A problem is that the motors will have some stray capacitance across their winding(s) and also to their body (earth). Therefore, you probably need (inductive) Low-Pass filters between each PWM output pin and the motor terminals. I'd start with perhaps 1 mH, of course with low internal (series) resistance (much less than an ohm), and "semi-air-spaced" construction (e.g. wound on a magnetic "bobbin" or rod) to avoid the magnetic material (probably ferrite) saturating.

Ultimately, I'd like to see "physical", non-electrolytic, capacitors of perhaps 100 nF - 1 uF from each motor terminal to earth (and perhaps also across the motor windings), which shouldn't affect the input power (or heating effects), once suitable inductors are connected in series with the PWM output terminals.

Cheers, Alan.

PS: In a previous post I used the term "back emf" (which I believe is still correct when referring to motors). "EMF" is the old term "Electro Motive Force", another name for "Voltage". Thus "Back emf" means the same as "Reverse Voltage" (which is effectively in series with the motor, or the battery).
 

WhiteSpace

Well-known member
Thanks @AllyCat - that's all very useful.

I've probably taken quite enough of your time already, but your response has prompted a whole series of further questions. Please just say if you don't want to spend any more time on this.

Calculating the currents in parallel circuits is "easy",
I was trying to work out why the current in one motor is 2A when the other one is not running, and 1.1A when it is. I had thought that the current drawn would be the same in both cases, and was trying to work out whether the fact of having two circuits in parallel made the difference. If I understand correctly, resistance of two parallel circuits is 1/R both = 1/R circuit 1 + 1/R circuit 2 and I was trying to understand whether that might account for the difference.

So you have two H-bridges (one for each motor) but with only one (0.18 ohm) resistor in the "earth" side of both of them?
Yes, that's correct: I have two separate H-Bridge drivers, the TC4469 chips. Each gets a PWM signal and a direction signal from the Picaxe, which has converted them from the IRIN. Motor stop is 0 PWM. There doesn't appear to be an active braking option with these drivers. I represented the motor circuits like this, ignoring the MOSFETs' RDS(ON) for these purposes.

23511

I'll filter the signal from the sense resistor as you suggest, although interestingly the ReadADC10 figure is very stable - it doesn't ever seem to show the "off" part of the PWM phase but only the voltage for the "on" part.

The problem is that you have rather a lot of "unknowns".
Agreed! The motors came from the same supplier, bought at the same time. I've just tested the 3rd bought at the same time and it comes in with a resistance of 14.2R, so different again. They all seem to be working OK, but I'm surprised that there's such a wild variation. I've asked the supplier for more info, but it's based in China (I bought them off eBay), so I may or may not get a satisfactory answer. From the outside they look identical to well-know branded motors sold by various robot parts suppliers at rather higher prices. This may be a question of getting what you pay for...

Another is that you cannot actually "turn off" the motors, you can only set around a 50% duty cycle and hope that the (average dc) voltages on each side of the bridge are similar (i.e. half the supply rail) so that little current flows through the motor.
I'm not sure that I understand. I had understood that if I set the duty cycle to 0, no current flows at all in either direction?

For the hot P-channel MOSFETs, I've put a 1N5817 diode from bottom to top across all 8 MOSFETs in the 2 H-bridges and that seems to have sorted the problem, at least until I put the motors into a vehicle and start applying serious loads. I've already got a 220nF polyester capacitor across the terminals of each motor. I'll look at your other suggestions too.

Thanks again.
 

premelec

Senior Member
I haven't followed everything here... Rpar = (Ra*Rb)/(Ra+Rb) - and how is it you are measuring resistance of the motors [you say there are 3 all different]? it is easy to get errors in measuring small resistances... from connecting wires, test lead resistance etc... perhaps easiest route to accurate figure is to run a small current through R to measure and then read the millivolts across it. Good luck....
 

WhiteSpace

Well-known member
Thanks @premelec. I did two things in post #32 - measured resistance across the terminals of the motors, out of the circuit although with their capacitors still soldered across the terminals, with ohmmeter set to its lowest setting; took 10 readings with a twiddle of the motor shaft in between in case the position of the moving parts affected it. The readings fluctuated but averaged out to 9.35R, 4.88R and 14.2R. I then also took ReadADC10 readings from the sense resistors while the motors were in circuit doing various things:
Both motors full ahead:
Left 23; Right 42
Left stop, right full ahead: Left 1; Right 76
Right stop, left full ahead: 42, Right 1
So here the mV figures shown by ReadADC10 show differences that are consistent with the resistance readings across the terminals

Apologies for the silly question - how would I run a small measurement current through the motors (and do I need to do so if I have done readings via the sense resistors, which seems to be more or less the same process)? The stuff I have read talks about providing a small known current. Does this mean that I connect a small resistor (I have a couple of 15R resistors) in series with the motor and just one or two AA batteries, measure the voltage drop across the known resistor to find the current, and then calculate the unknown motor resistance from the voltage drop across the motor and the known current? Although everything just points to the motors not being very consistent, so I think I'll just need to find some more consistent motors, get a couple more of the same and see if some of them match, or just live with it. Thanks.
 

Eng460

Well-known member
Hi Whitespace, may I suggest the basic problem you are facing is that a motor is not made of resistors, but inductors. Measuring resistance using ohms law is only valid when the motor is stationary or stalled, hence stall current. When the motor is running, the inductance of the motor windings comes into play, and the reading no longer follows a simple application of ohms law.

Behaviour of an inductance is entirely different from the behaviour of a resistor.

An inductor is a coil of wire which produces a magnetic field which stores energy when passing a current. An ideal inductor has no resistance, but a real one has a small resistance, which is the value you are measuring with the motor stalled.

An inductor produces a back emf proportional to the rate of change of current. That rate of change is the vital factor in understanding what happens when you apply a voltage to an inductor. When the connection is made, the current is zero and attempts to rise. Initially it rises quite rapidly. However the back emf proportional to the rate of change of current opposes the applied voltage, so the current rises at a rate that continually reduces until the rate of change is zero so no back emf, and the circuit continues as though the wire was only a resistor. If the motor coil inductance is large enough, you might actually notice that the reading of your voltmeter rises in a very different manner to when you connect it to a pure resistance, especially if you still have an old analogue meter with a needle on a moving coil.

EMF is often used for the back voltage produced in systems. The term is retained for historical reasons and is ok to use so long as you clearly understand that it is a voltage, not a force.

So there is no validity in connecting your Picaxe pin to measure the voltage over the sense resistor plus motor in series to measure resistance. It should just measure the voltage across the sense resistor alone. Then the current implied from the measured voltage across the sense resistor is the same as the motor current which is in series. The resistor in the connection to the pin and the capacitor suggested by others is a filter intended to average the current reading, as the pwm and the motor brush connections to the coils mean the actual current is changing rapidly so highly affected by inductance. Someone may be able to demonstrate the actual current variation on an oscilloscope, but unfortunately most of us don’t have one of those. Basically the pwm output is a voltage which is switching between 0 and 5 V, and the current is the result of all the resistors, inductors and capacitors in the circuit. Because inductors and capacitors involve time barying back emf’s and changing currents, it’s not something I would try to predict without a computer. Better to just view it if the facilities are available. If you are really a beggar for punishment, it can be done using a spreadsheet, but it’s not a trivial exercise.

So with your motor, measure the stall current with the motors stopped, one motor in the circuit at a time. This will help you set a stall current system to protect the motor. The stall current is normally measured with a low voltage, eg a 1.5 volt battery, as the resistance is normally quite low, and the coil is not designed to carry the current it would carry at full motor voltage for any length of time, and could easily cook your motor. The measured resistance allows you to calculate the stall current with the normal supply voltage using ohms law.

The normal running current will always be less than the stall current. The motor actually produces its maximum torque at stall. As the motor starts to spin, the motor draws less current and produces less torque until at free running the motor draws the least current and produces no useable torque. (All the torque produced is absorbed in overcoming friction in bearings and air turbulence.) Power is torque times rotative speed, so as the motor speed increases the power produced at first increases despite the falling torque, but then a maximum is reached where in further speed increase, the reducing torque means the output power reduces, to zero at the free running speed. If my memory serves me well, maximum power is at a point where the current is about half the stall current. On many hobby motors I have noticed that the motor rated maximum power is less than half the stall current, so I assume the bearings or windings would still overheat on prolonged running at that current. So the motor should be run below the rated power and your circuit should include some protection from excessive running at power above the rated current.

The different motor resistances you are measuring, if real, and they may be, suggests motors with different windings, either wire gauge or number of turns on each pole, or even different number of poles. They may have been designed for a different power level or voltage, but I don’t know why you would get that variation within one batch.

I hope that helps get you on a sound basis to continue your experiments. Sorry it is so long. Still more on dc motors has been left out than what is included in that description.

Eng460
 

WhiteSpace

Well-known member
Wow @Eng460 thanks for this amazingly detailed response. I’m very grateful to you (and all the others who have chipped in so far). I’ll go away and give this a go.
 

AllyCat

Senior Member
Hi,

An obvious reason why the motors are not balanced is "because they were cheap", so they might be factory rejects. However, if their resistance remains reasonably constant as they are rotated through a full turn, then it's unlikely to be a "serious" fault, such as a disconnected coil or damaged commutator/brush.

The physical cause might be that the coils are wound with thinner wire (higher resistance), or because they have less turns (lower resistance). In either case that might have been a production mistake, or to save cost. If thinner wire was used you could match the lower resistance motor by simply adding a resistor in series. Another possible reason for a higher resistance is that a resistor had been included internally to limit the stall current, perhaps to prevent the motor "burning out" if it remains stalled for too long.

If the motor coils have different numbers of turns, then you won't be able to match them well. There are various ways you might be able to test this. An inductance measurement would be the normal method, because the inductance is proportional to the square of the number of turns. But very few multimeters include an inductor test facility, one reason being that the inductance, the (series) resistance and the (stray) capacitance can all be important parameters. Note that copper (of the windings) has a significant positive temperature coefficient, so the resistance may rise when the motor runs (and particularly if stalled).

A test you could try is to rotate each motor at a constant speed and measure the voltage generated on your multimeter. It needn't be turned very fast (perhaps just by hand), only sufficient to generate a few hundred mV. The voltage generated should be approximately proportional to the number of coil turns (and of course the speed of rotation), although there are many other variables (which hopefully can be ignored). Another possibility, if a cord (or string) could be wrapped around the motor shaft or a pulley, would be to measure the stalled torque (at low voltage to avoid damage) by hanging an adjustable weight on the cord (so that the motor moves it neither up nor down).
... Please just say if you don't want to spend any more time on this.

I'm not sure that I understand. I had understood that if I set the duty cycle to 0, no current flows at all in either direction?
That's OK, I'll continue to contribute when I have time, and think I have anything "useful" to say. ;)

Ah yes. I thought the bridge was being used in a "symmetrical" mode (PWM on both sides), but looking again, I see that one side is constantly either low or high (to select the direction) and the other side has PWM to control the speed. Note that in the "reverse" direction the PWM must change from 100% - 0% (for increasing speed) but that is probably handled automatically by the control/driver ic. You should NOT add any capacitance to the motor (across its terminals, or to ground) on the PWM (switching) side of the bridge, unless (i.e. until) you insert a filter inductor (as mentioned in my previous post #34) between the PWM output and the motor.

From your later post, it does appear that you are now measuring the "expected" current drains for each motor and direction (given their resistance differences).

Cheers, Alan.
 
Last edited:
Top