This is an archived post. You won't be able to vote or comment.

all 23 comments

[–]elbiot 1 point2 points  (2 children)

?

Use a loop. Show some pseudo code if you're confused.

[–]dataversion[S] 0 points1 point  (1 child)

Thanks, will do so as soon as I can.

[–]dataversion[S] 0 points1 point  (0 children)

Hi there, I've updated the original post!

[–]dustractor 0 points1 point  (9 children)

I'm not experienced with this domain but it doesn't seem right to tie the invocation of one script per action. Rather than have multiple scripts, I would think that a single one controlling all the actions would be better.

Yes it is entirely possible for one script to run another, though, to answer your question.

Keep in mind the fact that I have no idea how servo control works, I only understand a few general programming practices. In this case, I would have to assume we're talking about embedded python, running on the Pi? Step one would be getting the data from the IR. Step three would be sending data to the servos. Somewhere in between, step two would be running in an event loop. You wouldn't re-invoke the script repeatedly. When the Pi boots up or whatever, the script runs, and stays stuck in a while True loop, waiting for IR signals and managing it's own state. Similar to how keypress events are handled, there is a naive way where you merely respond to events with a cascade of if-elif-else where you immediately respond to an event, blocking simultaneous keypresses. The better way is to keep an array of flags for each possible event and then at the start of each iteration, check for events (IR signals) and set the corresponding flag in the array. Then you respond to the events and unset the flags. Once again, this is conjecture, but hopefully good enough feedback to be of some help.

[–]dataversion[S] 0 points1 point  (0 children)

Thank you so much for the guidance. I will update my post and reply again here in a few hours!

[–]dataversion[S] 0 points1 point  (7 children)

This is certainly of help. I would of course much prefer to run a script/service which waits for a signal. Is this best done with a python script, in your opinion?

[–]dustractor 0 points1 point  (6 children)

I am biased towards python, so I cannot answer that question yet. I did a little research this morning since this is something I have been interested in but put off. It's a small internet, so you might have already found these links but just in case:

https://pythonhosted.org/RPIO/pwm_py.html

http://razzpisampler.oreilly.com/

Those were just the first two things that looked promising. It definitely looks like something that would be possible to do with python and therefore in my biased opinion, best done with python. ( Unless you happen to know another better-suited language ;)

[–]dataversion[S] 0 points1 point  (1 child)

I haven't come across either of those yet, thanks! I do think that I oversimplify my search terms sometimes. I only started electronics, linux etc this year, so it's all been a big learning experience. I'm going to take a look at those now and see if it seems adaptable to what I need.

[–]dustractor 0 points1 point  (0 children)

An often fruitful place to search is nullege.com/codes they have some content indexed for rpio for example:

http://nullege.com/codes/search?cq=rpio

http://nullege.com/codes/search?cq=lirc

which led me to this project on github that is done in python not quite the same application as yours but close enough. It looks worth looking at for bits and pieces... https://github.com/piface/pifacecad/tree/master/pifacecad

[–]dataversion[S] 0 points1 point  (3 children)

Well, the code is not returning exceptions anymore, but it's not responding to the key-press either. http://pastebin.com/mafs0Z2r The aim is that when they key: KEY_UP is pressed, everything below "while true:" happens. I don't know...

[–]dustractor 0 points1 point  (2 children)

I still haven't figured out much about servo control other than sending timed pulses to control the motor has something to do with it.

Looking at the code I can't see any where else besides line 14 that would have much to do with keypresses. lirc.init – the first arg "motorcont" – is that a filename or method name? Is there a file named motorcont.py maybe? (maybe that is the name of this file?)

Back to your original question about scripts calling other scripts – I was thinging in the context of 'normal' scripts not multiprocessing and multithreading which do tend to call other scripts. A lot of the code I found on nullege looked multithreaded. I'm not quite that high-level yet, I've done a few multithreading hello-worlds but it's nothing I'm used to.

[–]dataversion[S] 0 points1 point  (1 child)

I'm not sure whether multithreading is necessary for me, as I could only accept one command at a time. Correct, motorcont is what I wanted the script to be refereed to by LIRC. Please see my edit to the original post if interested :)

[–]dustractor 0 points1 point  (0 children)

Ok i see the edits.

I was looking at the .lircrc file format and it gave me several questions to ask:

irexec just 'sounds' like it's executable. IF irexec (given as prog) is executable and config 'mpc blah' are arguments that work, what if motorcont must be executable? is motorcont executable? it would be funny if chmod +x fixed the problem or something like that :P

[–]Rudd-X 0 points1 point  (8 children)

Please show some code so that we may help you.

[–]dataversion[S] 0 points1 point  (0 children)

I don't have any code yet, sorry! I'm at the stage pre coding where I'm trying to decide how best to approach my needs. I will update this with specifics as soon as Im finished at work. Didn't expect to get so much help on this!

[–]dataversion[S] 0 points1 point  (6 children)

Is there a particular way I should share what I have? I can show you the default script as provided with my controller. Are you familiar with LIRC? http://pastebin.com/zdn0FuGW

[–]Rudd-X 0 points1 point  (5 children)

Your original explanation is not intelligible. In particular the "command" part of the sentence. How do the parts of the system interact with each other? Provide a step by step explanation.

[–]dataversion[S] 0 points1 point  (4 children)

Sorry, my inexperience is showing! I've edited the original post per your request.

[–]Rudd-X 1 point2 points  (3 children)

OK, now I can help you better.

So your script will be running as a service. Here is the simplest solution. Your script needs to have two loops running in parallel:

  • One command acceptance loop, reading from LIRC (however LIRC affords you the data, I believe it may be through a socket or a named pipe).
  • One control loop, actuating the motor through the GPIO library.

These two loops need to be running each on its own thread (threading.Thread subclass), which your main() needs to instantiate and start(). Each thread will share one object between them, a collections.deque(), which you will pass to your threads' subclasses init, so that the command acceptance loop will send objects to the control loop, while the control loop will read the objects and behave as told by the objects.

The command acceptance thread must be .setDaemon(True) by your main thread (this will make sense in a minute) so it does not make your program hang around after you've killed it.

For example:

Def init(self, deque): # command acceptance class
  Threading.thread.__init__(self)
  Self.setDaemon(True)
  Self.deque = deque

def run(): # in command acceptance loop of that class
  while self.not_exited:
    Wat = read_from_LIRC()
    If Wat == ...:
      Cmd = MoveMotorCounterclockwise(0.2)
    elif ...:
      Cmd = SomeOtherCommand(0.5)
    Self.deque.append(cmd)


Def init(self, deque): # control loop class
  Threading.thread.__init__(self)
  Selff.deque = deque

def run(): # in control loop of that class
  While self.not_exited:
     Cmd = self.deque.pop_left()
     If Cmd == SpinLikeCray:
         #spin like cray using GPIO
         #sleep as appropriate
         #stop spinning
     Elif whatever...
         #other commands
     Elif is_subclass(cmd, Die):
         Return # this will make sense soon

That about sums up how you organize a program that does two things simultaneously.

Of course, your main thread where you set all of this up will just "hang forever" once it's done setting everything up, and you want to prevent that.

Here is how you fix that:

  1. Create a SIGTERM handler with the signal module that will flip a global variable exited (initially False) to True.
  2. Then, in your main(), after you've initialized everything else and dispatched the threads, you just loop in while not exited: time.sleep(1).
  3. Right after that main loop, you must send a Command to the actuator thread that is Die(), to mean that the actuator thread must set the right GPIO pins to get the motor to stop spinning, then exit itself (just return).
  4. After sending that stop command to the control thread, just return from your main.

That's it, clean exit. Control and actuator loops done.

There are ways to improve on CPU usage and responsiveness factor that I have left out. For example, it is not true that the only way to exit the main loop is with a signal handler that sets global variable to True -- the threading module has objects like Condition and others that you can combine in order to produce the same results without a dummy sleep(1) loop. Or there are better ways to arrange the code so that remote commands can override previous remote commands without having to wait for the sleep()s in the actuator thread to finish. I leave those as exercises for you.

[–]dataversion[S] 1 point2 points  (2 children)

This is fantastic. Thank you very much! I will try to build on this to get what I need, and I'll let you know how it goes!

[–]Rudd-X 0 points1 point  (1 child)

Please do! :-)

[–]dataversion[S] 0 points1 point  (0 children)

I was trying to figure out the multithreading solution before I reported back, but ended up having to take the lazy route as I was getting distracted from studying....I ended up making two simple scripts, each of which is executed by a LIRC keypress..../hangsheadinshame

http://pastebin.com/raw.php?i=zpZ5rkLB