I need feedback on my program
avionikeren
Posts: 64
Hi folks,
I`ve been usin the propeller for a while now on different projects, but I need some feedback on my programs to learn more. I think my programs could be more effective and smaller.
Will you have a look at the attached program and give me some hints?
The program is used to control a ROV by reading serial data from a visual basic program on a computer and refresh 2ea 4channel DAC`s (light dimming), Tristate outputs (MCZ33880 for zoom and focus), serial to hydraulic valve drivers(3ea valvepacks with 8ea proportional valves in each pack), relays and reading ADC`s on the 1st valve driver and send them to another propeller (called proplink in the code).
The program works perfect, I would just like to know how to do the same with less code.
I`ve been usin the propeller for a while now on different projects, but I need some feedback on my programs to learn more. I think my programs could be more effective and smaller.
Will you have a look at the attached program and give me some hints?
The program is used to control a ROV by reading serial data from a visual basic program on a computer and refresh 2ea 4channel DAC`s (light dimming), Tristate outputs (MCZ33880 for zoom and focus), serial to hydraulic valve drivers(3ea valvepacks with 8ea proportional valves in each pack), relays and reading ADC`s on the 1st valve driver and send them to another propeller (called proplink in the code).
The program works perfect, I would just like to know how to do the same with less code.
spin
25K
Comments
Look up arrays in the Propeller Manuel (click Help in Propeller Tool, then "Propeller Manuel (pdf)") for descriptions in detail of how to use them.
Also, if you used arrays, this:
Could be reduced to this:
You know, this inspires me to write a "code optimizing" tutorial. Maybe I should do that some time....
Anyway, I hope this helps.
Microcontrolled
Here is updated version of the program, please let me know if there is more I could do to the code.
The "SetValveDefaults" section is atrocious. Take advantage of the DAT block and arrange your data there, then output it by using a "repeat i from 0 to x" statement. X being the number of characters and i being the variable. You may also want to look at the data block in the Propeller Manuel.
Hope this helps,
Microcontrolled
Your variable is defined as "byte npropvalve[24]". The index always starts at 0 (zero). So, actually you overwrite whatever comes after the array because starting with 0 the allowed range for the array with 24 elements is 0-23! This seems to be a general problem in your code ;o)
Store your constants in a dat section. Then you can access the constants like an array, which removes the need of all the IF-statements: Of course channel has to start from 0 here as well.
For this: you can use the bytemove-instruction - which gives shorter and faster code, as bytemove is implemented in PASM.
I`m trying to shorten the disabled code below with the first five lines, but it doesn`t work.
Is it not possible to do negative steps?
Let's improve "updateTristate".
1. First of all the indentation seems to be wrong in most of the if channel>1 cases. But ... to be honest I don't see a difference in the =1 and >1 versions. You added some 0 in the =1 ifs, but adding 0 digits in front of a number does not change the value at all. So, remove the if channel-statements and simply do the shiftout.
2. The other if statements can be replaced by a case statement by combining zoom and focus. You simply shift zoom 8 bits to the left and or the result with focus. The result will then contain zoom in bits 8-15 and focus in bits 0-7. If you use hex-values it looks like this: $zz_ff, where zz is the zoom value and ff is the focus value. The code then looks like: If you want, you can replace the $zz_ff-values with some self explanatory constants, which makes the code more readable.
The updateValveXX functions can also be replaced by only one function with one parameter telling which calculation to do (1A,1B,2A or 2B) using different values defined in DAT arrays. The general function is:
return := (((newvalue * c1[ which ]) + c2[ which ]) * 25) / 10
where
DAT
c1 byte 1,-1,1,-1
c2 byte -100,100,-100,100
In this case which=0 will give you the result of 1A, which=1 will give you the result of 1B ....
(Found that during writing: 1A=2A and 1B=2B, so you can even ommit that differentiation)
updateValvepack1 and updateValvepack2 can also be put together in one function.
next to come ... ;o)
About the updatevalvepack functions, I split it in two identical because I was afraid of running the same PUB simultaneous from different cogs. Or is that totally wrong thinking?
Below, I have merged the updatevalve as you suggested, but the code below will not work as I expected. Both valve A and B goes the same way at the same time. I want to move valve A if npropvalve > 100 and move valve B if npropvalve < 100. Valve A and B is actually two solenoids pulling one valve in different directions.
Well ... there is no easy answer. It depends on what the function is doing.
If the function only works with it's parameters and with local variables and maybe read access of static global variables, there is no problem calling it from 2 different COGs.
If the function also writes to global variables or has to read dynamic global variables changed by other COGs, you surely need to know what you do.
So, for the functions in question I don't see a problem.
For your current problem I don't have an answer yet, since I have to work first ;o)
But if you invert the logic you only need the calculation once:
if (newvalue <= 100 and valve ==0) or (newvalue >= 100 and valve == 1 )
return 0
else
return ((( newvalue .......
(will have a look this evening)
It`s not possible to assign a negative value to a byte.
I first made it work by changing:
DAT
c1 byte 1,-1
c2 byte -100,100
To:
DAT
c1 byte 2,0
c2 byte 0,200
And of course subtracting this in the code.
But when I was thinking about this for a while I came up with this instead:
I have attached the complete code, I`m very happy with this now, but still let me know if you see anything else I should fix. Thanks for your help!!
The variable rxvalid is not used anywhere -> remove it.
can be done with bytefill
this can be done with the strcomp instruction.
can also be done in the loop which comes a little bit later.
how about ... and again you could calculate the checksum while transmitting - would remove the need to loop over all values again.
this kind of repeat appears 4 times, so make it a function.
Happy coding ;o)
PS: I was not aware of the byte-problem because I did not use negative bytes so far with the propeller. But you could stay with -1 and -100, because there is an operator which will extend the most significant bit as if it is a signed number. ~c1[ valve ] would extend the byte correctly. Just for the records, as you solved it differently.
CON
ADC_SIZE = 6
VAR
byte adc[ ADC_SIZE ]
...
repeat x from 0 to constant( ADC_SIZE-1 )
If you use this constant anywhere in your code, you can easily extend the size of the array without taking care of the loops that loop over the array. And it makes code just a little bit more readable.
What I'd do is change the order of the serial interfaces. If you use serial[0] and serial[1] for valveControl2 you can directly use o as index without adding 2.
Instead of o*8 you can use o<<3, which is much faster than the multiplication. *4 can be replaced by <<2 and /16 can be replaced by >>4. In other words, if you have to multiply/divide by constants with a value of 2^x you better use shift-operations.
You have a lot of loops, which simply transfer bytes out of an array. Again you could make a function for that:
Instead of
repeat f from 0 to 6
serial[1].Tx(pwm16setValves[f])
you can then call
transfer( 1, @pwm16setValves[f], 7 )
If you do not need the checksum, then ignore the result, otherwise the checksum returned can be used.
Another implementation of transfer would maybe contain an additional parameter, which tells the function to simply send the checksum if TRUE.
I have attached some pictures of the ROV control system in case you find it interesting.
The system will be in a 20mm thick aluminium tube to withstand water down to 3000meters.
At the surface the ROV is controlled from a computer and a USB joystick (which appears as a windows gaming device). The software is written in VB.Net.
The idea of having functions is to save memory for code you'd have to repeat several times otherwise. With the right function name it also increases readability of the code. You should keep in mind that some code will run for years until you HAVE to change it again. Then you'll be happy to find easy understandable code.
BTW, stack3 is not used, so you can remove it.
Thanks for sharing the photos! How are the commands transfered to the ROV?