Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shepherd Overhaul #42

Open
7 tasks
fenjalien opened this issue Apr 18, 2022 · 11 comments
Open
7 tasks

Shepherd Overhaul #42

fenjalien opened this issue Apr 18, 2022 · 11 comments

Comments

@fenjalien
Copy link
Contributor

fenjalien commented Apr 18, 2022

Coming from these comments:

Must Do:

Might Do:

  • Automagically generate mock-shepherd from shepherd
  • Rewrite robot lib
    • Encapsulated within shepherd so that the robot lib outlives the usercode.
    • As a module
    • Possibly in rust
@shardros
Copy link
Member

shardros commented Apr 18, 2022

The only way I can think to wait for start without the user code being able to init the robot lib is to be able to is to have every method of the robot lib call a "wait_for_start" which just passes if the start button has already been pressed. That way we will load the robot lib but stop normally at the first robot lib call for the start button to be pressed should you want to wait for start you would do something like the following:

import robot as R

R.bypass_wait_for_start()

R.servos[0] = 20;
R.servos[1] = 34;

R.wait_for_start()

while True:
    print(R.see())

Metaclasses or decorators can be used to wrap the API surface like this.

@fenjalien
Copy link
Contributor Author

fenjalien commented Apr 18, 2022

@shardros from your comment #38 (comment)

It would be nice if some how we could automagically generate mock-shepherd from shepherd so that it was always upto date not sure how best to do that.

I feel like this should be possible using some form extreme of monkey patching.

Reset is hacky but its one function.

Maybe a simplier way would be to have shepherd instanciate robot and then you just do:

import robot as R

R.motors[1] = 100
 R.see()

The robot object lives within shepherd and is the hardware interface. The robot lib just exposes the shepherd.robot namespace. Then having a reset call on the robot object which is persistant with shepherd isn't such a bad thing. Its just the robot API which is our "HAL". No messaging required.

So the import robot as R is just a proxy to initiate a robot object in shepherd.robot? That sounds just as bad if not worse. The usercode runs as a seperate process so by importing robot which then imports the object you'll be rerunning the init code thats already been run in shepherd. I just feel uneasy allowing two seperate processes uncontrolled mutability over physical state.
Now that I think about it I'm pretty sure theres some form of lock over the gpio for processes. So the robot object living for as long as shepherd runs would clash with running usercode. We haven't had much trouble with this as shepherd destroys the robot object after reseting state.

It even makes the usercode simplier as there is no R = robot.robot() which is a nothing line which nobody understands anyway.

It does feel weird but it does look nicer.

Not sure how to do wait for start

I see no problem in having the robot initiate when import robot as R is called, then allowing the usercode to do whatever it likes. For competition code we just require that the R.wait_for_start() function is called before the robot actually moves.

I'm not 100% sold on robot-rs having the robot lib in the same language as the usercode and not compiling across means that people can and have reached into the robot lib to do all kinds of fun stuff.

Yea fun stuff is fun but theres still a danger of breaking stuff which rust would prevent. As long as we have an open enough API that allows users to do what they want and still stop them when they might break things, we should be okay. Having a "don't process" option on R.see() would be a start.

I do really like shepherd-fast though, shepherd-rs might be valuable if we ever do a bare-metal brain though I'm not convinced that is useful atm.

Totally fair it was a pain to write, i think.

@fenjalien
Copy link
Contributor Author

fenjalien commented Apr 18, 2022

What do you think of also overhauling sheep to be a vscode extension? Personally as long as sheep works and can be served staticlly I don't want to touch it.

but it seems possible to host vscode locally now

and it might be possible to get blockly working in vscode

@shardros
Copy link
Member

shardros commented Apr 18, 2022 via email

@shardros
Copy link
Member

So the import robot as R is just a proxy to initiate a robot object in shepherd.robot? That sounds just as bad if not worse.

There would be just one object in shepherd.robot which would be singleton. The API interface would span across the different processes which are used using locks like normal threaded code. We don't need to do anything high efficiency as there would effectively never be any contention so something fool-proof like bellow would work:

while (resource.busy == true) pass
get_mutex()
set/read value
release_mutex()

Not sure we need to be too concerned about concurrency. All robot state is stored in shepherd.

@shardros
Copy link
Member

shardros commented Apr 18, 2022

Now that I think about it I'm pretty sure theres some form of lock over the gpio for processes

GPIO would only be used by shepherd

@shardros
Copy link
Member

It would also make running the user code just a bit faster as we wouldn't have to wait for the cameras to init etc each time which takes a second or so

@WillMunns
Copy link
Contributor

Could the majority of shepherd and the robot library be moved behind a socket interface?

If you did that then sheep "go" would just message the socket, as would the start button. We could poll the relevant socket for state of GPIO, battery voltage etc. This would also open up the possibility of remote control. You'd need a different command to commit code for execution which would reload the usercode to complete the tasks that sheep does on run. A socket interface would also allow us a global "ABORT" from the arena, (as well as global "start", which we should not ever use because this responsibility has to sit with the competitors).

Sheep is currently uncluttered. I wonder during any refactoring if the status of battery, servos, motor power, GPIO would be useful to expose for debugging. They would also make the arena status more interesting.

@shardros
Copy link
Member

shardros commented Apr 19, 2022

Could the majority of shepherd and the robot library be moved behind a socket interface?

I prototyped sending the image over a socket which I think would be the only remotely difficult thing in 2020: https://github.com/shardros/playing-with-sockets/

battery, servos, motor power, GPIO

I think so. It would decouple issues between software and hardware. "X is not working" would be obvious weather the software was or was not setting it to a value.

If it is too much clutter then we could always hide it

The more I think about it the more I think that the robot object should live within shepherd. The only reason why we do R = robot.Robot() is because SR does it and they have to do it because if the user doesn't run init then nothing will because they are the only thing which is running on that system.

@WillMunns
Copy link
Contributor

its quite a effective way to force the robot to block on start push without telling the students they need to add extra code, so behaviorally it might still be worthwhile. The way that you have an "object" to operate on is quite nice when describing to people whats happening. From a user POV I think we should keep the same interface, but modify how it works in the background so that GG crashes don't cause user code crashes and vise-versa.

Internally you don't have to pass an image over the socket interface, none of our competitors are really going to try to wrap their own image recognition, so you could pull all of the OpenCV code outside and have a "when socket is opened, take picture, digest, and spit out marker details". Its still nice for the arena to collect images this way, but we can do that with websockets, even if websockets are just saying "image.jpg?". We would end up with less flashing if we alternated though image<0-9>.jpg?. As the image is served over HTTP, if a team really wanted to they could fetch the image the same way.

@shardros
Copy link
Member

shardros commented Apr 19, 2022

its quite a effective way to force the robot to block on start push without telling the students they need to add extra code

I agree, the default should be to have no additional code. I am suggesting that a call to robot.X will block untill the start button is pressed. A way of implementing this:

class Robot():
     def wait_for_start(func):
          while not self.start_button_has_been_pressed:
              pass

    @self.wait_for_start
    def see():
          # Do stuff here

We would need some way of disabling this behaviour so people could do things before start if they wanted but it makes the user code simpler. This gets rid of R = robot.Robot() which is basically asking the user to do configuration which we can do for them.

Internally you don't have to pass an image over the socket interface

I wasn't even really considering people doing their own vision stuff. Its more so we could write the bytes directly into where the image is in sheep rather than say "hey go get a new image you've never seen before" thereby getting rid of all the flickering even when R.see() is called.

The way that you have an "object" to operate on is quite nice when describing to people whats happening.

80% of GCSE students in RC do not know what an object is and for the 10% which this is explained to you still have an object.

Its just we make a robot object for you and then give it to you with import robot. robot is still an object here just not one the user instaniated but one which is handed to them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants