-
Notifications
You must be signed in to change notification settings - Fork 19
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
Sub input parameters & logic #13
Comments
Sorry accidentally pressed submit button... |
Hi! Im glad to hear that you want to recommend my EV3Basic to more
students.
But unfortunately I can not do much of the things you requested. Since the
whole thing is constructed on top of Small Basic I must live with its
restrictions. There is just no way to create proper functions and it is
also not possible to split a program into seperate files. I thought about
providing such features in my compiler as extensions. But then we would
have two incompatible systems and this would just not be worth it.
About boolean operations: Again the limits of Small Basic forbid to make
good use of this. All comparator operations ( = >=, etc) can only be used
inside an if or while, so there is no real use for boolean operators.
But maybe you think about some bit-manipulation operations that would work
on multiple bits at a time? Like shift, not, xor, etc. ? If you make a
specific proposal, I could provide these as numerical functions in a
library object.
Reinhard
Am 28.12.2017 10:44 schrieb "LaiYanKai" <notifications@github.com>:
… Hi. I am an undergraduate and have extensive experience with EV3G. Im
trying to introduce EV3 Basic into my high school but I have some
problems...
1.
there is no xor or not logic operators in ev3 basic, would it be
possible to add it into the library, or do I not know something?
2.
in designing modules for use in competitions, for example pid
linetracing, and particular those with many input parameters, I have to
write a chunk of code just to get it set up. This is because i have to
write the variables used as parameters, and each variable takes up a line
of code. Would it be possible if we can do it the way u did to your library
functions (one liner)
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#13>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AKaD1J663CVC9mzC19CqPF3mKtGAmGtrks5tE2MTgaJpZM4ROKwA>
.
|
Hello! Thanks for the quick reply.
|
I take back my word on the bit length. I realised if i flipped the bit around so it starts reading the MSB first, that would still be accomplishable if a numeric type is used. So yes you are right pls use an intermediate numeric type? Also I would like to add a method that reverses the order of the bits. Thats because some beginners may find it easier that way, if for some reason part of their program parses it from right to left and another part from left to right... |
Imo if you are able to create the wrapper function for the muti parameter functions, it would greatly improve the useability of the program for competitons because it is lightweight and incredibly fast. One reason why i hate using ev3g is that a decent program lags the computer by a great amount, and graphic drag and drop really isnt the way to go for some high school students. Ev3dev is immensely powerful but the time it takes to upload files and run them is too long for students to have enough time to debug their programs. The other consideration is ev3basic, which imo is quite powerful, lightweight and fast, but the only problem is the code overhead for using user created functions and the logic operations, which imo isnt too hard to fix for u... i rly hope u can fix the issue, because it would greatly enhance its useability for competitions and its status as the next step for students who have mastered graphical programming. |
About bit manipulation: It would make sense to privide this functionality in a library with functions to perform the standard bitwise functions on normal numerical types. The compiler for "brick" mode only supports 32-bit floating-point numbers, and the programms running on the PC handle everything as strings and convert them to 64-bit floating point numbers as needed. So the limiting factor is the "brick" mode with its 32-bit floats. While a standard 32-bit float has 23 bits as mantissa, only that many bits can be squeezed into a single value. For the sake of consistency with other things that treat the numbers as bits - mainly the I2C-communication features that are byte-oriented and the raw sensor readouts - I would propose to do the bit-manipulation also on single bytes (8 bits). |
About the suggested wrapper function: ' set up the function and the wrapping ' call the function It is necessary to use the proper CallX - method with the correct number of parameters endocoded into the name. All the parameter and result passing will be done using global properties, so it is impossible to have recursive function calls or even functions calling other functions. This would also be made impossible by the inner working of the EV3 byte code interpreter. But all in all, you can create functions that can be called in a one-liner and the result value can be immediately used for further purposes. M.C2(DoSomething, 4,5) |
I just realized, that I can not make these callback-properties as arrays. So setting up the function would more look like Module.Function = DoSomethingSub So, every assignment to the Module.Function property will install a new possible function, and the counter will be maintained by this process automatically and can be read out with the FunctionIndex property and memorized for future use. I am still not very happy with the fact that the arguments are passed in globally accessible properties. This makes cascading functions hard (but not impossible) and is a real pain to consider when it comes to multithreading. |
About the function calling: I am still not happy with any of the proposals. Mainly because it conflicts so heavily with other use cases and multithreading in particular (which was a real pain to get working in the first place). Maybe we could go back to your proposal to at least reduce the number of lines needed for any call. Instead of setting up all parameters individually in one line each, you could create a whole array of parameters in a one-liner and then use the normal subroutine call. DoSomethingPar = Vector.I3(4,5,6) Again this would restrict the use to numbers, but strings can still be passed as individual variables like before. |
Hey! Talking about bytes, on a side note, HiTechnic Color sensor V2 stores its Colour, R, G, B and White (CRGBW) data on registers 66, 67, 68, 69, 70, so using your I2C read registers function, we can read the sensor incredibly quickly without changing modes. Having the byte operation can greatly complement the learning value when students are encouraged to use the I2C operation. This sensor is in most ways superior to the EV3 Colour sensor and can be used in WRO. I understand that all variables are global, so what we did is to use a particular naming convention to differentiate the main program variables from those used in the functions. So this in a sense makes some variables "local" to the program. Just saying. Since EV3G does not allow recursive calls and concurrent running of the same function (myBlocks in EV3G), the students have more or less lived with it, so probably it is still too early to talk about recursion. The vector thing is quite useful. But text parameters are particularly important, like "True" and just text. Since we have to live with global properties, there must be a way to pass the parameters (num, logic, text) to the functions. It is probably okay to start with such inelegant solutions first, because everything is a work in progress...: 'Assign the parameters DoSomething = Mod.Key (the FunctionIndex, I called it as such since it is the key to call the function, like in threading classes used in other languages) sum = Module.C2(DoSomething, Arg1, Arg2) 'this should lock the use of the properties that are used to pass the parameters |
So, after a long walk through the winter, I came up with the following solution. It may look strange, but it will probably do the job (I am still not sure about the naming, I call the library "Function" for a start): ' define a function with 2 numeric parameters and a numeric return value ' call the defined function In the PC mode, there are no type restrictions on the variables and function arguments, so there will be no problem to pass arbitrary types. The parameter/return values for every different function will be stored in a global storage, maintained by the Function library. But there will be only a single storage for every function. So while it is perfectly fine for the SUM function to call other functions, it should not call itself because this would overwrite the parameter store. Also concurrently running a function twice leads to the same problem. For the brick mode, everything needs to have one of the 4 supported types: number, string, array of numbers, array of strings. By making it mandatory to pass the function identifier (the "SUM" in this case) always as a constant string literal, my compiler can figure out all parameter types and result types. It is a bit annoying, that you have to explicitly encode the number of parameters in the call, but Small Basic does not support library functions with a variable argument count. It will be fairly easy to put this feature into the Small Basic extension (PC mode) to experiment with it. What do you think? |
Woah yes. I know nuts about the compiler side but on the user side of things that's perfect since ev3g does not allow concurrency and recursion, but you can implement some form of concurrency. This will be great. I thought about the concurrency. There are many helper functions which need to be executed concurrently but lasts only a short while. This means that if the user can design a code to lock the function and its data structures by simply monitoring a global variable before running the function, then the overwrite problem for concurrency can be "solved", since the wait isn't too long to be noticed. And since the same functions are called consecutively during recursion, the user can just design a code to extract all the data before the properties in the Function class are overwritten. Besides, there is always a simpler solution when the same function is ran concurrently AND recursively... so don't worry about the overwriting yet! Whatever you proposed about the parameters is in my opinion sufficient for high-school students. That's because they can learn about function calling, and also appreciate (and possibly learn) how lower-level codes handle concurrency and recursion. As for the module and caller names, like what you said, should be kept short so that a function with multiple params can be seen within the editor window when it is called (methods used to extract the parameters will be fine). Maybe if u use Function, it can be shortened to Fx (since thats how they are commonly depicted in STEM illustrations), and Call1 be C1 etc. Maybe NUMBER can be shortened to NUM (if this makes it confusing because "NUMBER" is used elsewhere in the extension, then we can just use "NUMBER"). Just a note EV3G accepts only up to 10 params (input + output). I am honestly quite amazed by your dedication to this project. |
After some more consideration, I have now found a solution that would work much better. ' define a classic recursion example: towers of hanoi. X = F.C4("HANOI", "A", "B", "C", 10) The whole magic more or less happens in the C4 - operation. This will create a new local data storage that has space for the 4 parameters, 3 temporary values and 1 return value. Then the specified subroutine will be called and after its return, the local data storage will be removed and the return value will be passed out of the C4 function. With this naming scheme, the code is pretty compact. That there are no nice names for the variables, but only this generic properties for the parameters and locals is ugly, but I can not help it. You need to document the parameters properly in comments. For all this magic to work in the EV3 brick also, I need to restrict the possible types to numbers and strings. And the name of the function to call or define must always be a direct string literal. |
Hey, that's FANTASTIC!
|
Well, I could provide some accessor function to read the parameter values by name instead of having numbered propertierties . ... Again I have to say, that I can not have any arrays here. While this would work in Small Basic, I could never get this into the EV3 brick in a sensible way. So arrays are only possible as global variables. |
Hey! Yes. I agree that it is cumbersome too, making the statements quite long. A short comment on the functions will do the job of informing users about how to use the vars and params, so the approach on the earlier post should work fine. That said, when would you be roughly completing this next version? hehe, I'm quite excited to get my hands on it. |
After having slept over the matter, I changed my mind just once again. Now I think it would be nice to unify the parameters and the local variables. So it would be possible to use the parameters exactly like local variables and even modify them like it is possible in most programming languages (java, javascript, c, etc.). So this would mean to provide getter and setter functions to do so instead of using assignments. And maybe using only a single letter for the command names is a bit too compact and unreadable. My proposal would now be (doing more unification of the syntax): F.Sub = HANOI Note, that it is here allowed to ommit parameter when calling a function. The missing parameters will be initialized to the default value "0" (or 0 in brick mode for a number typed parameter) I am not sure if there will be much use of the feature, but I intend to make it possible for such a function to consist of multiple subroutines that can call each other via the normal small basic subroutine call. For the PC mode this comes without restrictions, for brick mode I will impose some compiler checks to make sure that all subroutines that call each other directly are indeed in the same function context. This generic Get and Set functions can also be used on the top level outside of any function context if you need to have thread-local variables there. But these variables are then only visible on the top level and not inside any function context. For globally visible stuff, you still need the normal global variables that are shared by all functions and threads. About timelines: I am not sure when I will have time to implement all this magic stuff. I guess I can come up with the implementation for PC mode quite soon, but the brick mode compiler will take longer. |
As a proof of concept, I have patched together a quick implementation of the "Byte" and "F" library for use in PC mode. No documentation for the functions and of course no support for the brick mode compilation yet. You can fetch this experimental version from: https://1drv.ms/f/s!AuAO_Q-atz3PaVbs7BahvHZtApQ The version number is still just 1.2.0 - when I have a stable and correctly working version, this will then become 1.2.1. Please use this installation file only now for experimenting with the feature and don't pass it to other persion.. |
Haha, I asked you about the time because the WRO challenge will come out by 15 Jan, but really the time is only at the back of the mind. That's because I have to create or improve lesson plans of which the bulk of it would be mechanical, and it takes only a short amount of time to prepare the plans for programming. And I would have until around the middle of March to prepare the stuff, which is quite a lot of time. So honestly, no rush! Besides, there would still be enough time for other organisations interested in EV3 basic to learn and use it for WRO. I'm based in Singapore, in fact, I am currently interning at a company (Duck Learning, LEGO Education sole distributor in Sg) that organises the national-level WRO competition in Sg. I'm looking into ways to improve the competitiveness (scores) of teams in Sg and more importantly my high school. I feel that EV3 Basic could be the next step, hence all these threads. And YES, good magical stuff are worth the wait!!!
I recommend using "-0.1" or -0.1, that is because usually 0 is a valid data point for many sensors, including colour sensors, while negative, non-integer numbers are not. And since input can come from either raw or manipulated sensor data, it will become a lot easier for users to differentiate a valid data point from a "NULL" data point. Hmmm... Is there a way to assign the default values? like
When programming the robots, I routinely run into functions which can be shortened. For example for PID Line tracing or comparing the RGB values from the colour sensor, the "PORT" argument is almost always the same, except for a few instances. So YES THERE WILL BE OF MUCH USE TO THIS FEATURE. |
Hey, The following have the same methods and parameters (probably not the NOT method)
For the FromBinary and ToBinary etc. methods, I propose renaming them, because I found them confusing...
--or---
Where Base is either "BIN" or "HEX" BTW, there is only up to a call5 method so far for the Function class, it is still a work in progress right, because there should be at least a call10 method (hehe, bcos EV3G can support up to 10 parameters)? |
I was considering having more bits in a number. But this would have been limited to 23 bit because of the used numerical precission on the brick. I could support 16-bit words to make it look less silly, but that would stilll mean not much to a novice in computing. But a "byte" is really something you need to know about. And having bytes that actuallly consist of bits makes really sense from an educational point of view. |
Your first proposal to rename the conversion methods is even more confusing. Str2hex would suggest that you convert a string to a hex representation, which is also a string. The second proposal is cumbersome to use and hard to implement. My Byte.ToHex and Byte.ToBinary is perfectly clear in this respect. I must admit that the FromHex and FromBinary are a bit confusing. Maybe you have a better idea? |
The whole F library is not finished. I will support 20 or so parameters, About default values: The parameter specifier will look like "X:0 Y:1 MSG:HELLO" which will specify default values as well as implicitely the types. Same thing for the return type specifier which also contain a default return value (for the case that the function does not call the Return command). This would eliminate the need for the NUMBER and STRING keyword inside the specifier strings. |
I'm okay with limiting it to 8 bits from an educational point of view, two's complement, size of bytes, bitwise operations etc. Besides, if we really want to expand the functionality, we can always use the powerful F library. Do you think, in the context of using Bytes, that a rotate left or right function would be good? I saw the amount of work you did on the Byte.txt, it's crazy, so I'm perfectly alright if that isn't implemented. Yep I agree with the Str2Hex and Str2Bin. That's why I called it Str2Num, because it is about converting a string representation into a numeric data type, so that it is easier for beginners to use them and fit into the parameters. Personally i saw Hex and Bin as numbers (probably other novices would), instead of strings, and that's where the confusion arose, so I thought maybe it could be clearer to use Str2Num. If I persist on this current proposal, I would modify to HexStr2Num(Str1) and BinStr2Num(Str1). But really, we can always look into the documentation to know how to use it. In that regard, I'm fine with the current proposal. I can't ask too much because that will be too much work for you! The parameter specifier is great, never would have thought of it. I could sense the potential problem of passing numbers if they are meant to be strings, but since this is small basic, the primitive doesn't matter. Thanks! |
Hi! I had to redo some of the commands, mainly the way how the function return type is handled. Also there is now no specific support for local variables. Since the call parameters can be written to, and the caller does not need to provide values for all parametes, this mechanism can be easily "abused" for local storage. The Byte library had minor changes too. I will provide the commands to convert from string to numbers as Byte.H and Byte.B to make it short and easier usable when you want to just include some numeric values in the code. This version is not finished, because I expect that there are some bugs. And documentation is pretty thin and not translated in any language. It would be nice if you could test the new functionality (see examples "Function", "Recursion", "Concurrency" for more details). |
Hey! Thank you so much! I will test and reply by Sunday 1600 GMT lolol. |
Hi!
So instead of the silly if else overhead in small basic
It could be better to make do with a function like SomeClass.MoreThan(a, b). If this could be expanded, the following methods could be implemented:
A similar thing can be done for logic input:
Thanks! |
Hi!
|
Adding to point 5: |
Hello! Regarding (3), yes if there is plenty of overhead on the compiler side, then forget it. I'm trying to see if there is an efficient way (particularly short-circuiting, and less overhead with compiler) of doing this. Since it is not possible, then the if else will be good to work with. The judges crave some complexity, but this reason you provided is even better. I stated (4) primarily because it could be faster to read multiple data at once from the sensors (like reading all the color, R, G, B and white values for HiTechnic sensor V2 and the 2 raw reflected light intensity values for the color sensor) and returning their values. But come to think of it, if there is no efficient way of doing it on the compiler side, then we can always read values one at a time from the sensor, which should be as fast as reading multiple values... I thought of the file thing too lol, that would be a great idea! Thanks for the tip on (5) for colons. In fact my concern was if spaces were allowed in the default. But since it's just a short line of code to change the default to spaces after calling the function, it really doesn't matter. Noted for (6)! I'll keep in touch if there are any bugs. It will take some time. The first time I could fully commit to testing a robot on the WRO map is coming Saturday. I would do some quick testing before that. Actually so far I find the libraries stable (I haven't got to the level of concurrency and recursion as that of your examples, and I probably wouldn't. However, I will be testing the libraries with the motors, sensors and ev3 features soon). |
One more thought about (4): Your use case for reading multiple sensor values is actually a very good reason to use only a single function call. There is a massive time overhead for each individual I2C communication (in the order of multiple milliseconds), and the cost of string concatenation and parsing is probably much less (but I would need to actually benchmark this). RGB = EV3File.ParseNumbers(F.Call("READCOLORS", 1)) could perfectly make sense. |
Hello again! The core part will be the exact behaviour of the new Byte.ToLogic function: For every positive value it will return "True", for 0 or negative values it will return "False". Following this scheme, you could then also treat such numbers as logic values for the purpose of storing and computation. Using just the standard Math library, you could implement every logic operator imaginable:
Since all these functions from Math are inlined into the bytecode where used and the arithmetic operations are also quite light-weight, this approach would actually be quite fast. Of course it will quickly become a nightmare to read and understand, but it has a kind of puzzling elegance ;-) As a challenge your the reader: I am quite unhappy with bulky implementation of the = operator (just the <> and NOT stacked together). If you could come up with something more elegant, that would be nice. For special cases where X and Y are guaranteed to be integer values, some compare operators could be written shorter:
|
Maybe the previous post needs a tiny bit of clarification. Imagine you want to write something like: X = A < B AND C < D which is not possible in SmallBasic, you could instead write X = Byte.ToLogic(Math.Min(B-A,D-C)) in just one line. |
Hey! That's a nice idea for the logic and ToLogic, I never thought that math can be used to replace the logic functions! With these ideas and the F class it is possible to achieve the output. It will also be a nice exercise for advanced students to understand more. I am honestly very very happy with the capabilities you have designed so far. As for the bugs and issues, it could be a course of two or three months before my students and I can identify them... |
So, I finally implemented the two commands new for Byte and created the Vector.Data command to split a string into a number array. Instead of putting this into the EV3File object, I think it makes more sense to add it to the Vector object. |
Hey man, thanks! My students / juniors and I have been writing out some functionalities with the experimental program, I will get back to you in about 2 to 3 weeks if we spot any bugs! |
Hi! One of my students have been using this software. However, is it possible if we could make a function call non-blocking (call on a new thread): We can technically use Sub, call the function in it, and then use a thread.run, but this means that we can't use the parameters. |
Hi. I am an undergraduate and have extensive experience with EV3G. Im trying to introduce EV3 Basic into my high school but I have some problems...
there is no xor or not logic operators in ev3 basic, would it be possible to add it into the library, or do I not know something?
in designing modules for use in competitions, for example pid linetracing, and particular those with many input parameters, I have to write a chunk of code just to get it set up. This is because i have to write the variables used as parameters, and each variable takes up a line of code. Would it be possible if we can do it the way u did to your library functions (one liner)
The text was updated successfully, but these errors were encountered: