The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
I've got an RGB LED plugged into 3 of the PWM outputs. I want to cross-fade between colours.
I thought this would be trivial but apparently not. I've simplified this to just be a single output for now.
Dim Start As UInteger = 0
Dim [End] As UInteger = 255
Dim Steps = 100
For x = 1 To Steps
Dim Temp = ([End] - Start) / Steps * x + Start
Dim R = CUInt(Temp)
Debug.Print(x.ToString & ": Temp: " & Temp.ToString & ", R:" & R.ToString)
LedR.SetPulse(255, R)
Threading.Thread.Sleep(20)
Next
As you can see the actual calculation works perfectly but I can't find ANY way to shoe-horn the resulting double into a UInt.
NB: In this scenario, I don't care at all about precision so Ceil/Floor/Truncate are all perfectly acceptable.
I've tried:
Dim R = CUInt(Temp) 'Odd output - maybe reading memory and just treating it as a UInt
Dim R = CType(Temp, UInteger) 'Throws: An unhandled exception of type 'System.Exception' occurred in Netduino_VBTest.exe
Dim R = Convert.ToUInteger(Temp) 'Doesn't have an overload for Double (or anything except string!)
Dim R = Convert.ToUInteger(Temp.ToString) 'Throws an exception
Just declare and type your variables. This is always good practice.
Sub Main()
Dim Start As UInteger = 0
Dim [End] As UInteger = 255
Dim Steps = 100
'Declare your vars
'***********************
Dim R As UInteger = 0
Dim temp As Double = 0.0
'***********************
For x = 1 To Steps
temp = ([End] - Start) / Steps * x + Start
R = CUInt(temp)
Debug.Print(x.ToString & ": Temp: " & Temp.ToString & ", R:" & R.ToString)
'LedR.SetPulse(255, R)
'Threading.Thread.Sleep(20)
Next
'Output
'======
'95: Temp: 242.24999999999997, R:242
'96: Temp: 244.79999999999998, R:245
'97: Temp: 247.34999999999999, R:247
'98: Temp: 249.89999999999998, R:250
'99: Temp: 252.44999999999999, R:252
'100: Temp: 254.99999999999997, R:255
End Sub
I don't know a .net micro vb translation of this as I haven't got VB on this computer,
but the C# version works.
Or maybe create a c# library project that your vb code can call, then put in this method.
namespace misc.random.libs.workarounds
{
public class utils
{
public static int ConvertToInt(double input)
{
return (int)System.Math.Round(input);
}
}
}
Thanks all for your answers, I'll respond individually...
The trick is to multiply first then divide so that you don't lose any precision.
...
Might be of some help.
Paul
Thanks, that's a reasonable approach to take - especially since I'm not concerned with precision. The problem is that I like to code with Option Strict on which means the conversion you perform which rounds to the nearest integer (result=) is a narrowing conversion, resulting in an Error/Warning. This is same of vanilla .Net but in vanilla, I'd use CInt() to explicitly inform the compiler that I'm expecting the narrowing conversion to take place, removing the error/warning and also reducing coding errors by preventing inadvertent conversion from double to int.
Just declare and type your variables. This is always good practice.Baxter
Thanks for the suggestion. I suspect you ran your test using the emulator not an actual netduino? I get the correct output using the emulator too. Running your code against the netduino shows exactly the same problem as my example:
(If you ran it against your netduino, which one and what firmware?)
I have to say I disagree with you re: typing variables. Implicit typing is perfectly acceptable as it's done at design time and is simply a shorthand notation (as opposed to say PHP with mixed variable types). You can verify this by hovering over the variable in the editor - it will tell you what the type is and won't allow you to treat it as anything else. Using a variable before it's initialised is bad practice but that's why VS gives you a warning.
One other reason I prefer my approach is that variables declared inside the loop are out-of-scope once you leave the loop so are eligible for GC. It also means I won't refer to them by mistake as the designer knows they're no longer valid.
Although I haven't been able to achieve it yet with the MF, all my normal .Net apps have 0 warnings (I treat warnings as errors and TFS won't allow a code checkin unless it compiles and passes unit tests). This tends to enforce good coding habits and has served me well so far - If anyone has reasons they believe I'm wrong, let me know as I'd love to discuss coding style improvements.
Could you convert your code to c#?
Hi Magpie - I could indeed write this in C# (and I use C# at work more often than not) but I personally prefer VB and this is my first noddy project to test VB support - needless to say, I was amazed that you can't do the conversion. Incidentally, Math.Round seems to be available in VB too but it still returns a double (even though it doesn't have a param to indicate precision). As such, I just get an integer stored as a double and the same problems happen again.
I've found a workaround but it's such an ugly hack and I don't recommend anyone use it for any purpose...
Dim Test = 123.45
Debug.Print(UInteger.Parse(Test.ToString.Split("."c)(0)).ToString)
*shudder*
NB:
UInteger.Parse("123") works fine
UInteger.Parse("123.0") throws an exception
Thanks, that's a reasonable approach to take - especially since I'm not concerned with precision. The problem is that I like to code with Option Strict on which means the conversion you perform which rounds to the nearest integer (result=) is a narrowing conversion, resulting in an Error/Warning. This is same of vanilla .Net but in vanilla, I'd use CInt() to explicitly inform the compiler that I'm expecting the narrowing conversion to take place, removing the error/warning and also reducing coding errors by preventing inadvertent conversion from double to int.
If I was working in C/C++ there would not be any rounding or conversion; this is because all of the variables are of type integer. The whole thing gets done in integer arithmetic; any fractional part generated by the divide is just lost.
Does VB convert to floating point to do the calculation when you use the multiply and divide operators - thus requiring a conversion?
If I was working in C/C++ there would not be any rounding or conversion; this is because all of the variables are of type integer. The whole thing gets done in integer arithmetic; any fractional part generated by the divide is just lost.
Does VB convert to floating point to do the calculation when you use the multiply and divide operators - thus requiring a conversion?
Paul
Exactly so
Dim I as Integer
I = 3/2
or
Dim I, J as Integer
J = 4
I = J/2
or even
Dim I as Integer
I = 1.5
Would all produce a warning (Implicit conversion from Double to Integer)
You can, of course, disable the warning but I tend to like it as it's enforcing strong typing rules. If I intended to force it into an int, I'd do:
Dim I as Integer
I = CInt(3/2)
CInt takes a double (amongst other things) and returns an integer thus complying with strong typing, performing the truncation for me and also providing a level of confidence that I'm not treating double as integers and losing precision unless I explicitly intend to do so.
EDIT: You've just reminded me of the integer divison operator which I rarely ever use...
7 / 2 produces 3.5
7 \ 2 produces 3
With your rearranged formula, this might do the trick. Let me have a play...
Ok, Using:
Dim R = ([End] - Start) * x \ Steps + Start
Seems to work as I'd expect - Thank You!
(Incidentally, it technically results into a long but Long-UInt works without issue and I shouldn't ever overflow)
This does solve the immediate problem but I still think the fundamental question of converting a double to an int is an important one - perhaps it's just been too long since I played with PICs and I've got set in my comfy desktop cpu ways.
This is very strange. After reading your comment, I re-ran the code that I submitted and got the same answer; and yes, I deployed to Netduno not the emulator (Project Properties, transport:USB, Device:NetduinoPlus_NetduinoPlus). Also, I did not run your code initially. So I ran your original code to get:
I am running MF 4.2 RC1 with Netduino Plus. I never ugraded to RC3 because of all of the problems noted in the forum. I seem to recall that there were other issues with doubles in RC3. I guess this is just another bug in RC3 (e.g. Dim R = CUInt(Temp)). You have a good point about scope.
This is very strange. After reading your comment, I re-ran the code that I submitted and got the same answer; and yes, I deployed to Netduno not the emulator (Project Properties, transport:USB, Device:NetduinoPlus_NetduinoPlus). Also, I did not run your code initially. So I ran your original code to get:
I am running MF 4.2 RC1 with Netduino Plus. I never ugraded to RC3 because of all of the problems noted in the forum. I seem to recall that there were other issues with doubles in RC3. I guess this is just another bug in RC3 (e.g. Dim R = CUInt(Temp)). You have a good point about scope.
Baxter
Hi Baxter,
Thanks for the info - I think you must be right re: being a bug in RC3 (which is what I'm running). I'll wait until the next release and see how it goes.
Thanks also for the confirmation that my code works on your hardware - good to know I'm not being a complete idiot