Code Monkey home page Code Monkey logo

Comments (20)

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

Funny you should mention this. I was thinking that the G29 F B L R options should be more flexible, and was looking into why the G29 code does not permit the X and Y boundaries to exceed the build radius. It seems like an unnecessary restriction. I want to remove the restriction and I'm looking over the consequences (e.g. adversely affecting the bed level interpolation).

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

The main issue is that the 55mm spec radius for the MPMD is all that the stock bed sticker is set to. There is no room for error in bed movement, sticker placement, M666 adjustment, and G29 probing without going outside the bed sticker and having a drop in height. With an upgraded bed which has a 115mm or 120mm glass or magnetic bed, there is enough tolerance for misplacement, but not enough for probing further than the 55mm radius. The other issue on the MPMD is the nonlinear response with a larger radius. That is why probing at a constant radius would be superior if possible.

EDIT: I should point out that every printer shipped from the factory prints about 2% small. I figure that was on purpose because the G29 P5 probes right to the 55mm radius. The factory sticker alignment to the actual center of where the home sensor alignments will come down onto the bed has too much tolerance to work. So, instead of fixing their tolerance issues, or making the factory bed sticker bigger, they "fixed" it in the FW settings. Just like they "fixed" the underpowered power supply in the FW. The printer has good bones, but abusive parents. That is what happens when the manufacturing line changes the design to make it cheaper to make after the design engineers are done (speaking as the design engineer who has had to fix products again after the manufacturing engineers decided to save money by removing important parts).

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

@see3d Yes, that's the mechanical issue. In Marlin, as G29 probes the bed, it computes (rather than probes) a bed mesh value for any grid point where the radius exceeds 55mm. But for G29 R<-n> L<n> F<-n> B<n>, Marlin requires n ≤ 55. Since the command won't probe those points anyway, why add the restriction? I thought removing the restriction might be a way to create what would effectively be a smaller grid pattern (fewer useful grid points). Though, an effectively smaller grid may not be all that useful.

As far as achieving a probe pattern that includes the "extra" grid points in your example: I'm not sure of my math, 3R/sqrt(10), but I think n = 52 will place the points of interest inside a 55mm radius. And for a 50mm radius, n = 47.

So, G29 R-52 L52 F-52 B52 V3 should produce the probe pattern you described (n = 50 should, too).

And R/sqrt(2) places all of the 7x7 grid points inside the radius, R. For a 55mm radius, n = 38. For the 50mm radius, n = 35.

To test radial patterns, I was planning to generate non-square mesh data using G30; use the data to create an equivalent 7x7 square mesh; and then feed the square mesh into G29 manually. On the surface, I'd say it will make no difference, but... since the mesh leveling (probing) also includes machine calibration errors, I think where the bed is probed could indeed make a difference. It will be interesting to find out.

editorializing...

To me, the mpmd printer is a cheap printer, but design-wise a good set of trade-offs. But alas, as you said, then there the other things: the power supply issue, the build area fabrication, the stepper motors wired differently at every turn, ... lazy "fixes" to me -- the Dr. Jekyll, Mr. Hyde of conscientious design engineer and whatever a company turns into to get a product out the door.

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

@aegean-odyssey Those grid n numbers, look about right just by eye. A grid of n=50 should be good enough to land on a factory bed sticker with enough tolerance after the preliminary calibrations are completed. On the radial one, I choose radius=50 for a few reasons. It keeps things inside the sticker, it is easy to check calibration points at 100mm diameter, few parts will go over 100mm, and the nonlinear arm motion gets hard to extrapolate beyond that with only a few probe points.

I agree with your idea. It should be possible with an external application to probe the bed like I do with the G30 in great detail, then write the grid mesh points back to the drive, especially if it could handle a larger matrix, including points external to the bed. Sort of a inverse calculation of the points so they come out right in the calculated mesh for printing.

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

Now running 119r13. Below are 4 screenshots. The first is with my alignment algorithm applied to the TX, TY, TZ radial axis using G30 Z value (no G29 compensation). The second is after G29 M500 and then probe the axis again using the G30 Q value.

The alignment of the bed without the G29 mesh is actually good enough to print on, but could be better.
The G29 Mesh gave an excellent result in the X and TY axis. Some improvement on the Y axis, but did not work well for the other axis. Overall, applying the mesh made the bed worse.

The 3rd screenshot is probing just the points that made up the G29 in the same order using G30 Z value (no G29 compensation). The graph points are are just points, the colored lines have no significance other than showing the G29 sequence and wraps around to the next line.

The 4th plot is using G30 Q value. Now that is what it should look like!
So the problem is the G29 pattern and how it is not able to interpolate to the delta axis for a good compensation.

Screen Shot 2020-08-05 at 5 40 49 PM
Screen Shot 2020-08-05 at 5 41 38 PM
Screen Shot 2020-08-05 at 6 14 20 PM
Screen Shot 2020-08-05 at 6 14 34 PM

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

Interesting. Let me make sure I'm following.

The bed leveling mesh, G29, is not so much used to correct errors in the build surface, but principally it used to correct errors in the machine's geometry settings, i.e. the G33 calibration. And due to the errors in those parameters, Z(x,y) error measured via G29 is wrong -- akin to using a faulty ruler to make a measurment. The proposed solution is to choose a set of probe points, that despite the errors in the probing process, somehow reveal the underlying errors in the machine's geometry. Enough so, that a mesh created from these points does the trick.

I'm almost set up to give this solution a try.

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

Since the bed on the MPMD is so small, there is not as much chance for large deviations. The thin aluminum build plate is not perfectly flat though, so can benefit from G29 correction. With a 3mm glass bed topper like I have, that source of error is eliminated from my testing. What is left is the mechanical errors in the machine geometry, which are significant. So yes, picking probe points that align with the delta geometry can be more effective in removing this significant source of error, since only a few points are probed and must be interpolated to other points during printing.

One other source of probing error that can show up in these charts is due to mechanical backlash. It can be reduced by having consistent motion direction in the probing sequence. That is why the final chart looks so close. I followed the same path that the G29 used to get to each point.

However, measurement deviation from where the top of the bed is located and where the switch picks up the signal is also a source of error, but it is undetectable in these tests. It can only be seen in the results of how the first layer is printed (which is the main reason for the G29 correction). To correct for those errors in a stock printer, the bed hold down clips have to be shimmed and a bed tilt geometry calculation included in the probing data. I mention this because the probing test may show a perfect bed alignment and the printed first layer may not agree with that result.

As an aside, I modified my bed hold down clips and bed switches to mechanically eliminate this source of error. I replace the bed switches with others that do not have any switch throw or bed tilt during probing. If my chart as shown above shows a perfect bed alignment, then my first layer also looks perfect (aside from mechanical backlash).

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

@see3d, yours is the muscle car of MPMD printers! Truly the most souped-up model. My printer (and I'd say the stock printer, in general) is more on the Yugo end of the spectrum. I surely don't want the firmware to be an obstacle to enthusiasts, but for those driving the economy model, I'd like the firmware to provide a little smoother ride and a bit more joy from the experience. Your insights have been quite helpful.

I've put together the start of some online tools to help collect data from the printer, and to make some experimental efforts to compensate for calibration errors. Currently it amounts to a few bed probing patterns, and a few bed mesh correction routines -- my first attempt at using GitHub's Pages to serve up online tools. It started out as a couple of command-line python routines, but I think the web route will be easier to support if it happens to draw any attention. I've provided a link below.

[MPMD Experimental]

 

Since mpmd_marlin_1.1.x firmware can save output to a file on the micro SD card, the basic idea is:

  • choose a bed probing pattern (online tool); download the g-code command file to run on the printer
  • place the command file on the micro SD card, use print to select and run the command
  • retrieve the data file (e.g. \G30PROBE.TXT) from the card
  • select a bed mesh correction (online tool) and supply the data file; download the mesh correction file
  • place the file on the micro SD card, use print to select and run the command to create a new mesh

I hope it turns out to be less cumbersome than it looks from the description above.

I've yet to dive into testing strategies, but if the inverse distance weight (IDW) interpolation works to produce a grid mesh from a non-grid mesh, then the IDW algorithm might be simple and small enough to squeeze into the firmware.

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

Actually, mine is not the most souped up model. I have tried to only add things that were cheap and plug in so that it could be reverted back to stock (that is until I bit the bullet and changed the Bowden tube path to go up and over through the top plate down to the hot end) . Others have added new extruders, new hot ends, new carriages and arms and SKR controllers. I am just trying to address the things that keep the MPMD from being an accurate functional model printing machine. The journey is not over and new FW and associated calibration tools are important pieces. Please keep up your excellent support from the FW end.

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

Here is a quick hand drawn graph of what my MPMD well aligned bed looks like around the diameter at a 50mm radius (solid line), and at 37.5mm radius (dotted line). At 37.5mm and in towards the center, it is flat within the measurement margin of error. At 50mm, the error has progressed to a wavy pattern that is high at the towers and low opposite the towers. It will obviously get worse at 55mm radius, but it is rare to print that far out.

The current G29 pattern can not interpolate this pattern, because it does not probe it in the 6 places that will show it. I am in the middle of a 2 week long production run of 1.25 hour prints that prints out a circle to 53mm radius. With the G29 correction, the wave pattern can be seen in the fist layer as scraping the bed at the towers and almost not sticking opposite the towers.

For some reason, the previous M4MPMD FW did a much better job at correcting this error when I previously ran this part. I would revert, but the pressure advance makes a nicer print, so I don't want to go backwards now.

Perhaps if the MPMD was designed with arms that were a few mm longer, this would not have been as bad?

2020-08-11_125913

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

Marlin4MPMD's G29 probing code is pretty much identical to the G29 code in the mpmd_marlin_1.1.x firmware, and both firmware's mesh interpolation seem to produce identical results. I think what we're seeing here is genuine calibration error (in the G33 sense).

The two firmware differ in the tapping method (2 or 3 taps) and vastly in the auto-calibration procedure, the G33 code.

Marlin4MPMD's G33 code seems to only adjusts the endstops (M666); there is no other "tuning" of the machine's geometry. It uses a given radius to probe the bed at the three tower angles, plus it probes the center to compute an endstop adjustment. It employs a simplistic (not a bad thing) and straight-forward method to adjust the endstops.

By the time we get to Marlin 1.1.x (and the mpmd_marlin_1.1.x firmware), the G33 code repeatly tries to adjust the endstops, the radius, and tower angle trims, trying reduce some error measurement from the previous trial to the current trial; it uses a handful a probing patterns in its attempts.

I am not sure that Marlin's latest G33 is doing a good job -- it's a complicated process that I'm just looking into now. My sense is that the process need not be so complicated; that all of the tapping, measuring, and figuring doesn't improve the "correctness" of the auto-calibrated parameters; especially with the MP Mini Delta's measurement errors. Still, I need to understand it better -- the "failing" here could entirely be the difference between using "two taps, use the last" and the "average three taps" methods of probing. Something to try.

The up at the tower, down away from the tower seems like maybe endstop calibration error. You've much more experience, it's only a hunch on my end. Btw, are you using the AUTO_CALIBRATE.gcode file/command? I ask, just in case, because the command deliberately adjusts the mesh to a plane via G29 C1, which is probably not appropriate for your calibration.

from mpmd_marlin_1.1.x.

mulcmu avatar mulcmu commented on September 7, 2024

@aegean-odyssey I really like the start of your MPMD experimental online calibration interface. It has potential to really lower the complexity for newcomers. It eliminates need to setup python/usb connection to printer and diagnose any problems with the script execution. Plus should be easier for developers to maintain.

One idea that I had for a calibration script was integrating carbon paper distance measurements with the z probe data. This way calibration algorithm could compute x and y locations for the probe points as well. This extra data might be able allow computation of tower angle and the individual arm R/L offsets.

@see3d mentioned above controlling the approach direction for the probe points to standardize the mechanical backlash. Another option to deal with the backlash would be randomizing the probe pattern and averaging the results for each point over a few passes. While this might not have as repeatable measurements it might be more representative of actual movement when printing and worth some investigation.

EDIT: Here was a link discussing the randomized probing with delta calibration: http://boim.com/DeltaUtil/DeltaCalibrationTools.html

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

I am only using G30 not G33 in my calibration spreadsheet. None of the automated ones are good enough yet, except I could use the G33 in M4MPMD for adjusting the M666, since it used my algorithm. However, my algorithm has evolved since then and I do not adjust that one by itself anymore. I am averaging 6 taps in 1.1.x (two groups of 3). I have my own process that is based on making the M666 towers match the same, but at a smaller radius to get away from the outer edge deviations. My spreadsheet Adjusts all the M666 and M665 alignment parameters until it can make the tilts and bowls come within certain limits and the arms should match each other as close as it can. Any mismatch in the arm probes throws off the delta symmetry. There is one cycle of probes along each delta axis, then it calculates a new gcode for the next cycle, getting closer with each cycle. It will take fewer cycles if the printer has been aligned in the past, so it is not so far out of alignment. It will usually take about 6 cycles to get close, but could take a dozen. When I don't change the probe gcode, then in successive runs I can see the amount of error (noise), in the measurement system. It is usually about 0.02mm. However, not every cycle makes the alignment better. The different alignment parameters interact, so bringing one into closer alignment can push another further out. Measurement noise can be a contributing factor to this, so having more consistent measurements helps reduce the number of cycles it takes.

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

@mulcmu Yes, it is possible to do a lot of random motions, but it would be an enormous number of probes to gain statistical validity. It would be a good approach as a study to validate an approach, but I would not want to wait hours for it to do an alignment. Perhaps an alternative would be to take two passes. One all in one direction and the other in the opposite direction. Then average the same point from each. What we really want is monotonicity in our probes. That way we know that extrapolations get us closer to the correct value. In the case of characterizing the shape of the curve that an arm takes across its motion, going in one direction only will give that shape. Going in reverse, should give the same shape, but with a constant offset. It is the shape we want, and we want that shape to be matched between the 3 arms. The Purpose of the alignments should be to make parameter or physical adjustments to make that happen. Then generalized extrapolations will work well for unprobed points between the arms.

An interest point, the G29 P5 ABL often does a poor job in getting a good first layer. However, doing the spreadsheet alignments first for M665/6, then doing the G29 P5 gave excellent results. ABL can not correct all the sins with just a few probes.

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

@mulcmu, the experimental online tools site is taking shape. I will probably come back to you for the ideas you mention when I'm further along with it.

My focus has been to use the firmware's ability to capture output in a disk file to add some ancillary tools and facilities that aren't part of the firmware proper. I started with some command line python scripts. But when thinking about adding a graphical user interface, the "online tools" approach seemed far easier for me to support -- there is no "installation" help needed and the browser imposes a certain discipline on the developer (me) to keeps things cross-platform compatible. The little bit of extra effort to implement client-side only tools (the online tools site is entirely static pages) has been a fun constraint to play with.

The firmware needs a few more tweaks to assist the effort. @see3d's comments have highlighted the shortcomings and hopefully with the next release, I'll address most of these. While my focus for the firmware is as an upgrade for the stock printer, I do want to eliminate obstacles for the sophiscated user, modder, and experimenter. The next firmware release, r14, alters the probing method (2 independent taps, instead of 3 averaged taps) and provides a way to relay the unadulterated measurements. I think these changes will make it possible to collect data and completely configure the printer independent of the firmware's automatic calibration procedures.

I also like the possibilities of externally directing the machine to calibrate it. @PurpleHullPeas python script is a great example. I imagine it also could take the form of an OctoPrint plugin. I keep an eye on the project, and work to keep the firmware amenable to such strategies, as well.

Also, it does look like G33 options can direct the printer to do random probing during the calibration -- the G33 code does a great many things that I'd like to better understand and exploit. I started out not wanting to change Marlin, but I've thrown in the towel on that score. The G33 code will be my next assault.

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

I've added a viewer to the Online Tools; so I've a rudimentary way to assess the calibration strategies. The tool looks through the file (e.g. CALIBRAT.TXT) to extract probe results and the bed level mesh. If it finds both, it will use the same bilinear z-offset correction as the printer to see how well the calibration performs.

It's back the firmware now to get the G33 code to produce probing information along the lines of the G29 and G30 codes. There are some conflicts in the way the three use the probing code they share, so it's time to bring them in sync anyway. I'm also thinking that the G33 code might be a better place to put the non-rectangular probe patterns that have been suggested by @see3d -- I believe the code is all ready running similar patterns.

Attached is sample output from the tool with actual data -- a rather lousy calibration result.
CALIBRAT.TXT.pdf

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

Here is the actual Gcode that I am using to probe my bed for calibration. This is the 6 cross radial with anti-backlash.

M111 S128 ;give me the raw data

; The M665/6 adjustment parameters generated for this alignment pass
M665 A1.68 B-0.83 C-0.27
M665 D0.93 E-0.31 F-0.31
M666 X-0.7 Y-0.68 Z0
M665 L122.3 R62.96

; The special marker near 0,0 to validate the result data for the spreadsheet
G28
G90
G0 Z10 F5000
G0 X0.01 Y0.01
G30
G0 Z10

;Z
G0 X0 Y55
G0 X0 Y50
G30
G0 Z10
G30
G0 Z10

G0 X0 Y37.5
G30
G0 Z10
G30
G0 Z10

G0 X0 Y25
G30
G0 Z10
G30
G0 Z10

G0 X0 Y0
G30
G0 Z10
G30
G0 Z10

G0 X0 Y-25
G30
G0 Z10
G30
G0 Z10

G0 X0 Y-37.5
G30
G0 Z10
G30
G0 Z10

G0 X0 Y-50
G30
G0 Z10
G30
G0 Z10

;X
G0 X-48.301 Y-28
G0 X-43.301 Y-25
G30
G0 Z10
G30
G0 Z10

G0 X-32.476 Y-18.75
G30
G0 Z10
G30
G0 Z10

G0 X-21.651 Y-12.5
G30
G0 Z10
G30
G0 Z10

G0 X0 Y0
G30
G0 Z10
G30
G0 Z10

G0 X21.651 Y12.5
G30
G0 Z10
G30
G0 Z10

G0 X32.476 Y18.75
G30
G0 Z10
G30
G0 Z10

G0 X43.301 Y25
G30
G0 Z10
G30
G0 Z10

;Y
G0 X48.301 Y-28
G0 X43.301 Y-25
G30
G0 Z10
G30
G0 Z10

G0 X32.476 Y-18.75
G30
G0 Z10
G30
G0 Z10

G0 X21.651 Y-12.5
G30
G0 Z10
G30
G0 Z10

G0 X0 Y0
G30
G0 Z10
G30
G0 Z10

G0 X-21.651 Y12.5
G30
G0 Z10
G30
G0 Z10

G0 X-32.476 Y18.75
G30
G0 Z10
G30
G0 Z10

G0 X-43.301 Y25
G30
G0 Z10
G30
G0 Z10

;Axis X
G0 X55 Y0
G0 X50 Y0
G30
G0 Z10
G30
G0 Z10

G0 X37.5 Y0
G30
G0 Z10
G30
G0 Z10

G0 X25 Y0
G30
G0 Z10
G30
G0 Z10

G0 X0 Y0
G30
G0 Z10
G30
G0 Z10

G0 X-25 Y0
G30
G0 Z10
G30
G0 Z10

G0 X-37.5 Y0
G30
G0 Z10
G30
G0 Z10

G0 X-50 Y0
G30
G0 Z10
G30
G0 Z10

;UL
G0 X-28 Y48.301
G0 X-25 Y43.301
G30
G0 Z10
G30
G0 Z10

G0 X-18.75 Y32.476
G30
G0 Z10
G30
G0 Z10

G0 X-12.5 Y21.651
G30
G0 Z10
G30
G0 Z10

G0 X0 Y0
G30
G0 Z10
G30
G0 Z10

G0 X12.5 Y-21.651
G30
G0 Z10
G30
G0 Z10

G0 X18.75 Y-32.476
G30
G0 Z10
G30
G0 Z10

G0 X25 Y-43.301
G30
G0 Z10
G30
G0 Z10

;LL
G0 X-28 Y-48.301
G0 X-25 Y-43.301
G30
G0 Z10
G30
G0 Z10

G0 X-18.75 Y-32.476
G30
G0 Z10
G30
G0 Z10

G0 X-12.5 Y-21.651
G30
G0 Z10
G30
G0 Z10

G0 X0 Y0
G30
G0 Z10
G30
G0 Z10

G0 X12.5 Y21.651
G30
G0 Z10
G30
G0 Z10

G0 X18.75 Y32.476
G30
G0 Z10
G30
G0 Z10

G0 X25 Y43.301
G30
G0 Z10
G30
G0 Z10
G28

from mpmd_marlin_1.1.x.

see3d avatar see3d commented on September 7, 2024

I rate the quality of the alignment by What % of the bed is within 0.5mm, and 0.10mm after adjusting the Z offset to the median. Min/Max is also a consideration, but the goodness weighting is higher towards the center of the plate.

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

Thank you for the information. I appreciate it.

For the G33 code, Marlin seems to devote quite a bit space to generating patterns. It moves forward and back through the patterns; I guess to mitigate measurement issues like backlash. Since we're not trying to be all things to all people, though, your approach seems more sensible -- find the small set of patterns that do the best job on this particular printer. With this strategy in mind, I think I can rewrite the G33 code to be more compact. I'm working on changing its output to resemble the G29 and G30 codes so that if I add a new option for "dryrun" (e.g. G33 D), its patterns can be used generically to probe the bed, as well.

Your center-weighted quality metric makes sense. I worked myself into a ton of confusion surrounding a quality metric; mostly trying to get the silly color bars to show more green as quality improved. Currently, the limits show the ±3σ range (removing the mean). I chose 3σ within ±0.015mm as the "very good" range, 3σ within ±0.030mm as the "good" range, 3σ within ±0.045mm as the "fair" range, and 3σ outside of ±0.045mm as the "poor" range. It's definitely something I'll need to revisit.

But for now it's back to the firmware.

from mpmd_marlin_1.1.x.

aegean-odyssey avatar aegean-odyssey commented on September 7, 2024

Closing this issue to move it into the Discussions area under the category of "A Better Calibration". There's too much good information here to leave it buried in a closed git issue.

from mpmd_marlin_1.1.x.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.