Closed wm closed 11 years ago
Is there a reason you're reconnecting to the servo? When the Components::Servo
instance is created, after_initialize
runs just once and then the Servo object keeps track of the position. Are you destroying that object and creating another?
I have two reasons
I am hoping to make it work for multiple programs running together but failing that approach I will probably use a client server approach. That said point 1 above still stands.
There may well be a limitation that would not make point 2 usable. I just have not read too much of the Dino source yet.
It's not just the behavior inside the Servo
instance you need to worry about. Reconnecting to the board will reset the position of the servo for a couple other reasons:
In any case, the solution to your second problem also solves your first, so let me explain that.
Dino relies on Ruby either opening a serial connection or a TCP socket to talk to the board. The Arduino sketches are written to use exactly one of either. So having multiple users (or applications) accessing the board directly, is tricky. You'd have to keep disconnecting and reconnecting.
When the board gets reset upon connection, this lets Ruby keep track of, and be sure of, the state of all the hardware on the board. In other words, once connected, the instance of Dino::Board
assumes it has total control of the board and any communication with the board has to go through it. I don't know if @austinbv agrees, but I think this should be a fundamental design principle for this project.
Imagine if you removed this "reset on connect and then keep track of everything" behavior. One user connects and turns an LED on. Another user connects, turns it off. The first user's code is still running with the assumption that the LED is on, but it isn't.
You could create a system at the board level to let multiple users connect and push updates about the hardware state to them, but there's still the fact that serial connections and TCP sockets are both 1-1 connections. Are users going to keep trying to connect until the board is available and then disconnect as soon as they've written/read what they need? Also, the whole point of this gem is to write less Arduino code.
Some kind of messaging system IS what you need, just not at that low level.
I currently have a single Arduino running Dino with 4 separate applications using it:
All of it runs on RabbitMQ. A 5th Ruby script, a daemon, makes the actual connection to the board, offers up a custom API via a message queue and then just waits for and sends messages. It does nothing else.
The 4 applications interact with the board indirectly by exchanging messages with the daemon. So I can stop any one of the applications, make changes, and start it back up, without stopping anything else. In fact, I've rewritten the applications multiple times, but the daemon has been running, connected to the board with the same TCP connection, for almost a month.
I'm halfway done with a writeup on how this works, but it isn't very complicated. You can apply the same design to your system. Create a daemon that runs on the machine, connects to the board, and can set the position of the servo. Write the daemon in a way where you set the position by sending messages to one queue, and it then publishes the new position on another queue. Check out https://github.com/ruby-amqp/amqp/.
Since the Board
instance and the Servo
instance belong to the daemon, the daemon is always sure of the position of the servo, since it gets stored as an instance variable, and only the daemon can actually write to the board. If one user sends a message to the first queue asking to change the position, the daemon writes it to the board, and then publishes the updated position to the second queue. Once other users/applications are subscribed to the second queue, they'll be updated with the new position.
Since the daemon is always running now, and you interact with it only by sending messages to a queue, there's no need to disconnect from the board and reconnect to it when you log in via SSH, so the position doesn't get reset each time.
Wow - thanks for the thorough response. I suspected much of what you mentioned.
The queue approach is great. I will follow that path I think. I also look forward to your writeup on it. Thanks again
The after_initialize sets the servo position to the passed in option or 0. However I would like to have my servo stay in the same position upon connection and reconnection. Is there a way to do this?
I am willing to write the code to extend the servo to do this but was wondering if there is a particular approach you would like me to take.
One way may be something like this
Any guidance here would be great