MXS: 3ds max crashed when running my 'delete duplicates' script - crash

3ds max crashes when I run my script. A windows Error message box is produced (by the process "Windows Problem Reporting"). There are no errors produced in Maxscript (the listener does not display any errors during script run-time). CPU and RAM usage are at acceptable levels during script run-time. My script worked without crashed and produced the required results on a smaller scene (10-20 objects) with only standard primitive objects. The error/crash occurs on a larger scene containing 4051 polygonal objects.
The script looks at all objects, finds identical objects and deletes all but one of the identical objects leaving you with a scene without any duplicate objects).
When running the script on a scene containing 4051 objects windows gives me an error message box ; "3ds max has stopped working - A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available."
During script run-time RAM and CPU usage of 3ds max remain acceptable (according to task manager)(30-40% CPU (i5-6600k) and 3-4GB RAM out of 16GB).
Image of the 'Windows Problem Reporting' error message box:
How the process looks in task manager:
Image of CPU/RAM usage of 3ds max during script runtime:
Note: after the error messagebox has appeared 3ds max's RAM/CPU/DISK usage drop to near zero values. After the error message box appears windows gives me no other choice than to close 3ds max.
I've let the script run a lot of times to check if the error message occurred at the same object each run, this was not the case, the error message occurred at a different object (when a different object was being processed by the script) each time I ran the script. The script tends to crash when it is comparing the first object in the scene ("Mesh_000") to another object in the scene with a mesh number in between "700" and "900". The following array contains the index of the mesh on which my script crashed during some of the tests I've performed: #(805,832,733,766,877). The script runs for 10-20 minutes before crashing.
The .max scene which causes the error can be found here:
larger .max scene which causes error
The script works like this(pseudo code):
duplicate_objs = #()
meshes_array = Collect all meshes in scene
for mesh in meshes_array do(
Compare mesh to all other meshes in meshes_array
if an identical mesh is found do(append duplicate_objs identical_mesh)
)
--Delete all the duplicate meshes:
delete duplicate_objs
The code for my script:
fn fn_construct_objs_array x = (
clearselection()
select geometry
deselect helpers
objs = selection as array
checked_objs_list = #()
items_to_delete_from_objs = #()
)
fn fn_delete_duplicates equal_pos_boolean =(
--print "DELETING DUPLICATES"
obj_dups = #()
ConvertTo objs[1] Editable_Poly
PolyCount_src = polyop.getNumFaces objs[1]
TriCount_src = (objs[1].mesh.numFaces)
VertCount_src = (getnumverts objs[1])
Position_src = objs[1].pos
for i in 1 to objs.count do(
if i <= objs.count and objs[i] != objs[1] do(
format "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n--> Comp. original obj (%) to comparison-obj(%) \n" objs[1] objs[i]
ConvertTo objs[i] Editable_Poly
PolyCount = polyop.getNumFaces objs[i]
Tricount = (objs[i].mesh.numFaces)
Position = objs[i].pos
VertCount = (getnumverts objs[i])
if(Tricount == Tricount_src and PolyCount == PolyCount_src and VertCount == VertCount_src and ( if equal_pos_boolean then( Position == Position_src)else(true) )) do(
if((finditem checked_objs_list (objs[i]) == 0) ) do(
appendifunique obj_dups objs[i]; --print "||||||||||||||||||||| FOUND DUPLICATE OBJECT |||||||||||||||||||||| \n"
appendifunique checked_objs_list objs[i]
append items_to_delete_from_objs objs[i]
)-- end if(finditem checked_objs_array objs[i] == 0 ) do(
)-- end if(Tricount == Tricount_src and PolyCount == PolyCount_src and VertCount == VertCount_src and ( if equal_pos_boolean then( Position == Position_src)else(true) )) do(
)-- end if i <= objs.count(
)
for item in items_to_delete_from_objs do(
deleteitem objs (finditem objs item)
)
items_to_delete_from_objs = #()
deleteitem objs 1
for duplicate in obj_dups do(delete duplicate)
if objs.count > 0 do (
--format "objs left to process = % \n" objs.count ;
fn_delete_duplicates equal_pos_boolean
)--end if objs.count > 0 do(
)--end fn_delete_duplicates
fn_construct_objs_array 1
fn_delete_duplicates true
Note: meshes being identical is (in this context) defined as the meshes having the same polycount, vertcount, edgecount, position.

I'm bad at debugging others' code, so again just a quick glance - I'd definitely avoid for loop in for duplicate in obj_dups do(delete duplicate), delete is a mapped function and you can pass a collection as an argument to it. That way, there won't be so many scene explorer updates and it should be much faster. I'd also prefer iteration over recursion. All in all, this is how I'd write it:
struct objInfo
(
obj, polyCount, vertCount, pos,
fn isSamePos pos1 pos2 eps:1e-6 =
(
local diff = pos2 - pos1
dot diff diff < eps
),
fn isEqual info checkPos:off =
(
this.vertCount == info.vertCount and
this.polyCount == info.polyCount and
(not checkPos or isSamePos this.pos info.pos)
),
on create do
(
local polyVertCount = getPolygonCount obj
polyCount = polyVertCount[1]
vertCount = polyVertCount[2]
pos = obj.pos
)
)
fn collectDuplicates checkPos:off =
(
items = for obj in geometry collect objInfo obj:obj
itemCount = items.count
collected = #{}
duplicates = #()
for item = 1 to itemCount where not collected[item] do
(
local current = items[item]
for nextItem = item + 1 to itemCount
where not collected[nextItem] and
(
local next = items[nextItem]
next.isEqual current checkPos:checkPos
)
do
(
append duplicates next.obj
append collected nextItem
)
)
return duplicates
)
delete (collectDuplicates checkPos:off)

From a cursory look, I'd warn against using objs[i].mesh.numFaces since it creates new mesh instance in memory and you're not calling dispose to delete it - if you opt to go this way and compare both polycount and tricount, definitely do the conversion and collect the meshes outside the loop first (and preferably use snapshotAsMes, too). Also, you might want to use getPolygonCount <node> which gives you node polygon count (if the result of the stack is polyobject) and vertex count.

I've edited my code using Swordslayer's suggestions; the collection of mesh information now takes place outside of the loop and I am using getpolygonCount to get both poly- and vertcount.
The scene mentioned in my original question containing 4051 standard primitive objects does not cause a crash anymore (and is significantly faster), however another scene containing imported objects now causes a 'Stack Overflow Error' inside 3ds max... The strange thing is that this error only occurs the first time I run the script after starting up 3ds max. When running the script a second (or third etc.) time after the stack overflow error has occured the script executes without any errors (takes approx 10-20 seconds for it to finish) and the script functions as it should (as in it deletes the duplicate objects). The stack overflow error occurs each time I run the script on the original scene AFTER just having started 3ds max.
Another strange thing (to me) is that even though the stack overflow error occurs, the script does indeed delete the proper objects (the duplicate objects) before producing said error.
RAM usage by 3ds max before/after the system exception error is as follows:
3ds max scene opened, before running script: RAM usage = approx 1800MB
during script run, before the error messagebox pops up: RAM usage increased from initial 1800 to a final value of 2132.6MB
system exception error messagebox has appeared: RAM usage = 2132.6MB
after clicking OK on the error messagebox: RAM usage = 2132.6MB
(note: as mentioned in my original question I have 16GB of ram)
My current code:
checked_objs_list; items_to_delete_from_objs; theMeshes; equal_pos_bool ; mesh_data
fn construct_arrays x =(
max select none ; select geometry ; deselect helpers
theMeshes = selection as array
mesh_info = for theMesh in theMeshes collect ( #(theMesh, getpolygoncount theMesh, theMesh.pos) ) --collects #(tricount, vertcount) for all meshes in 'getpolycount_meshes'
max select none
--Declare initial values of array variables
checked_objs_list = #()
items_to_delete_from_objs = #()
return mesh_info
)--end fn construct_arrays
fn delete_duplicates equal_pos_bool =(
obj_dups = #()
appendifunique items_to_delete_from_objs mesh_data[1]
if i <= mesh_data.count and i != 1 do(
if(mesh_data[i][2][1] == mesh_data[1][2][1] and mesh_data[i][2][2] == mesh_data[1][2][2] and ( if equal_pos_bool then( mesh_data[i][3] == mesh_data[1][3])else(true) )) do(
if((finditem checked_objs_list (mesh_data[i]) == 0) ) do(
appendifunique obj_dups mesh_data[i][1] ; --print "||||||||||||||||||||| FOUND DUPLICATE OBJECT |||||||||||||||||||||| \n"
appendifunique checked_objs_list mesh_data[i]
appendifunique items_to_delete_from_objs mesh_data[i]
)-- end if(finditem checked_objs_array objs[i] == 0 ) do(
)-- end if(Tricount == Tricount_src and PolyCount == PolyCount_src and VertCount == VertCount_src and ( if equal_pos_boolean then( Position == Position_src)else(true) )) do(
)-- end if i <= objs.count(
) --end for i in 1 to mesh_data[1].count do(
for item in items_to_delete_from_objs do(
deleteitem mesh_data (finditem mesh_data item)
)
items_to_delete_from_objs = #()
for duplicate in obj_dups do(delete duplicate)
if mesh_data.count > 0 do (
delete_duplicates equal_pos_bool
)
)
mesh_data = construct_arrays 1 --call construct_arrays function and save returned data in variable 'mesh_data'
delete_duplicates false --function call
The issue does not appear to be related to the amount of objects/polygons in the scene; I ran the script on a scene containing 16204 standard primitive objects This scene consists of 11,418,736 polygons and 5,780,404 vertices whilst the scene with the imported objects which is causing the stack overflow error consists of just 703,737 polygons and 769,886 vertices (which is significantly lower).
I let the stack overflow error occur multiple times, each producing a slighty different error messagebox, all of which can be seen below:
Error produced on 1st crash:
Error produced on 2nd crash:
Error produced on 3rd crash:
The error that is shown in the listener window tells me the error occured in 'Macro_SceneExplorer.mcr' in line 1001, this line contains the following code:
sceneexplorermanager.ExplorerIsOpen ~SE_SCENE_EXPLORER_NAME~
It also tells me this line of code was called from line 44 of my 'delete_duplicates.ms' script, which contains the following code:
for duplicate in obj_dups do(delete duplicate)
Here is part of the error message produced in the listener window after the stack overflow error has occured (the full error and stacktrace can be found here: https://drive.google.com/open?id=1s-BplnpiM_sz3yfN4XVySmhcsK5zraeX ) :
-- Error occurred in anonymous codeblock; filename: C:\Program Files\Autodesk\3ds Max 2018\MacroScripts\Macro_SceneExplorer.mcr; position: 29880; line: 1001
-- MAXScript MacroScript Error Exception:
-- Known system exception
-- ########################################################################
-- Address: 0x6745e920; nCode: 0x00000000C00000FD
-- Desc: EXCEPTION_STACK_OVERFLOW The thread used up its stack.
-- ########################################################################
-- MAXScript callstack:
-- thread data: threadID:5300
-- ------------------------------------------------------
-- [stack level: 0]
-- In isChecked(); filename: C:\Program Files\Autodesk\3ds Max 2018\MacroScripts\Macro_SceneExplorer.mcr; position: 29881; line: 1001
-- member of: codeblock macroScript: Scene Explorer_SESceneExplorer
-- Locals:
-- Externals:
-- owner: <CodeBlock:Scene Explorer_SESceneExplorer>
-- Scene Explorer_SESceneExplorer: <CodeBlock:Scene Explorer_SESceneExplorer>
-- ------------------------------------------------------
-- [stack level: 1]
-- called from codeblock macroScript: Scene Explorer_SESceneExplorer; filename: C:\Users\Philips\Desktop\ninjaripper1.7.1\tools \3dmax_maxscript_importer\0000_delete duplicates (pre-construct_arrays) 9 (noprint) 2.ms; position: 2755; line: 44
-- Locals:
-- Externals:
-- ------------------------------------------------------
-- [stack level: 2]
-- called from duplicate loop; filename: C:\Users\Philips\Desktop\ninjaripper1.7.1\tools\3dmax_maxscript_importer\0000_delete duplicates (pre-construct_arrays) 9 (noprint) 2.ms; position: 2755; line: 44
-- Parameters:
-- duplicate: <Deleted scene node>
-- Locals:
-- duplicate: <Deleted scene node>
-- Externals:
-- owner: undefined
-- ------------------------------------------------------
-- [stack level: 3]
-- called from delete_duplicates(); filename: C:\Users\Philips\Desktop\ninjaripper1.7.1\tools\3dmax_maxscript_importer\0000_delete duplicates (pre-construct_arrays) 9 (noprint) 2.ms; position: 2755; line: 44
-- Parameters:
-- equal_pos_bool: false
-- Locals:
-- equal_pos_bool: false
-- obj_dups: #(<Deleted scene node>)
-- Externals:
-- owner: undefined
-- delete_duplicates: Global:delete_duplicates : delete_duplicates()
-- mesh_data: Global:mesh_data : #(#($Editable_Mesh:Mesh_2184 # [0.000000,0.000000,0.000000], #(128, 28), [0,0,0]), #($Editable_Mesh:Mesh_2185 # [0.000000,0.000000,0.000000], #(128, 28), [0,0,0]), #($Editable_Mesh:Mesh_2256 # [0.000000,0.000000,0.000000], #(256, 768), [0,0,0]), #($Editable_Mesh:Mesh_2258 # [0.000000,0.000000,0.000000], #(2048, 1057), [0,0,0]), #($Editable_Mesh:Mesh_2261 # [0.000000,0.000000,0.000000], #(512, 273), [0,0,0]), #($Editable_Mesh:Mesh_2262 # [0.000000,0.000000,0.000000], #(512, 281), [0,0,0]), #($Editable_Mesh:Mesh_2263 # [0.000000,0.000000,0.000000], #(2048, 1057), [0,0,0]), #($Editable_Mesh:Mesh_2265 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2266 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2267 # [0.000000,0.000000,0.000000], #(128, 73), [0,0,0]), #($Editable_Mesh:Mesh_2268 # [0.000000,0.000000,0.000000], #(128, 77), [0,0,0]), #($Editable_Mesh:Mesh_2269 # [0.000000,0.000000,0.000000], #(512, 273), [0,0,0]), #($Editable_Mesh:Mesh_2270 # [0.000000,0.000000,0.000000], #(2048, 1041), [0,0,0]), #($Editable_Mesh:Mesh_2271 # [0.000000,0.000000,0.000000], #(32, 21), [0,0,0]), #($Editable_Mesh:Mesh_2272 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2273 # [0.000000,0.000000,0.000000], #(128, 73), [0,0,0]), #($Editable_Mesh:Mesh_2274 # [0.000000,0.000000,0.000000], #(512, 265), [0,0,0]), #($Editable_Mesh:Mesh_2276 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2277 # [0.000000,0.000000,0.000000], #(128, 73), [0,0,0]), #($Editable_Mesh:Mesh_2278 # [0.000000,0.000000,0.000000], #(50, 60), [0,0,0]), ...)
-- items_to_delete_from_objs: Global:items_to_delete_from_objs : #()
-- ------------------------------------------------------
-- [stack level: 4]
-- called from delete_duplicates(); filename: C:\Users\Philips\Desktop\ninjaripper1.7.1\tools\3dmax_maxscript_importer\0000_delete duplicates (pre-construct_arrays) 9 (noprint) 2.ms; position: 2958; line: 49
-- Parameters:
-- equal_pos_bool: false
-- Locals:
-- equal_pos_bool: false
-- obj_dups: #()
-- Externals:
-- owner: undefined
-- delete_duplicates: Global:delete_duplicates : delete_duplicates()
-- mesh_data: Global:mesh_data : #(#($Editable_Mesh:Mesh_2184 # [0.000000,0.000000,0.000000], #(128, 28), [0,0,0]), #($Editable_Mesh:Mesh_2185 # [0.000000,0.000000,0.000000], #(128, 28), [0,0,0]), #($Editable_Mesh:Mesh_2256 # [0.000000,0.000000,0.000000], #(256, 768), [0,0,0]), #($Editable_Mesh:Mesh_2258 # [0.000000,0.000000,0.000000], #(2048, 1057), [0,0,0]), #($Editable_Mesh:Mesh_2261 # [0.000000,0.000000,0.000000], #(512, 273), [0,0,0]), #($Editable_Mesh:Mesh_2262 # [0.000000,0.000000,0.000000], #(512, 281), [0,0,0]), #($Editable_Mesh:Mesh_2263 # [0.000000,0.000000,0.000000], #(2048, 1057), [0,0,0]), #($Editable_Mesh:Mesh_2265 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2266 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2267 # [0.000000,0.000000,0.000000], #(128, 73), [0,0,0]), #($Editable_Mesh:Mesh_2268 # [0.000000,0.000000,0.000000], #(128, 77), [0,0,0]), #($Editable_Mesh:Mesh_2269 # [0.000000,0.000000,0.000000], #(512, 273), [0,0,0]), #($Editable_Mesh:Mesh_2270 # [0.000000,0.000000,0.000000], #(2048, 1041), [0,0,0]), #($Editable_Mesh:Mesh_2271 # [0.000000,0.000000,0.000000], #(32, 21), [0,0,0]), #($Editable_Mesh:Mesh_2272 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2273 # [0.000000,0.000000,0.000000], #(128, 73), [0,0,0]), #($Editable_Mesh:Mesh_2274 # [0.000000,0.000000,0.000000], #(512, 265), [0,0,0]), #($Editable_Mesh:Mesh_2276 # [0.000000,0.000000,0.000000], #(32, 23), [0,0,0]), #($Editable_Mesh:Mesh_2277 # [0.000000,0.000000,0.000000], #(128, 73), [0,0,0]), #($Editable_Mesh:Mesh_2278 # [0.000000,0.000000,0.000000], #(50, 60), [0,0,0]), ...)
-- items_to_delete_from_objs: Global:items_to_delete_from_objs : #()
The error goes on like this until stack level 386... the rest of the error looks similar to the section shown below (once again the error goes on for a long time, please see the previously mentioned .txt file for the full error):
-- [stack level: 387]
-- called from top-level
-- ########################################################################
-- C++ callstack:
-- (ucrtbase): (filename not available): malloc_base
-- (maxutil): (filename not available): GetWindowTextW
-- (MAXScrpt): (filename not available): InterfaceFunction::val_to_FPValue
-- (MAXScrpt): (filename not available): Generic::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): Generic::apply
-- (MAXScrpt): (filename not available): SourceFileWrapper::apply
-- (MAXScrpt): (filename not available): SourcePositionWrapper::apply_no_alloc_frame
-- (MAXScrpt): (filename not available): MacroEntry::DisableCompileGuard::DisableCompileGuard
-- (MAXScrpt): (filename not available): InitMacroScriptDir
-- (core): (filename not available): MacroButtonData::SetLabel
-- (core): (filename not available): MaxSDK::QMaxMultiResIconManager::trUtf8
-- (Qt5Core): (filename not available): QMetaObject::activate
-- (core): (filename not available): MaxSDK::QMaxMacroButtonUpdater::qt_static_metacall
-- (core): (filename not available): MaxSDK::QMaxMacroButtonUpdater::updateAll
-- (MAXScrpt): (filename not available): collect_nodes
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): Array::map
-- (MAXScrpt): (filename not available): clear_error_source_data
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): SourceFileWrapper::eval
-- (MAXScrpt): (filename not available): Generic::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): clear_error_source_data
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): SourceFileWrapper::eval
-- (MAXScrpt): (filename not available): Generic::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): clear_error_source_data
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): SourceFileWrapper::eval
-- (MAXScrpt): (filename not available): Generic::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
-- (MAXScrpt): (filename not available): clear_error_source_data
-- (MAXScrpt): (filename not available): Primitive::apply
-- (MAXScrpt): (filename not available): CodeTree::eval
Sometimes, instead of the error messagebox 'Stack Overflow Error' I get the error messagebox 'Unknown System Exception' (most of the time I get the stack overflow error messagebox, I have not been able to spot a reason for one of the other to occur yet). Other times no error messagebox is produced by 3ds max and windows problem reporting gives me a messagebox saying 3ds max has stopped working.
I tried finding more info about the '3ds max has stopped working' error using window's event viewer:
Files:
The scene containing 4000+ standard primitive objects on which the script works perfectly: https://drive.google.com/open?id=1ittqWwvqgJjrsNcNkbhM_mOHUnz1W-SH
The scene containing imported objects which causes the aforementioned stack overflow/unknown system exception errors:
https://drive.google.com/open?id=1JpncS9pJcYxGeZU4UI_uzmLIPnB9r0uJ
listener output (error) after stack overflow error message has occurred:
https://drive.google.com/open?id=1s-BplnpiM_sz3yfN4XVySmhcsK5zraeX
listener output (error) after unknown system exception error message has occurred:
https://drive.google.com/open?id=1QPl0e0RHcqKIPkMaorMRJm-Q_LyWvG1E
'delete_duplicates.ms' maxscript code:
https://drive.google.com/open?id=1FCpJNlgII6ouLYsh0ySjHXuTiKmfkWEK
Another .max scene I used for testing which produced similar errors:
https://drive.google.com/open?id=142JOth12rATD3sW4LlTmMX2vVzCLnmJs
Any suggestion on what I'm doing wrong/what might be the cause of these errors will be greatly appreciated, thank you!

Related

Eigen on STM32 works only until a certain size

I am trying to use Eigen C++ library on STM32F4 Discovery embedded board to perform some matrix operations in the future, specifically to do some kalman filtering on sensor data.
I tried linking against the standard c++ library and even tried to compile the program using g++ arm compiler.
typedef Eigen::Matrix<float, 10, 10> Matrix10d;
Matrix10d mat1 = Matrix10d::Constant(10, 10, 1);
Matrix10d mat2 = Matrix10d::Constant(10, 10, 2);
Matrix10d result;
result = mat1 * mat2;
I can compile the same code if the matrix size as been set to 7. If I cross that then the code wont compile and the eigen gives me a warning that
warning: argument 1 value '4294967295' exceeds maximum object size 2147483647
These are the partial error messages I am getting
n function 'throw_std_bad_alloc,
inlined from 'check_size_for_overflow at bla/bla/Eigen/src/Core/util/Memory.h:289:24
Here is the memory allocation in Linker script I am using
/*
* STM32F407xG memory setup.
* Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
*/
MEMORY
{
flash0 : org = 0x08000000, len = 1M
flash1 : org = 0x00000000, len = 0
flash2 : org = 0x00000000, len = 0
flash3 : org = 0x00000000, len = 0
flash4 : org = 0x00000000, len = 0
flash5 : org = 0x00000000, len = 0
flash6 : org = 0x00000000, len = 0
flash7 : org = 0x00000000, len = 0
ram0 : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */
ram1 : org = 0x20000000, len = 112k /* SRAM1 */
ram2 : org = 0x2001C000, len = 16k /* SRAM2 */
ram3 : org = 0x00000000, len = 0
ram4 : org = 0x10000000, len = 64k /* CCM SRAM */
ram5 : org = 0x40024000, len = 4k /* BCKP SRAM */
ram6 : org = 0x00000000, len = 0
ram7 : org = 0x00000000, len = 0
}
I am just running STM32F4 discovery board with unchanged Chibios configuration
# Stack size to be allocated to the Cortex-M process stack. This stack is
# the stack used by the main() thread.
ifeq ($(USE_PROCESS_STACKSIZE),)
USE_PROCESS_STACKSIZE = 0x400
endif
Update
I was not able to reproduce this error anymore. The sad thing is that I didn't do anything to solve the issue.
arm-none-eabi-gcc -c -mcpu=cortex-m4 -O3 -Os -ggdb -fomit-frame-pointer -falign-functions=16 -ffunction-sections -fdata-sections -fno-common -flto -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -Wall -Wextra -Wundef -Wstrict-prototypes -Wa,-alms=build/lst/ -DCORTEX_USE_FPU=TRUE -DCHPRINTF_USE_FLOAT=TRUE -DTHUMB_PRESENT -mno-thumb-interwork -DTHUMB_NO_INTERWORKING -MD -MP -MF .dep/build.d -I.
The above are the compiler options that I am using if anyone is interested.
Now I can multiply even 20x20 matrices with out any problem.
Matrix20d mat1 = Matrix20d::Constant(20, 20, 2);
// Multiply the matrix with a vector.
Vector20d vec = Vector20d::Constant(20, 1, 2);
Vector20d result;
systime_t startTime = chVTGetSystemTimeX();
result = mat1 * vec;
// Calculate the timedifference
systime_t endTime = chVTGetSystemTimeX();
systime_t timeDifference = chTimeDiffX(startTime, endTime);
chprintf(chp,"Time taken for the multiplication in milliseconds : %d\n", (int)timeDifference);
chprintf(chp, "System time : %d \n", startTime);
chprintf(chp, "Systime end : %d \n", endTime);
chprintf(chp, "Values in the vector : \n [");
for(Eigen::Index i=0; i < result.size();i++)
{
chprintf(chp, "%0.3f, ", result(i));
}
chprintf(chp, "] \n");
chThdSleepMilliseconds(1000);
It took about ~1ms to do the above computation.
I thought that there might be some problem with my compiler. So I tried with two versions of compilers
Version - 1
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 7-2017-q4-major) 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204]
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Version-2
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors 6-2017-q2-update) 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437]
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Convert string elements in series to floats in Red language

I want to convert many decimal numbers available as strings to floats in one go. I am trying following code which combines these strings into a series and then convert them to floats. This works all right but fails if there is an error:
a: "1.5"
b: ""
c: "3.7"
invars: [a b c]
print a
print type? a
set invars foreach x invars [append [] to-float reduce x] ; code to convert string series to float series;
print a
print type? a
The error is:
*** Script Error: cannot MAKE/TO float! from: ""
*** Where: to
*** Stack: to-float
For error correction, I tried following code:
temp: []
foreach x invars [
y: copy ""
either error? [set [y] to-float reduce x]
[append temp reduce x] ; put original value if not convertable
[append temp reduce y] ]
print temp
set invars temp
print a
print type? a
But this is also not working. Where is the problem and how can this be corrected?
forall invars [invars/1: load get invars/1]
>> invars
== [1.5 [] 3.7]
and if you want to get rid of the empty blocks
>> replace/all invars block! 0
== [1.5 0 3.7]
and if you really want to do all in (:less:) steps
forall invars [invars/1: either empty? invars/1: get invars/1 [0.0] [load invars/1]]
After you can set your variables again.
But if you want just set your variables, you have to do
foreach x invars [set :x load get x]
with to-float
foreach x invars [either empty? get x [set :x 0] [set :x to-float get x]]
and finally an all error safe version with to-float
foreach x invars [attempt [set :x to-float get x]]
== 3.7
>> a
== 1.5
>> b
== ""
>> c
== 3.7

Reading I2C data from GPS

I have a ublox M8 GPS connected to my Raspberry Pi via I2C and I'm trying to pull data from it.
I'm using python to attempt to get data via the I2C connection with the GPS module but all I get back in an incrementing number each request.
I'm not sure what I'm doing wrong.
i2cdetect -y 1 returns:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- 42 -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Python Code
import smbus
import time
bus = smbus.SMBus(1)
address = 0x42
bus.read_byte_data(address,0x00)
bus.read_byte(address)
returns:
160
161
I am experimenting with this also.
Using some info from this page about how to use the smbus.
And using the arduino code from here (note the 0xfd and 0xff bytes aren't used below)
I can get the GNGGA string below ($GNGGA means both US and Russian GPS systems are being used):
import time
import json
import smbus
import logging
BUS = None
address = 0x42
gpsReadInterval = 0.1
LOG = logging.getLogger()
# GUIDE
# http://ava.upuaut.net/?p=768
GPSDAT = {
'strType': None,
'fixTime': None,
'lat': None,
'latDir': None,
'lon': None,
'lonDir': None,
'fixQual': None,
'numSat': None,
'horDil': None,
'alt': None,
'altUnit': None,
'galt': None,
'galtUnit': None,
'DPGS_updt': None,
'DPGS_ID': None
}
def connectBus():
global BUS
BUS = smbus.SMBus(1)
def parseResponse(gpsLine):
global lastLocation
gpsChars = ''.join(chr(c) for c in gpsLine)
if "*" not in gpsChars:
return False
gpsStr, chkSum = gpsChars.split('*')
gpsComponents = gpsStr.split(',')
gpsStart = gpsComponents[0]
if (gpsStart == "$GNGGA"):
chkVal = 0
for ch in gpsStr[1:]: # Remove the $
chkVal ^= ord(ch)
if (chkVal == int(chkSum, 16)):
for i, k in enumerate(
['strType', 'fixTime',
'lat', 'latDir', 'lon', 'lonDir',
'fixQual', 'numSat', 'horDil',
'alt', 'altUnit', 'galt', 'galtUnit',
'DPGS_updt', 'DPGS_ID']):
GPSDAT[k] = gpsComponents[i]
print gpsChars
print json.dumps(GPSDAT, indent=2)
def readGPS():
c = None
response = []
try:
while True: # Newline, or bad char.
c = BUS.read_byte(address)
if c == 255:
return False
elif c == 10:
break
else:
response.append(c)
parseResponse(response)
except IOError:
time.sleep(0.5)
connectBus()
except Exception, e:
print e
LOG.error(e)
connectBus()
while True:
readGPS()
time.sleep(gpsReadInterval)
Here is some of the output.
$GNGGA,,,,,,0,00,99.99,,,,,,*56
{
"galt": "",
"DPGS_updt": "",
"lon": "",
"strType": "$GNGGA",
"lat": "",
"alt": "",
"fixTime": "",
"lonDir": "",
"numSat": "00",
"fixQual": "0",
"altUnit": "",
"galtUnit": "",
"horDil": "99.99",
"latDir": "",
"DPGS_ID": ""
}
I have it indoors away from windows, etc. So bad data expected.
Hope this helps.

SPIN verifier: cannot prove LTL formulae

I have quite simpe sender-receiver protocol:
#define SZ 4
int sent = 0;
int received = 0;
chan ch = [SZ] of {int};
int varch;
init {
do
:: ((len(ch) < SZ) && (received != 1)) ->
d_step {
ch ! 1; sent = 1; printf("sent\n");
}
:: ((len(ch) == SZ) || ((received == 1) && (len(ch) > 0))) ->
d_step {
ch ? varch; received = 1; printf("received\n");
}
:: 1 -> /* simulates ramdomness */
atomic {
printf("timeout1\n");/*break; */
}
od;
}
which sends four packets and then receives them. Then I try to prove property: always send implies eventually receive:
ltl pr { [] ( (sent == 1) -> (<> (received == 1)) ) }
...and nothing happens: SPIN does not find both this property prove and its negation.
Why?
So, upon quick inspection, the LTL property cannot possibly be satisfied. The LTL property includes always but one viable execution is for the do::od statement to take the /* simulates randomness */ option forever. In that case, no queue will be 'received' and the LTL fails.
My SPIN run confirms the above (I put your code into a file 'sr.pml')
$ spin -a sr.pml
$ gcc -o pan pan.c
$ ./pan -a
pan:1: acceptance cycle (at depth 16)
pan: wrote sr.pml.trail
(Spin Version 6.3.2 -- 17 May 2014)
Warning: Search not completed
+ Partial Order Reduction
Full statespace search for:
never claim + (pr)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 60 byte, depth reached 20, errors: 1
12 states, stored (14 visited)
0 states, matched
14 transitions (= visited+matched)
0 atomic steps
hash conflicts: 0 (resolved)
Stats on memory usage (in Megabytes):
0.001 equivalent memory usage for states (stored*(State-vector + overhead))
0.290 actual memory usage for states
128.000 memory used for hash table (-w24)
0.534 memory used for DFS stack (-m10000)
128.730 total actual memory usage
pan: elapsed time 0 seconds
And then we can see the path with:
$ spin -p -t sr.pml
ltl pr: [] ((! ((sent==1))) || (<> ((received==1))))
starting claim 1
using statement merging
Never claim moves to line 4 [(1)]
2: proc 0 (:init::1) sr.pml:8 (state 1) [(((len(ch)<4)&&(received!=1)))]
4: proc 0 (:init::1) sr.pml:9 (state 5) [ch!1]
4: proc 0 (:init::1) sr.pml:10 (state 3) [sent = 1]
sent
4: proc 0 (:init::1) sr.pml:10 (state 4) [printf('sent\\n')]
Never claim moves to line 3 [((!(!((sent==1)))&&!((received==1))))]
6: proc 0 (:init::1) sr.pml:8 (state 1) [(((len(ch)<4)&&(received!=1)))]
Never claim moves to line 8 [(!((received==1)))]
8: proc 0 (:init::1) sr.pml:9 (state 5) [ch!1]
8: proc 0 (:init::1) sr.pml:10 (state 3) [sent = 1]
sent
8: proc 0 (:init::1) sr.pml:10 (state 4) [printf('sent\\n')]
10: proc 0 (:init::1) sr.pml:8 (state 1) [(((len(ch)<4)&&(received!=1)))]
12: proc 0 (:init::1) sr.pml:9 (state 5) [ch!1]
12: proc 0 (:init::1) sr.pml:10 (state 3) [sent = 1]
sent
12: proc 0 (:init::1) sr.pml:10 (state 4) [printf('sent\\n')]
14: proc 0 (:init::1) sr.pml:8 (state 1) [(((len(ch)<4)&&(received!=1)))]
16: proc 0 (:init::1) sr.pml:9 (state 5) [ch!1]
16: proc 0 (:init::1) sr.pml:10 (state 3) [sent = 1]
sent
16: proc 0 (:init::1) sr.pml:10 (state 4) [printf('sent\\n')]
<<<<<START OF CYCLE>>>>>
18: proc 0 (:init::1) sr.pml:16 (state 11) [(1)]
timeout1
20: proc 0 (:init::1) sr.pml:18 (state 12) [printf('timeout1\\n')]
spin: trail ends after 20 steps
#processes: 1
sent = 1
received = 0
queue 1 (ch): [1][1][1][1]
varch = 0
20: proc 0 (:init::1) sr.pml:7 (state 14)
20: proc - (pr:1) _spin_nvr.tmp:7 (state 10)
1 processes created
The <<<<<START OF CYCLE>>>> shows sr.pml at line 16 (:: 1 -> ...) executed forever. Also, there are other failures of the LTL. Run the SPIN search with './pan -a -i' to find the shortest trail; it indicates that your LTL isn't finding what you intend to find.

How to format a number with padding in Erlang

I need to pad the output of an integer to a given length.
For example, with a length of 4 digits, the output of the integer 4 is "0004" instead of "4". How can I do this in Erlang?
adding a bit of explanation to Zed's answer:
Erlang Format specification is: ~F.P.PadModC.
"~4..0B~n" translates to:
~F. = ~4. (Field width of 4)
P. = . (no Precision specified)
Pad = 0 (Pad with zeroes)
Mod = (no control sequence Modifier specified)
C = B (Control sequence B = integer in default base 10)
and ~n is new line.
io:format("~4..0B~n", [Num]).
string:right(integer_to_list(4), 4, $0).
The problem with io:format is that if your integer doesn't fit, you get asterisks:
> io:format("~4..0B~n", [1234]).
1234
> io:format("~4..0B~n", [12345]).
****
The problem with string:right is that it throws away the characters that don't fit:
> string:right(integer_to_list(1234), 4, $0).
"1234"
> string:right(integer_to_list(12345), 4, $0).
"2345"
I haven't found a library module that behaves as I would expect (i.e. print my number even if it doesn't fit into the padding), so I wrote my own formatting function:
%%------------------------------------------------------------------------------
%% #doc Format an integer with a padding of zeroes
%% #end
%%------------------------------------------------------------------------------
-spec format_with_padding(Number :: integer(),
Padding :: integer()) -> iodata().
format_with_padding(Number, Padding) when Number < 0 ->
[$- | format_with_padding(-Number, Padding - 1)];
format_with_padding(Number, Padding) ->
NumberStr = integer_to_list(Number),
ZeroesNeeded = max(Padding - length(NumberStr), 0),
[lists:duplicate(ZeroesNeeded, $0), NumberStr].
(You can use iolist_to_binary/1 to convert the result to binary, or you can use lists:flatten(io_lib:format("~s", [Result])) to convert it to a list.)
Eshell V12.0.3 (abort with ^G)
1> F = fun(Max, I)-> case Max - length(integer_to_list(I)) of X when X > 0 -> string:chars($0, X) ++ integer_to_list(I); _ -> I end end.
#Fun<erl_eval.43.40011524>
2> F(10, 22).
"0000000022"
3> F(3, 22345).
22345