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

Add simulator for NXT #14

Closed
wants to merge 135 commits into from
Closed

Add simulator for NXT #14

wants to merge 135 commits into from

Conversation

mandaiy
Copy link
Member

@mandaiy mandaiy commented Oct 30, 2016

This commit adds a feature of simulating NXT robots.
Users of the simulator can use NxtMachineSimulator by instantiating that class.
The simulator class allows users to create simulatable version of sensors/motors by the same way
as normal NxtMachine.

tiwanari and others added 15 commits February 21, 2016 23:44
Remove timeout from ICommunicator#write and ICommunicator#read
This PR enables us to check that

the code base sent as a PR can be compiled correctly
$ gradlew check works properly (and this means tests are green)
Additionally, I changed the settings of repositories (drive/drivecommand). This makes following changes:

when the test fails, merge button will be disabled.
when owners (PILE members) push some code to develop or master, the patch will be merged into the branch after testing. If the test fails, merge process will be canceled. (I've not checked it yet, though...)

Issue #8
- Add the build status for `develop`
- Fix a typo
This commit adds a feature of simulating NXT robots.
Users of the simulator can use NxtMachineSimulator by instantiating that class.
The simulator class allows users to create *simulatable* version of sensors/motors by the same way
as normal NxtMachine.
@mandaiy
Copy link
Member Author

mandaiy commented Oct 30, 2016

According to #12, I added a simulator feature for NXT robots.
One thing I misunderstood is that users manipulate robots via Sensors/Motors.
So I implemented some simulatable sensors/motors.
Stay tuned for Ev3 and Pile version.

TODO: add test cases, general controllers.

Please feel free to leave any opinions.

@mandaiy
Copy link
Member Author

mandaiy commented Oct 30, 2016

Added a simple use-case in drive.
You can run a program on your emulator.

@tiwanari
Copy link
Member

tiwanari commented Oct 31, 2016

One thing I misunderstood is that users manipulate robots via Sensors/Motors.
So I implemented some simulatable sensors/motors.

I see. The workaround looks good to keep loose couplings :)

Copy link
Member

@makotoshimazu makotoshimazu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments are based on my comment below.
#12 (comment)

@@ -0,0 +1,38 @@
package com.pileproject.drivecommand.machine.device.input.simulation;
Copy link
Member

@makotoshimazu makotoshimazu Nov 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel these objects are just for mocking. What do you think about moving to com.pileproject.drivecommand.mock.machine.device.input to clarify which classes are available for testing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't know which is better to be honest.
@tiwanari might have opinions on this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, at first, let me confirm options. They are;

  • com.pileproject.drivecommand.machine.device.input.mock (as followed the naming discussion)
  • com.pileproject.drivecommand.mock.machine.device.input

right?

Copy link
Member

@tiwanari tiwanari Nov 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, I agree with @amiq11's idea in the case we use these classes just for testing because users can easily understand where these mocks are placed.
Let's regard the mock package as a small repository for mocks (It may help some developers who implement a communication for other robots).

If some classes, especially *Controllers, in this PR are general enough (i.e., it can be used not only for such testing/mocking but also for other purposes), we shouldn't move them into the mock package.

import com.pileproject.drivecommand.machine.device.port.InputPort;
import com.pileproject.drivecommand.model.ProtocolBase;

public class SimulatedColorSensor extends ColorSensor {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel Mock is more common word for this purpose. How about MockColorSensor?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.

private int illuminance;

public SimulatedColorSensor(InputPort port, ProtocolBase protocol) {
super(port, protocol);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is super necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's necessary because the superclass does not have a default constructor and then the subclasses must call one of its superclass's constructors.
Welcome to Java!

private float green;
private float blue;

private int illuminance;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding m before each members for keeping the naming convention?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah yeah gotcha gotcha...

@@ -0,0 +1,29 @@
package com.pileproject.drivecommand.model.com;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about moving this class to com.pileproject.drivecommand.mock.model?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the first reply

/**
* Null object of {@link ICommunicator}.
*/
public class NullCommunicator implements ICommunicator {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename this to MockCommunicator if you agree with the "mock" prefix.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

K.

import com.pileproject.drivecommand.machine.device.port.InputPort;
import com.pileproject.drivecommand.machine.device.port.OutputPort;

public class NxtMachineSimulator extends NxtMachine {
Copy link
Member

@makotoshimazu makotoshimazu Nov 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this class could targets not only NxtMachine but all classes derived from MachineBase.
We can move this class to com.pileproject.drivecommand.mock.model, for example, and can also implement MockMachine inheriting MachineBase.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once I thought exactly same thing as you thought.
But users of this library might use only one of the machines in this library and
in that case the corresponding mocking class has to be on the line of inheritance of the machine.
So we'd better to provide mocks for the every machines.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding, MachineBase should be the interface exactly for such purpose when we designed this library. User's program should handle MachineBase in their codes except for the factory class (currently it's NxtController, right?).

But users of this library might use only one of the machines in this library

I know there is such case, but this library should assume what I mentioned above. Additionally, I'm wondering if there is benefit when users directly use the derived classes like NxtMachine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your opinion seems right.
One thing which made me confused was that NxtController takes NxtMachine as its constructor argument, which seems to have to be MachineBase.
And now I feel that the controller's name is misleading as it implies general enough to be able to control any nxt machines.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and NxtController is not a factory class. now MachineProvider is responsible for that.

Copy link
Member

@makotoshimazu makotoshimazu Nov 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with the actual codes, but I think NxtController should take NxtMachine because NxtController binds each port, which is Nxt(Input|Output)Port, with each device like motors and sensors.
Also, why is MachineProvider separated with the corresponding controller? In my understanding, the controller class shapes the machine. In other words, User's programs can define the model of his/her machine by implementing the controller class (ex: the machine should have two motors, and two sensors). This means MachineBase itself without controller is useless for the user's code (drive in our case). That's why I thought "(currently it's NxtController, right?).".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then the mock class has to be the sub class of the corresponding concrete class doesn't it?
if not, NxtController cannot take mocking instance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and technically machines and controllers are tied up in the provider class. it's just because for the simplicity of the implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay... let me summarize your comments.

How about making a common Mock class

Yeah, it's a reasonable way. But, what use cases do you imagine? I think we should refer some use cases (or a purpose) for each case (a common Mock class / Mock classes derived from *Machines).

I feel "Mock classes derived from *Machines" is a case that we, drive developers, come up with at first because we have separated apps and these classes will be used in the corresponding apps which require a concrete machine class as an argument for their controllers (these controllers have some naming problems as @Myusak mentioned. please see the next section).

The name, NxtController

Some problems of the name;

  • It doesn't mention about the form of NXT but, in drive, the class specifies the form/sensors/motors as @amiq11 mentioned (these controllers specify the forms). So the name is too general for the purpose from a viewpoint Maybe, we should rename it like NxtCarController if we introduce it in this library.
  • It indeed says this class controls an NXT. So, the class should take a NxtMachine or one of its children. This is a case in which we need such mocking classes, not a general mocking class.

In short...

I think this is a very complicated problem and you both are right. It depends on situations.

What we should discuss

  • What cases do you suppose with the 2 options? (i.e., what is the purpose of each option?)
  • Should we choose one of them? Or can we choose both?
  • How much should we do in this library?
    • Assuming all cases is impossible
  • Are some design changes necessary ? (In particular, as for arguments etc.)

import java.io.IOException;
import java.util.Map;

public class NxtNullProtocol extends NxtProtocol {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also can be moved to com.pileproject.drivecommand.mock.model.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the first reply

Copy link
Member

@tiwanari tiwanari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some comments. We need more discussions.

@@ -0,0 +1,38 @@
package com.pileproject.drivecommand.machine.device.input.simulation;
Copy link
Member

@tiwanari tiwanari Nov 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, I agree with @amiq11's idea in the case we use these classes just for testing because users can easily understand where these mocks are placed.
Let's regard the mock package as a small repository for mocks (It may help some developers who implement a communication for other robots).

If some classes, especially *Controllers, in this PR are general enough (i.e., it can be used not only for such testing/mocking but also for other purposes), we shouldn't move them into the mock package.

import com.pileproject.drivecommand.machine.device.port.InputPort;
import com.pileproject.drivecommand.machine.device.port.OutputPort;

public class NxtMachineSimulator extends NxtMachine {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay... let me summarize your comments.

How about making a common Mock class

Yeah, it's a reasonable way. But, what use cases do you imagine? I think we should refer some use cases (or a purpose) for each case (a common Mock class / Mock classes derived from *Machines).

I feel "Mock classes derived from *Machines" is a case that we, drive developers, come up with at first because we have separated apps and these classes will be used in the corresponding apps which require a concrete machine class as an argument for their controllers (these controllers have some naming problems as @Myusak mentioned. please see the next section).

The name, NxtController

Some problems of the name;

  • It doesn't mention about the form of NXT but, in drive, the class specifies the form/sensors/motors as @amiq11 mentioned (these controllers specify the forms). So the name is too general for the purpose from a viewpoint Maybe, we should rename it like NxtCarController if we introduce it in this library.
  • It indeed says this class controls an NXT. So, the class should take a NxtMachine or one of its children. This is a case in which we need such mocking classes, not a general mocking class.

In short...

I think this is a very complicated problem and you both are right. It depends on situations.

What we should discuss

  • What cases do you suppose with the 2 options? (i.e., what is the purpose of each option?)
  • Should we choose one of them? Or can we choose both?
  • How much should we do in this library?
    • Assuming all cases is impossible
  • Are some design changes necessary ? (In particular, as for arguments etc.)

@tiwanari tiwanari force-pushed the develop branch 4 times, most recently from 847b676 to 1f05cc7 Compare December 23, 2016 03:53
@tiwanari
Copy link
Member

Oh, because of #19, this PR has a lot of diffs now...

@mandaiy Please take a look on this.

@mandaiy mandaiy closed this Jun 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants