IR RX and TX code

ivydene25

New Member
All,

I am looking at creating a lightweight IR based Remote control for indoor flying Planes of about 10 to 15 gms. The code below is my first thoughts but it seems to easy ;-)

Has any one got any advise as to it's viability?

The TX will read in via READADC the voltage from the three pots that will then control the length of the channel pulses. The start of the control frame is marked by a 1.5 mS pulse. As there are three channels I then have three control pulses.

TX Code
Code:
; 
; 08M2 Infrared TX 
; 3 channel rudder and elevator on joystick and throttle on linear slide pot
;
init:
	;
Do
	readadc c.1,b0
	w3=b0*57+7500/100
	b0=b4
	readadc c.2,b1
	w3=b1*57+7500/100        ; this converts from the ADC range of 0 to 255 to PMM range of 75 to 220
	b1=b4
	readadc c.3,b2
	w3=b2*57+7500/100
	b2=b4
	pulsout c.1,150
	pause 5
	pulsout c.1,b0
	pause 5
	pulsout c.1,b1
	pause 5
	pulsout c.1,b2
	pause 10
Loop
The RX currently outputs to Servos but I will be changing this to actuators once I have this working.

Code:
;
; 08M2 Infrared RX 
; 3 servo channels for rudder, elevator and throttle for external 
;
init:
	servo c.1,75		; Initialise throttle servo
	servo c.2,75		; Initialise elevator servo
	servo c.3,75		; Initialise rudder servo
do
	pulsin c.4,1,w1		; detect the start frame pulse of 1.5mS
	if w1 = 150 then
		for b0 = 1 to 3
			pulsin c.4,1,w1	; detect the channel pulses between 7.5mS and 22.5mS for each channel
			w1 = w1 / 100
			If b2 >= 75 and b2 <= 225 and b0 = 1 then servopos c.1,b2	;b2 is low byte of w1
			If b2 >= 75 and b2 <= 225 and b0 = 2 then servopos c.2,b2
			If b2 >= 75 and b2 <= 225 and b0 = 3 then servopos c.3,b2
		next b0
	endif
loop
Thanks for your time.

Cheers Jim
 

Goeytex

Senior Member
Scaling the ADC to get to 75 to 220 can be simplified to w3 = b0 * 4 / 7 + 75

Not positive, but I suspect that Pulsin being a blocking command and using the internal timer will interfere
with Servo and cause some serious servo glitches.
 
Last edited:

BESQUEUT

Senior Member
All,
I am looking at creating a lightweight IR based Remote control for indoor flying Planes of about 10 to 15 gms. The code below is my first thoughts but it seems to easy ;-)
Has any one got any advise as to it's viability?
Thanks for your time.
Cheers Jim
I think that problems will appear il you receive partial pulses... One of them can be interpreted as one 1.5 ms pulse and I can't know what will happen later...
Suppose than partial pulse was for servo N°2. Suppose this is interpreted as one 1,5 ms pulse.
Next pulse (for N°3) will goto to servo N°1
Next will be a 1,5 ms pulse and will be ignored.
Next pulse is for N°1 and will go to N°2. and so one...
I propose to use two (or more ?) 1,5 ms pulses. Will be more secure...

Another proposition is to deal with received 1.5 ms pulse in place of a 7.5/22.5 one
==> if this happen, you have to do something...(not only drop it...)
 
Last edited:

ivydene25

New Member
Thanks for your input.
I suppose the only way to get around the Pulsin issue is to run the servo code on a separate device.
Ultimately I would like to use PWM instead of PPM/servo output, will this suffer in the same way?
Cheers Jim
 

ivydene25

New Member
Paix,
A servo has a control board that examines the pulses fed to it and dependent on the length of the pulse determines the position. An actuator uses a direct current to induce an amount of rotational movement in a magnet.
One would use PPM and the other PWM.

Cheers Jim.
 

Goeytex

Senior Member
Picaxe PWM cannot quite get slow enough to control a servo effectively. 61 hz is the slowest possible speed using only
M2 parts @ 4mhz. Servos are nominal 50hz. However you can use pulsout in a 20 ms loop and
do it quite well.
Code:
do 
   pulsout  pin, pulsewidth 
   some other code here
   get some serial data maybe
   pulsin  as long at it doesn't "block" more than 15 ms or so 
   pause 18ms  minus  other code overhead
loop
The 20ms between servo pulses is not that critical and can vary from 10 - 30 ms with most servos
without causing any problems.
 
Last edited:

Paix

Senior Member
Thanks Ivydene25, I'll get Google to bring me up to date on the current possibilities. This is a new component on my radar. :)
 

ivydene25

New Member
Besqueut,
I was hoping to use an an IR RX module that would produce a demodulated signal. My understanding of Pulsin was that it triggered on high to low or low to high edges so if we encounter a pulse half way through then wouldn't be an edge or am I missing something?

Cheers Jim
 

ivydene25

New Member
Goeytex,
I was going to use PWM with the magnetic actuators rather that a servo but perhaps this is a way forward. It would be nice if I could fit the RX code on a single device.

Thanks Jim
 

BESQUEUT

Senior Member
Besqueut,
I was hoping to use an an IR RX module that would produce a demodulated signal. My understanding of Pulsin was that it triggered on high to low or low to high edges so if we encounter a pulse half way through then wouldn't be an edge or am I missing something?
Cheers Jim
Modulating is good to prevent receipt from another frequency, but does not prevent for partial pulses...

An idea will be to wait for next 1,5 pulse before updating trims.
It's very unlikely to receive a valid patern (1,5ms 11ms 12 ms 13 ms 1,5ms) with partial pulses due to masked emitter...
 

BESQUEUT

Senior Member
However you can use pulsout in a 20 ms loop and
do it quite well.
The 20ms between servo pulses is not that critical and can vary from 10 - 30 ms with most servos
without causing any problems.
I agree, and you can overspeed M2 parts...
 

ivydene25

New Member
OK had time to play and it is clear that pulsin and Servopos and PWM all must use the same timer as was said.
So the only way forward I can see is to use one 08m2 to run pulsin to capture the signal stream and a second one to control the outputs to the servos/actuators.
I did try a loop checking the input pin for a change of state and then do the timing myself, but in reality this caused the same issues as using Pulsin.
(not sure why that should be as I wouldn't expect my loop would use the same timer).

Cheers Jim
 

Goeytex

Senior Member
So the only way forward I can see is to use one 08m2 to run pulsin to capture the signal stream and a second one to control the outputs to the servos/actuators.
Yes, and the problem you will run into is getting the data from one Picaxe to the other without timer conflicts.
I2C cannot operate at the same time as pulsin on the same Picaxe. The background polling of I2C will collide with
Pulsin and/or pulsout from time to time causing false readings. Even then, an 08M2 can only be a master so one would have to
be an X2 or a 28X1. So that leaves serial or possibly SPI as the other options.

What kind of signal does an actuator require? Is it the same as a servo ?
 

ivydene25

New Member
OK I have looked at the RX code a bit further and I have come up with the following that gets around the conflict between Pulsin and servo or PWM. Hopefully it will enable a single 08m2 device.

Code:
;
;Infrared two channel RX (throttle and rudder)
;
;Expects a frame of three pulses
;1st is the start pulse and is 100uS long
;2nd is the rudder position and is between 750uS and 2250uS
;3rd is the throttle ESC and is between 750uS and 2250uS
;Current code using servos but may change to acctuator using PWM
;for rudder and PWN for Brushed motor.
;
init:
	b0 = 150	; Rudder position
	b1 = 75	; Throttle position
	w1 = 0	; Counter for pulse length
	pulsecnt = 0	; Count of which pulse we are looking at 
	result = 0	; Result of w1 conversion
	servo c.1,b0	; Rudder to middle position
	servo c.2,b1	; Throttle ESC to closed
	setint c.5,%00100000,%00100000	; set interrupt on pin c.5 for high
;
;Loop around setting the servo positions based on the pulse lenghts recieved
;
main:
	do
		servopos c.1,b0	; Set rudder servo position
		servopos c.2,b1	; Set Throttle ESC
	loop
;
;When Pin c.5 goes high this code is run.
;Code checks for the 1st pulse when recieved it looks for the next two pulses
;and sets the values of b0 and b1 for the servopos commands in main:
;
interrupt:
	do until pin c.5 = 0	; Count the length of the pulse
		inc w1
	loop
	select case pulsecnt	; Determine which pulse we are looking at
	case 0	;Start Pulse?
		if w1 < l1 and w1 > l2	; l1 and l2 need to be set dependent on
			pulsecnt = 1	; count for 100 uS. If start pulse recieved
		endif				; then look for rudder pulse.
	case 1	;Rudder 
		gosub convert	;convert w1 to 75 to 225 range move result to result
		if result >= 75 and result <= 225	; Check result is in range
			b0 = result		; move to Rudder position variable
			pulsecnt = 2	; ready to look for Throttle pulse
		elseif 
			pulsecnt = 0	; If not a valid pulse then start again.
		endif
	case 2	;Throttle
		gosub convert	;convert w1 to 75 to 225 range move result to result
		if result >= 75 and result <= 225	; Check result is in range 
			b1 = result		; move to Throttle position variable
		endif
		pulsecnt = 0		; reset to look for next start pulse
	endselect
	setint %00100000,%00100000	; reset interrupt
return
			
convert:
	;need to understand what values of w1 we can expect for pulses 
	;of range 7.5mS to 22.5mS.
	;store the result in result.
return
The issue I have currently is determining the time it will take for each time around the counting loop for w1, measuring the pulse widths. When using assembler one knows the number of clock cycles each command takes.

Does anyone have any idea on the sort of figures I will be likely to get, for w1, for 100uS, 750uS and 2200uS pulses.
These are used primarily within the case 0 section and the convert: subroutine?

As I am not sure what time penelty I may get from the Picaxe Shell. I have tried using debug to check these values but get random values as I have not built the TX and I am limited in test gear.

Cheers Jim
 

ivydene25

New Member
Goeytex,

Sorry missed your query about the PWM and actuators.
I try to run them at about 10KHz frequency, and modify the duty to provide variable position. Of course to go both ways you need to use two pins one driving one way the other the other way. I have seen people using bridges but that's over complex for me.
Remember that actuators have no feedback so are not accurate devices and are more influenced by outside parameters like the speed of the aircraft and the size of the rudder.
Actuators are normaly made to be between 50 and 100ohm, depends on the thickness of the wire and number of turns required.
This will of course set current limits dependent on voltage used. I normaly am using in light models about 25gms so use 3.7V lipo battery but need to keep the current down.

Cheers Jim
 

hippy

Ex-Staff (retired)
Does anyone have any idea on the sort of figures I will be likely to get, for w1, for 100uS, 750uS and 2200uS pulses.
Your existing code -

Code:
interrupt:
	do until pin c.5 = 0	; Count the length of the pulse
		inc w1
	loop
is equivalent to -

Code:
interrupt:
If pinc.5 <> 0 Then done
  inc w1
  Goto Interrupt
done:
So you will get better results with the following as that's less commands to execute each time round the loop -

Code:
interrupt:
	do 
		inc w1
	loop until pin c.5 = 0
as that is equivalent to -

Code:
interrupt:
  inc w1
  If pinc.5 <> 0 Then interrupt
I couldn't tell which PICAXE you are using or at what speed with a quick scan of the thread but the rule of thumb is 250us for a simple command at 4MHz, or 125us per component of a command.

For that second example loop there are approximately 7 components, so around 875us per loop at 4MHz. So for 100uS and 750uS you'll go round the loop once and for 2200uS probably three times.

With even simple commands taking 250us, whether you will ever get a 100us pulse interrupting at 4MHz is mostly luck and the delays in seeing the pulse and interrupt latency times have to be subtracted before the 'loop timing' starts.

The numbers may get better at faster than 4MHz speed but there could still be issues and difficulties in discriminating between pulse lengths. There's also the issue of how quickly each pulse follows each other, whether interrupt routine time will cause some pulses to be missed, though again I haven't studied the thread so don't fully understand what you are trying to achieve.
 

nick12ab

Senior Member
@Hippy - according to the code in the first post and it was also mentioned in post 13 so the PICAXE in use is a 08M2.
 

hippy

Ex-Staff (retired)
Thanks nick12ab. I was confused over the "SETINT C.5" which, ignoring the almost certain error in that, had me thinking it's not an 08M2, though could be with a DISCONNECT, but I gave up trying to second guess.
 

ivydene25

New Member
Hippy,

Thanks for the information. I was trying to get around using Pulsin due to the conflict with other timer sensitive commands.

As I am using the 08m2 I could increase the clock speed, I could also change the pulse durations as I am doing both RX and TX.

This is for slow flying indoor light models so I cannot see that this would matter.

Although it would be nice to have a resolution inline with the standard servo I could reduce it to say 9 steps 4 each side of centre.

I will have a think, thanks for your input. Jim
 

hippy

Ex-Staff (retired)
Okay; I've got my head around what's going on and what's required. Let's ignore the transmitter for now and concentrate on the receiver as the transmitter can be made to deliver what the receiver requires later.

You basically have to turn the way you've been thinking about it inside out: You can use SERVOPOS to set the servos as required and once set they will keep running in the background so you only need to update SERVOPOS when you have new data. Thus the program is -

Gosub InitialiseServos
Do
Loop

The DO-LOOP is empty so far, servos will keep updating and tracking required positions as would be expected; they don't actually change positions because there's been no update of SERVOPOS but would change if there had been - Perfect so far but no means to alter their positions !

So the challenge now is to allow the PICAXE to receive data and update SERVOPOS without using any blocking commands as that disrupts the servo loop timing. Maths and number manipulation won't block so you can do as much as you want, it's input commands which block; PULSIN, COUNT, SERIN, SERRXD, IRIN, INFRAIN are all problematic but you can test input pin levels and count by incrementing variables how long high or low and you could even use the internal timer to do background timing using SFR manipulation. An easier option though is to use HSERIN.

So let's start with one servo ( all untested code, incomplete and pin allocations may not be correct etc ) ...

Code:
#Picaxe 08M2
HSerSetup B2400
Servo 1, 150
bit8 = 1
Do
  HSerin w0
  If bit8 = 0 Then 
    ServoPos 1, b0
    bit8 = -1
  End If
Loop
That's quite easy to update to two sequential HSERIN for two servos but there's the chance the receiver reads the data swapped over, so use the lsb of the data to indicate if it's for channel 1 or 2. Using lsb means we can set and retrieve data simply be setting or clearing that bit and still pass 7-bit data without having to divide to send or multiply when we receive it. We now have -

Code:
#Picaxe 08M2
HSerSetup B2400, %000
Servo 1, 150
Servo 2, 150
bit8 = 1
Do
  HSerin w0
  If bit8 = 0 Then 
    If bit0 = 0 Then
      ServoPos 1, b0
    Else
      bit0 = 0
      ServoPos 2, b0
    End If
    bit8 = -1
  End If
Loop
Then to control it, all we need is to send the right data, something like ...

Code:
PwmOut IRLED_CATHODE, 38kHz
Do
  ReadAdc 1, b0 : bit0 = 0 : SerOut IRLED_ANODE, N2400,(b0) : Pause 10
  ReadAdc 2, b0 : bit0 = 1 : SerOut IRLED_ANODE, N2400,(b0) : Pause 10
Loop
There's no error checking or data validity checking but should be good enough to test proof of concept in ideal circumstances, and if it works it only needs making bullet proof and reliable. None of that should impact on the fundamental issue of making it all work without blocking which is the challenge we needed to overcome.
 
Top