Putting robotics at your service™

Free shipping on orders over $200

Basic Atom Pro / Bot Board / IRPD (remcon) Program.

Print view Share :
Previous topicNext topic

Page 1 of 2 [ 30 posts ]

1, 2
User avatar
Guru ( offline )
Posts: 9258
Posted: 2006-08-08 02:03 
This is the first version of the program that allows the IRPD to receive commands from a universal TV remote control. It has to be set to Sony format. The program is interupt driven and runs in the background. It's a Beta so lets see what it can do eh? ;)

http://www.lynxmotion.com/images/temp/atomrc01.zip

Nathan says...
Here is the first sample code. It's an interrupt driven irpd/remote handler. I had to change the mode of the remote to a sony format since those are the most widely documented (use 002 instead of 012). The sample will display the address(always the same) and the command (different number depending on the button pressed). You can change the main loop to do something other than display the commands received (ie: tell a bot to move). Note that software serial commands can be corrupted by the interrupt handler so you may see some glitching (I didn't but you might) when running the sample app.

_________________
Jim Frye, the Robot Guy
http://www.lynxmotion.com
I've always tried to do my best...


Expert ( offline )
Posts: 988
Posted: 2006-08-08 02:16 
Interesting, I must say. One question, this block of code makes it run in the background?
Code:
ONINTERRUPT WKPINT_3,handle_irpd
PMR5.bit3 = 1
TMA=4   ;increments on clock/256
ENABLE WKPINT_3


I understand what the ONINTERRUPT command does, but what is WKP3? Says here the intname, WKPINT_3, is:
WKPINT_3 WKP3 pin onchange interrupt
Also, what are interupts exactly? I know its a method of getting incoming data, but what is it exaactly?

-robodude666

_________________
What do you mean "NO SPOON!"????


Guru ( offline )
Posts: 2158
Posted: 2006-08-08 02:59 
robodude666 wrote:
Also, what are interupts exactly? I know its a method of getting incoming data, but what is it exaactly?

An interrupt forces a code branch to a sub-routine in response to some external hardware or software stimulus. The sub-routine is called an interrupt handler (or interrupt service routine) and takes great care to preserve registers, flags, and the stack because when it returns the code that got interrupted never has any idea the branch took place. Usually interrupts can be masked by hardware bits or flags to select which ones are enabled to be serviced. This gives the main program code the ability to pick and choose which hardware events it wants to service in the background (transparently/invisibly) and which to manually service as part of the main loop, or even ignore completely.


Expert ( offline )
Posts: 988
Posted: 2006-08-08 03:09 
So, basically it is a way for a background process to see if theres incoming data from a pin and if there is, it will jump to the label it was told do the stuff in the label and then return where it was originally? That is pretty bad ass I would have to say.

_________________
What do you mean "NO SPOON!"????


Guru ( offline )
Posts: 2158
Posted: 2006-08-08 03:46 
robodude666 wrote:
So, basically it is a way for a background process to see if theres incoming data from a pin and if there is, it will jump to the label it was told do the stuff in the label and then return where it was originally?

Actually the pin changing state (for example) is typically what initiates the background process. It doesn't have to be a pin, it can be lots of things like timers expiring, a serial port sending the last bit of a character, a packet of data arriving from a network, anything that dedicated hardware might be doing that needs some software attention.
Yes it is a very powerful tool, but but by the same token it can be a massive headache when there is a bug in the handler routine.
;)


Guru ( offline )
Posts: 1667
Posted: 2006-08-08 04:55 
Quote:
Yes it is a very powerful tool, but but by the same token it can be a massive headache when there is a bug in the handler routine.


I hereby second that motion.
>.<"

Interupts are lovely, but don't be like me and try to write your first micro program with them.
It was...
brutal.
:lol:

_________________
Disclaimer: The above person does not claim to have knowledge pertaining to the following subject: anything. Thus, said person may not be held liable for any mishaps/explosions that his advice incurs.


Guru ( offline )
Posts: 2158
Posted: 2006-08-08 04:59 
well, what did you put the bug in it for then?


User avatar
Guru ( offline )
Posts: 3580
Posted: 2006-08-08 05:02 
Yeah Nick, what he said-----^ :P

_________________
Mike

The robotics nut.


User avatar
Expert ( offline )
Posts: 628
Posted: 2006-08-09 06:44 
robodude666 wrote:
Interesting, I must say. One question, this block of code makes it run in the background?
Code:
ONINTERRUPT WKPINT_3,handle_irpd
PMR5.bit3 = 1
TMA=4   ;increments on clock/256
ENABLE WKPINT_3


I understand what the ONINTERRUPT command does, but what is WKP3? Says here the intname, WKPINT_3, is:
WKPINT_3 WKP3 pin onchange interrupt
Also, what are interupts exactly? I know its a method of getting incoming data, but what is it exaactly?

-robodude666


Setting bit3 of the PMR5 register sets pin 3 as a Wakeup(when pin goes low) interrupt instead of a normal I/O. The WKPINT_3 is the Wakeup3 interrupt. Ther are 6 possible wakeup ints(0-5). I used WKPINT_3 because Jim has the signal from the IRPD wired to pin 3 and I didn't want to change his wireing since he's making an assembly guide for this as well.

Also, TMA=4 is setting the TimerA timer to increment every 256 osc pulses(osc runs at 16000000 hz) so TimerA increments 62.5 times ever millisecond. I'm using TimerA to time the pulse widths coming from the Sony remote(technically it's a universal set to a Sony model).

The Sony singal format is a 2.4ms start pulse(low at the AtomPro's pin) followed by .6ms idle(high), then 12 data pulses(1=1.2ms low folled by .6ms high, 0=.6ms low folled by .6ms high).

So given that, there are three possible times between any two lows. Either 3ms,1.8ms or 1.2ms.

In TimerA time that is 187.5, 112.5 and 75.

I calculate the time from one low to the next by subtracting the last value of TimerA from the next value of TimerA. I then determine if a bit is either a start or data bit. If it's a start I initialize the handler. If it's a databit I load it(0 or 1) into my data variable(irpd_data). When I've received 12 bits I copy the command(low 7 bits) into the Command variable and the Address(high 4 bits) into the Address variable.

Note that Sony's system actually sends out 13 pulses(1start 7command and 5address) but I only read 12(1start 7command and 4address) because this way I use very little time in the interrupt. In order to get that last bit I would have to actually wait inside the interrupt for the length of all pulses(minimum of 16.2ms).

Since the 5th bit of the address bit is almost never used I'm not going to worry about it. Just so you know the only loss is that the address is only good for 16 devices(addresses) instead of Sony's full spec which supports 18 devices(assuming you found a remote that supported all 18 possible devices).

Nathan


User avatar
Guru ( offline )
Posts: 9258
Posted: 2006-08-17 23:59 
I'm having difficulty with the program. I added some simple servo pulse commands to the main loop and it's acting up. Here is the code.
Code:
ONINTERRUPT WKPINT_3,handle_irpd
PMR5.bit3 = 1
TMA=4   ;increments on clock/256
ENABLE WKPINT_3

lasttime var long
currenttime var long
datacount var byte
irpd_data var word
command var byte
address var byte
ServoP var word

lasttime = -1   ;indicate next data should be a startpulse
low 15

main

pulsout 15,servop
pause 20

   if(command<>0xFF)then
'      serout S_OUT,i115200,["Address = ",hex address,13,"Command = ",hex command,13]

   if (command = 0) then
      servop = 4000
   endif
   if (command = 1) then
      servop = 3000
   endif
   if (command = 2) then
      servop = 2000
   endif

      Command=0xFF
   endif
   goto main
   
handle_irpd
   currenttime=TCA
   if(lasttime<0)then
      datacount=0
      lasttime=currenttime
   else
      datacount=datacount+1
      if(currenttime<lasttime)then
         lasttime=lasttime-256
      endif
      lasttime=currenttime-lasttime
      irpd_data=irpd_data>>1      
      if(lasttime>175 AND lasttime<195)then
         irpd_data=0
      elseif(lasttime>100 and lasttime<120)
         irpd_data.bit10=1
      elseif(lasttime>65 and lasttime<85)
         irpd_data.bit10=0
      endif
      if(datacount=12)then
         lasttime=-1
         command = irpd_data&0x7F
         address = irpd_data>>7
      else
         lasttime = currenttime
      endif
   endif   
   resume


It apears to work at first. When I press the [2] button it moves to the center, when I press the [1] button it moves to the +45° position, when I press the [3] button it moves to the -45° position. It does this fine for a while then only the [1] button will move it to the correct place, and the one or both of the other two will not work. I also notice some jitter in the servo when pressing and holding the buttons.

Maybe I'm doing something wrong. :(

_________________
Jim Frye, the Robot Guy
http://www.lynxmotion.com
I've always tried to do my best...


Expert ( offline )
Posts: 988
Posted: 2006-08-18 00:13 
Jim doing something wrong? :o! Impossible :lol:.

So, as far as I understand, it works fine... But after you press the [1] button (center the servo) the [0] and [2] buttons don't work?

Not sure what the issue is, but try and make it print out the address and command for every time it goes through the main loop. Also, isn't command a hex value? not a dec value? Or you can have a hex value but still use it as a dec?

Another suggest you can try. Instead of making it just an if then statement, try and if elseif statement. make the whole thing a big elseif statement.

Also, could it be possible that so much IR light is coming from the remote that the IRPD is flooded with it and understands it wong?

Try this for the main loop:

Code:
main
   pulsout 15,servop
   pause 20
   
   if(command <> 0xFF) then
      serout S_OUT,i115200,["Address = ",hex address," ","Command = ",hex command]
      if(command = 0) then
         servop = 4000
      elseif(command = 1) then
         servop = 3000
      elseif(command = 2) then
         servop = 2000
      endif
      serout S_OUT,i115200,[" Servo Pulse = ",dec servop,13]
      Command=0xFF
   endif
goto main


That might work. Only reason I can think of for why it doesn't work anymore is that the command the IRPD is getting is not the same as before. Try that out, make sure its connected to PC so it can print out the stuff. I have never tried running a programming in MBasic so sorry if I am wrong about the syntex. I am guessing that serouting 13 to S_OUT prints a \n.

Oh, and uhhh question. What does
command <> 0xFF
do? I forgot what <> means >_<''

_________________
What do you mean "NO SPOON!"????


User avatar
Guru ( offline )
Posts: 3580
Posted: 2006-08-18 00:15 
What if you try this?

Code:
servop = 750 '<----- Added

main

Command=0xFF '<---- Added

pulsout 15,servop
pause 20

   if(command<>0xFF)then
'      serout S_OUT,i115200,["Address = ",hex address,13,"Command = ",hex command,13]

        if (command = 0) then
        servop = 4000
        endif
        if (command = 1) then
        servop = 3000
        endif
        if (command = 2) then
        servop = 2000
             else goto main '<-----Added
        endif


      'Command=0xFF      '<----- possibly take this out ?
   endif
   goto main


This is what I would try. I really am not sure. Let me know what results this gives.

_________________
Mike

The robotics nut.


Last edited by SN96 on 2006-08-18 00:42, edited 5 times in total.

Expert ( offline )
Posts: 988
Posted: 2006-08-18 00:24 
Hmm, ok. <> is not equal. same as != if I understand correctly.
In that case, I don't think it will work. You need to set the command to 0xFF so that it won't go through the if statement again. Well, actually. Won't matter since 2 is != to 0xFF =/ so nevermind about that.

Oh, wait, you took it out of the if and put it at the top. What is your reasoning behind that? Wouldn't it always skip the if statement if you have it equal to 0xFF at the beginning? If I understand, Jim is using an inturrupt which brings him back to the what ever line he was before he pressed a button on the remote. If he was at the top of main or at the bottom of main after the endif then he would never be able to control anything because it would always be set to 0xFF? Wouldnt it? Just wondering. Get what I mean though?

_________________
What do you mean "NO SPOON!"????


User avatar
Guru ( offline )
Posts: 3580
Posted: 2006-08-18 00:27 
robodude666 wrote:
Hmm, ok. <> is not equal. same as != if I understand correctly.
In that case, I don't think it will work. You need to set the command to 0xFF so that it won't go through the if statement again. Well, actually. Won't matter since 2 is != to 0xFF =/ so nevermind about that.

Oh, wait, you took it out of the if and put it at the top. What is your reasoning behind that? Wouldn't it always skip the if statement if you have it equal to 0xFF at the beginning? If I understand, Jim is using an inturrupt which brings him back to the what ever line he was before he pressed a button on the remote. If he was at the top of main or at the bottom of main after the endif then he would never be able to control anything because it would always be set to 0xFF? Wouldnt it? Just wondering. Get what I mean though?


huh? I have no idea what you are talking about

_________________
Mike

The robotics nut.


User avatar
Guru ( offline )
Posts: 3580
Posted: 2006-08-18 00:34 
Note: I went back and made some quick changes to the code. Sorry...

>>>Edit
This wait is killing me, Jim.... Are you done yet?.... :shock:

_________________
Mike

The robotics nut.


1, 2

All times are UTC - 5 hours [ DST ]. It is currently 2014-08-29 20:25
Feedback Form
Feedback Form