From: Thorsten R. <sch...@un...> - 2002-06-02 15:26:09
|
Hi, Sorry, I made the same error as real nowhereman - I sent something that was intended to go to the list to realnowhereman only. Here are the mails: Hi, > > I think it's best to do the sensor input using portals. > > I agree. This should be a good way of ensuring that the simulation tasks are > adequately distributed between the engine (world geometry, environment data, > collision control etc.) and the bots (movement, actions, reactions to > environment). Sorry, I don't understand the notion portals. Can somebody provide a link or a short explanation please? I also don't understand, why some 3D data should be used as the universal datatype. I think, if we use C++ we should definitly use template methods for data transport. The data can be handled by a specialized class that stores data using void pointers, has some internal data typing mechanism to handle invalid module linking gracefully and allow access to the data through template methods. This has the advantage, that it can be completely encapsulated in that data handling entity, it can be made safe and it can be made efficient. But the real advantage is that this way, you can transparently pass objects or any built in types between modules. If you pass images you can just use the image format of your favorite image processing library; same for speach; and if you just want to pass a bool or double, great, pass that, no problem. Client programmers only have to make sure, that each of two communicating modules agree on what is passed between them. *** I completely agree with realnowhereman on the machine code issue. If anybody needs something like that, an interpreter should be used and plugged in. Anything else would presumably break the project in more than one way ... *** In my last mail I wrote about a concept to control program flow (start with motors work through the links to the sensors and back ...). I thought a lot about that. I'll call the approach I described in my last mail the pull technic because you start with the motors and they'll "pull" the data all the way through the module graph. The two alternatives that come to my mind are layered execution and the "push" technic. With the later you start at the sensors and they push the data to the next order of modules and so on until the motors are reached. The push technic allows for a completely different approach to controllers. One big advantage is, you only need to process stuff that really gets new inputs. I.e. sensors only push data when they actually have new data. This could also be used asynchronously with event driven sensors. And it much morwe closely resembles what's happening inside our heads. We should not completely ignore the push approach and I think push and pull can be simultainously implemented in the base hirarchy without much effort and without adding too much confusion for client programmers. Layered execution means that modules are ordered into layers. Sensors would be in the top layer, motors in the botom layer, all other modules in between. Execution starts with the top layer and works serialy through all layers to the bottom. This would be easy for us to implement and we can think about keeping it in mind for later versions of BorgAsm, but it makes designing the controller awkward for client programmers, because it adds complexity to their task. Thorsten Hi, > The push model seems the most sane to me out of two reasons - it's close to > biology (reaction to stimulus) and it would (probably) create less CPU load > than the pull model. A layered hierarchy is implementable, but I agree with > Thorsten's critique - it's too awkward. The push model indeed looks more biology-like. But biological systems are massively parallel while computers are serial. Once you start pushing in a computer you'll go all the way to the motors before another sensor event is taken into account. To avoid that, one would have to frequently check for new events, creating much overhead. And still it's unlikely that you'd get anywehere with this approach, because computers are so fast. Brains are very, very slow and massively parallel. The dynamics of asynchronous events probably play a crucial role. But these dynamics are not at all understood, and we can't hope to change that with BorgAsm. Thus the push approach can only be used for simple Reflexes, and might be very usefull there. With the pull approach you can handle problems, where you need information from many sensors simultainously (e.g. higher coordination problems in multi limbed robots). Thus I think, we should implement both. The CPU load will presumably be almost the same in both approaches. In push mode each module has to make one function call for each output it generates. In pull mode each module has to make one function call for each input it requires. Inputs and outputs will obviously mach numbers. In push mode a push call by a sensor won't return until the motors are reached and the stack has worked back to the sensor. Vice versa for pull mode. The interface of the base class for nodes could contain five things: A pull method, a push method (both private), an input data member object, and output member data object and an abstract method where client programmers put their implementation of the module (the later three protected). Pull will call pull methods in upstream modules, write the result to the input member once the upstream calls returned, then call the implementation and finally return the output data member. Push will write the output to the downstream input data object, call the downstream implementation and finally call push An example of how I imagine this to work in C++: Node : public ... { protected: InputDataContainer in; // smart container of InputData objects OutputDataContainer out; // same for output virtual void implementation() = 0; // Client programmers use in to get their input and out to write // their output. Their implementation is thus not affected of // wether the module operates in push or in pull mode. private: Time t; InputLinks inLinks; OutputLinks outLinks; template<class Cont> void push(Cont inData) { in.add(inData); implementation(); for(unsigned int i = 0; i < outLinks.size(); i++) outLinks.link(i).push(out[outLinks.outPutDataIdentifier(i)]); } OutputDataObject pull(OutputDataIdentifier outId) { if(t.upToDate()) return out[outId]; for(unsigned int i = 0; i < inLinks.size(); i++) in.add(inLinks.link(i).pull(inLinks.inputDataIdentifier(i))); implementation(); return out[outId]; } }; To support arbitrary datatypes InputDataContainer and OutputDataContainer have Template methods. Sensors and motors have modified implementations of push and pull. One is public in Sensors, the other in motors. These public functions can then be called by the main loop of the program. Client programmers can choose if the want push or pull mode, they can even use both simultainously for different tasks. This is just a first coarse first draft that is meant to serve as an illustration of the lines I think along. Don't take it too seriously, the implementation might look completely different. Cheers, Thorsten |