Diseño de algoritmos críticos: implementación

  1. Diseño
  2. Implementación
  3. Integración


Cuando recién comenzaba mi carrera en desarrollo profesional, no entendía por qué era necesario el código abierto. Yo tampoco entendía los proyectos paralelos, de hecho. Después de todo, ¿por qué dar un valioso trabajo gratis? A lo largo de los años, a través del trabajo en proyectos de código abierto, así como trabajando con Apex.AI, ROS 2 y Autoware.Auto, he llegado a comprender el código abierto.



A los ingenieros les encanta crear. La gente quiere reconocimiento y gratitud.



Cuando combina estos factores, tiene el camino hacia el código abierto. Si estoy construyendo algo para satisfacer mis necesidades creativas, ¿por qué no dejar que todos los demás aprecien mi trabajo y encuentren un uso práctico y valor en él? Después de todo, no estoy haciendo esto por el dinero.



En cuanto a los proyectos paralelos, me di cuenta de su encanto solo después de comenzar a desarrollarme profesionalmente y abordar con más cuidado varios aspectos de mi trabajo. Para crear un producto confiable que la gente pagará, a menudo es necesario restringir artificialmente los flujos de trabajo. Análisis de diseño. Revisión de código. Estándares de codificación, guías de estilo, métricas de cobertura de prueba, y así sucesivamente. No me malinterpreten: todas estas son cosas buenas que probablemente sean necesarias para desarrollar un producto de calidad. Es solo que a veces un desarrollador quiere un poco de libertad. Un desarrollador puede querer crear lo que quiere, cómo quiere y cuándo quiere. No hay reuniones, revisiones o casos de negocios.



Entonces, ¿cómo combina estos aspectos cuando se trata de desarrollar algoritmos seguros o de alta calidad? Una gran parte del atractivo del mundo de código abierto es la libertad, y las prácticas que ayudan a garantizar que se desarrolle un código más confiable limitan esa libertad.



La respuesta que encontré es seguir una disciplina abierta y consistente, y usar liberalmente muchas herramientas geniales que provienen del mundo del código abierto.



Planificación de proyectos de código abierto.



Los ingenieros necesitan un conjunto de habilidades específicas para abordar estos problemas. Los ingenieros deben centrarse, necesitan buenas habilidades para resolver problemas. Los ingenieros también deben ser capaces de separar las preocupaciones y tener las habilidades básicas sólidas necesarias para obtener conocimiento de todo lo anterior.



Este conjunto de habilidades en particular puede llevarnos a los ingenieros a estar algo abrumados.



A pesar de todas las habilidades técnicas que tienen los ingenieros, en última instancia están limitadas en sus capacidades. Yo diría que la mayoría de los desarrolladores no pueden tener en cuenta todo el proyecto mientras escriben líneas de código individuales. Además, diría que la mayoría de los desarrolladores no pueden programar y mantener un proyecto más amplio en su cabeza sin olvidarse de los objetivos comerciales generales.



Aquí es donde entra en juego la magia negra de la gestión de proyectos.



Si bien los desarrolladores podemos tener relaciones algo controvertidas con los gerentes de recursos humanos, técnicos o de proyectos, debe reconocerse que todas estas personas están haciendo un trabajo importante. Los mejores representantes de la profesión de gestión se aseguran de que los desarrolladores no pierdan de vista tareas importantes, y los irritantes molestos no nos impiden disparar problemas con todas las armas.



Y aunque comprendemos la importancia de los diferentes gerentes, las personas con estas habilidades generalmente no se involucran en un proyecto típico de código abierto cuyo objetivo es divertirse.



Entonces, ¿qué debemos hacer entonces?



Bueno, los desarrolladores podemos ensuciarnos las manos y pasar un poco de tiempo planificando con anticipación.



No entraré en estas conversaciones, ya que en la publicación anterior entré en detalles sobre las etapas de diseño y planificación del desarrollo. La conclusión es que, teniendo en cuenta el diseño y la arquitectura, para los cuales, como regla, consisten en muchos componentes y forman algunas dependencias, en su propio proyecto usted forma el diseño usted mismo y recopila sus componentes por separado.



Volviendo al aspecto de la planificación del proyecto, me gusta comenzar con los componentes con menos dependencias (piense un minuto!) y luego continuar trabajando, agregando apéndices de implementación donde sea necesario para mantener el desarrollo. Con este orden de trabajo, generalmente puede crear muchos tickets (con algunas dependencias en ellos correspondientes a sus dependencias arquitectónicas, si su rastreador de tareas tiene esa funcionalidad). Estos tickets pueden contener algunas notas generales que es útil tener en cuenta antes de sumergirse en cualquier tarea con más detalle. Los boletos deben ser tan pequeños y específicos como sea posible. Seamos realistas: nuestro enfoque y capacidad para mantener el contexto son limitados. Cuanto más detalladamente se desglosan las tareas de desarrollo, más fácil, así que ¿por qué no tratar de hacer que las tareas difíciles sean lo más simples posible?



A medida que su proyecto evolucione, su trabajo consistirá en tomar los boletos en orden de prioridad y completar las tareas que se les asignen.



Obviamente, esta es una versión muy simplificada de la gestión de proyectos. Hay muchos otros aspectos de la verdadera gestión de proyectos, como los recursos, la planificación, los casos comerciales en competencia, etc. La gestión de proyectos en código abierto puede ser más simple y más libre. Quizás, en el mundo del desarrollo de código abierto, hay casos de gestión de proyectos en toda regla.



Desarrollo abierto



Después de haber escrito una pila de tickets, haber formado un plan de trabajo y haber entendido todos los detalles, podemos proceder al desarrollo.



Sin embargo, muchos de los factores de libertad presentes en el salvaje oeste del desarrollo abierto no deberían estar en el desarrollo de un código seguro. Puede evitar muchas dificultades utilizando herramientas de código abierto y con algo de disciplina (y tener amigos).



Soy un gran defensor de la disciplina como un medio para mejorar la calidad del trabajo (después de todo, la disciplina ocupa el sexto lugar en mi calificación en StrengthsFinder) Con suficiente disciplina para usar herramientas de código abierto, escuchar a los demás, actuar según los resultados y apegarnos a los flujos de trabajo, podemos superar muchos de los defectos que se introducen con los enfoques de vaqueros del mundo del código abierto.



En resumen, el uso de las siguientes herramientas y prácticas (que, con algunas advertencias, se pueden aplicar fácilmente en cualquier proyecto) ayuda a mejorar la calidad del código:



  1. Pruebas (o mejor aún, desarrollo impulsado por pruebas)
  2. Análisis estático
  3. Integración continua (CI / CD)
  4. Revisión de código


También daré una serie de principios a los que me adhiero al escribir código directamente:



  1. SECO
  2. Uso completo del lenguaje y las bibliotecas.
  3. El código debe ser legible y cegadoramente obvio.


Intentaré relacionar este texto con la implementación real del algoritmo de localización de END , que se completó en 10 solicitudes de fusión de mi buen colega Yunus . Está demasiado ocupado con el trabajo directo, así que puedo colgarme algunas medallas imaginarias escribiendo sobre su trabajo.



Además, para ilustrar algunos de los procesos y prácticas, daré un ejemplo de desarrollo de un algoritmo de código abierto para el controlador MPC . Fue desarrollado en un estilo un poco más suelto (vaquero) en más de 30 solicitudes de fusión , sin contar las ediciones adicionales y las mejoras realizadas después de que se completó el trabajo principal.



Pruebas



Hablemos de las pruebas.



Tuve una relación larga y difícil (según mis estándares) con las pruebas. Cuando obtuve un puesto como desarrollador y asumí el primer proyecto, no creía absolutamente que mi código funcionara y, por lo tanto, fui el primero en el equipo que comenzó a escribir al menos algunas pruebas unitarias significativas. Sin embargo, tenía toda la razón de que mi código no funcionaba.



Desde entonces, mi tumultuosa relación con las pruebas ha pasado por muchos giros y vueltas dignas de películas nocturnas. A veces me ha gustado. A veces lo odiaba todo. He escrito demasiadas pruebas. Demasiado copiar y pegar, demasiadas pruebas redundantes. Luego, las pruebas se convirtieron en un trabajo de rutina, otra parte del desarrollo. Primero escribí el código, y luego escribí pruebas para él, este era el orden de las cosas.



Ahora tengo una relación normal con las pruebas. Es una parte integral de mi flujo de trabajo, sin importar en qué aplicación trabajo.



Lo que ha cambiado para mí son las técnicas de desarrollo basadas en pruebas que comencé a usar en mi proyecto mpc.



Hablé brevemente sobre el desarrollo basado en pruebas en el texto anterior, pero aquí hay otra descripción del proceso:



  1. Desarrolle una especificación (casos de uso, requisitos, etc.).
  2. Implementar la API / arquitectura
  3. Escribir pruebas basadas en API y especificaciones de diseño; Deben fallar.
  4. Implementar lógica; las pruebas deben pasar


Hay cierta iteración en este proceso (las pruebas no fallan en los apéndices, la implementación falla las pruebas, la API puede ser incómoda, etc.), pero en general, creo que puede ser extremadamente útil.



He hablado mucho sobre la planificación antes de la implementación, y el desarrollo basado en pruebas le brinda esa oportunidad. Se señaló el primer punto. Luego piensa en la arquitectura y las API, y las asigna a casos de uso. Esto le brinda una gran oportunidad para acercarse al código, pero aún así pensar en el problema de manera más amplia. Se señaló el segundo punto.



Luego pasamos a escribir pruebas. Hay varias razones para los beneficios de escribir pruebas antes de la implementación, y creo que todas son importantes:



  1. Las pruebas deben escribirse como objetos de primera prioridad, no como complementos.
  2. , – .
  3. API , .
  4. , , , , .


En general, creo que los beneficios del desarrollo basado en pruebas son enormes, y una vez más, recomiendo a todos que al menos lo prueben.



Volvamos a Autoware. Auto. Yunus, aunque no se adhirió a los métodos de desarrollo basados ​​en pruebas, escribió pruebas para cada solicitud de fusión durante el desarrollo de END. Al mismo tiempo, el volumen del código de prueba era igual (y a veces incluso excedía) al volumen del código de implementación, y esto es bueno. En comparación, SQLite , que es probablemente el punto de referencia para las pruebas (no solo según los estándares de los proyectos de código abierto), tiene 662 veces más código de prueba que el código de implementación... En Autoware.Auto todavía no estamos del todo en esta etapa, pero si observa el historial de solicitudes de fusión relacionadas con NDT, notará que el volumen del código de prueba se arrastró lentamente hasta alcanzar el 90% de cobertura (aunque desde entonces ha caído debido a otros diseños y código externo).



Y eso es genial.



Del mismo modo, mi proyecto mpc tiene pruebas para todo, incluidas las pruebas mismas . Además, siempre realizo pruebas de regresión con cuidado para asegurarme de que el error esté solucionado y no vuelva a aparecer.



Estoy bien amigo.



Análisis estático



Muchos conceptos son curiosos porque las definiciones incluidas en ellos pueden extenderse significativamente. Por ejemplo, las pruebas van mucho más allá de las pruebas funcionales escritas a mano. De hecho, la verificación de estilo o la búsqueda de errores también se puede considerar una forma de prueba (es esencialmente una inspección, pero si se estira la definición, se puede llamar prueba).



Es "doloroso y laborioso trabajar con esas" pruebas ". Después de todo, ¿validación, validación para tabulaciones / espacios en alineación? No, gracias.



Pero una de las cosas más divertidas y valiosas de la programación es la capacidad de automatizar procesos dolorosos y que requieren mucho tiempo. Al mismo tiempo, el código puede lograr resultados más rápido y con mayor precisión que cualquier persona. ¿Qué sucede si podemos hacer lo mismo con errores y construcciones problemáticas o propensas a errores en nuestro código?



Bueno, podemos hacerlo con herramientas de análisis estático.



Escribí sobre análisis estático el tiempo suficiente en una publicación de blog anterior , por lo que no profundizaré en sus beneficios y las herramientas que puede usar.



En Autoware.Auto usamos una versión un poco más pequeña del conjunto ament_lintde nuestros amigos cercanos en ROS 2. Estas herramientas nos hacen mucho bien, pero quizás lo más importante es que nuestro código se formatea automáticamente para eliminar las disputas de estilo: las herramientas imparciales nos dicen qué está bien y qué está mal. Si está interesado, notaré que el formato clang es más estricto que no incrustar .



En el proyecto mpc, fui un poco más lejos. En él, utilicé la bandera Weverything del compilador Clang, además de todas las advertencias de clang-tidy y el analizador estático Clang. Sorprendentemente, el desarrollo comercial requirió varias opciones para ser deshabilitado (debido a advertencias redundantes y confusión conceptual) Al interactuar con el código externo, tuve que deshabilitar muchas comprobaciones, ya que generaban ruidos innecesarios.



Finalmente, me di cuenta de que el uso de un análisis estático extenso no interfiere en gran medida con el desarrollo normal (en el caso de escribir código nuevo y después de pasar un cierto punto en la curva de aprendizaje)



Es difícil cuantificar el valor del análisis estático, especialmente si lo usa desde el principio. El punto es que es difícil adivinar si el error existió antes de la introducción del análisis estático o no.



Sin embargo, creo que usar advertencias y análisis estático es una de esas cosas en las que, incluso cuando se usa correctamente, uno no puede estar seguro de que hicieron algo en absoluto.. En otras palabras, no puede estar seguro sobre el valor de un analizador estático cuando está encendido, pero diablos, notará que no está allí de inmediato.



CI / CD



Por mucho que me encanten las pruebas rigurosas y el análisis de código estático / dinámico, todas las pruebas y comprobaciones no tienen valor si no se ejecutan. CI puede enfrentar estos desafíos con una sobrecarga mínima.



Creo que todos están de acuerdo en que tener una infraestructura de CI / CD es una parte esencial del desarrollo moderno, así como también usar un sistema de control de versiones y tener estándares de desarrollo (al menos, guías de estilo). Sin embargo, el valor de una buena canalización de CI / CD es que sus operaciones deben ser reproducibles.



La canalización de CI / CD debe, como mínimo, construir código y ejecutar pruebas antes de insertar el código en su repositorio. Después de todo, nadie quiere ser ese tipo (o niña o persona) que rompió una asamblea o algún tipo de prueba y tiene que arreglar todo de forma rápida y vergonzosa. Los CI (y, por lo tanto, sus queridos ingenieros de DevOps) lo protegen de esta vergüenza.



Pero CI puede hacer mucho más por ti.



Con una sólida canalización de CI, puede probar cualquier número de combinaciones de sistemas operativos, compiladores y arquitecturas (con algunas limitaciones, considerando las pruebas de combinación ). También puede realizar compilaciones, ejecutar pruebas y otras operaciones que pueden ser demasiado intensivas en recursos o engorrosas para que un desarrollador las realice manualmente. No puedes saltar sobre tu cabeza.



Volviendo a la declaración original, tener un canal de CI / CD (que usamos en Autoware.Auto ) en su proyecto de código abierto ayudará a impulsar el desarrollo inmanejable. El código no podrá ingresar al proyecto si no crea ni pasa las pruebas. Si se adhiere a una estricta disciplina de prueba, siempre puede estar seguro de que el código funciona.



En Autoware.Auto, CI:



  1. Recoge el código
  2. Ejecuta pruebas (estilo, comprobaciones de linter, pruebas funcionales).
  3. Mide la cobertura de prueba
  4. Comprueba que el código esté documentado




A su vez, mi CI compiló rápidamente en el proyecto mpc:



  1. Recoge el código
  2. Realiza un escaneo (análisis estático de Clang)
  3. Ejecuta pruebas (pero no detiene CI si las pruebas fallan).


Una tubería de CI creada por un ingeniero experimentado de DevOps (como nuestro J.P. Samper o Hao Peng !) Puede hacer mucho más. Así que aprecia a tus ingenieros de DevOps. Nos hacen la vida (como desarrolladores) mucho más fácil.



Revisión de código



Los puntos de referencia, analizadores y CI son geniales. Puede ejecutar pruebas, analizar todo y asegurarse de que estas pruebas se realicen con CI, ¿verdad?



Lamentablemente no.



Una vez más, todas las pruebas en el mundo no tienen valor si son malas. Entonces, ¿cómo se asegura de que sus pruebas sean buenas?



Lamentablemente, no tengo respuestas mágicas. De hecho, vuelvo a la vieja técnica de ingeniería, la revisión por pares. En particular, a la revisión de código.



Generalmente se cree que dos cabezas son mejores que una. De hecho, yo diría que este concepto está respaldado no solo por la literatura, sino también por la teoría.



Conjunto de métodosen el aprendizaje automático ilustra esta teoría. Se cree que usar un conjunto de métodos es una manera rápida y fácil de mejorar el rendimiento de los modelos estadísticos (el conocido método de refuerzo es un ejemplo ). Del mismo modo, desde un punto de vista puramente estadístico, la varianza es menor (con supuestos) cuantas más muestras tenga. En otras palabras, es más probable que esté más cerca de la verdad si conecta a más empleados.



Puede probar esta técnica con un ejemplo en vivo haciendo un ejercicio de trabajo en equipo . Una versión menos divertida podría implicar adivinar estadísticas aleatorias individualmente y en grupo.



Dejando a un lado la teoría y el trabajo en equipo, la revisión de código es una herramienta importante y poderosa. Como era de esperar, la revisión del código es una parte integral de cualquier proceso de desarrollo profesional, e incluso lo recomienda la norma ISO 26262.



Todo esto sugiere que siempre existe el peligro de que un niño tenga siete niñeras. Además, a veces la revisión de código puede causar ciertas dificultades.



Sin embargo, creo que las revisiones de código pueden ser agradables e indoloras si tanto el revisor como el revisado por pares recuerdan lo siguiente:



  1. No eres tu código.
  2. Estás hablando con otra persona.
  3. Ser cortés
  4. Todos están trabajando hacia el mismo objetivo; la revisión de código no representa ninguna competencia (aunque a veces ocurre en la programación )


Muchas personas más inteligentes y agradables que yo han escrito sobre cómo hacer las revisiones de código correctamente, y los invito a echar un vistazo a su trabajo . Lo último que puedo decir es que debe hacer revisiones de código si desea que su código sea más confiable.



SECO



Entré en detalles sobre los procesos y herramientas que se pueden usar para crear un entorno de desarrollo: controles y herramientas que realizan controles y se aseguran de que el código sea lo suficientemente bueno.



A continuación, me gustaría pasar a una charla rápida sobre la destreza de programación y compartir algunas ideas sobre los procesos y la intención detrás de escribir líneas de código individuales.



Hay un par de conceptos que me han ayudado a mejorar mucho mi código. Uno de esos conceptos era la capacidad de recordar la intención, la semántica y la legibilidad, de lo que hablaré un poco más adelante. Otra es la comprensión de la POO y la separación de las preocupaciones . La última idea importante es SECO ( No te repitas ) o el principio "No te repitas".



DRY es lo que se enseña en la escuela y, como con muchas otras cosas, ponemos este pensamiento en el estante más alejado y no le damos mucha importancia fuera de los exámenes (al menos para mí). Pero, como es el caso con muchas otras cosas en la escuela, no aprendemos nada así. De hecho, esta es una buena práctica.



En pocas palabras, si te encuentras copiando y pegando código con frecuencia, o escribiendo código muy similar con frecuencia, esta es una muy buena indicación de que el código repetible debería convertirse en una función o parte de alguna abstracción.



Pero DRY va más allá de verificar que algún código se debe mover a una función. Este concepto también puede servir como base para algunas decisiones arquitectónicas.



Aunque este enfoque se cruza con algunos conceptos arquitectónicos (como alias, conectividad y separación de preocupaciones), un ejemplo de cómo DRY se aplica a la arquitectura se puede ver en mi proyecto mpc. Durante el desarrollo del controlador mpc, noté que tendría que duplicar algún código si alguna vez escribía otro controlador. Se trata de código repetitivo para el seguimiento de estado, publicaciones, suscripciones, conversiones y similares. En otras palabras, parecía que era una tarea separada del controlador mpc.



Esta fue una buena indicación de que debería separar los diseños generales y la funcionalidad en una clase separada . La recuperación de la inversión fue doble: el controlador mpc está 100% enfocado en el código relacionado con mpc, y conEl módulo asociado es solo una plantilla de configuración. En otras palabras, debido a abstracciones arquitectónicas, no tengo que reescribir todo cuando trabajo con un controlador diferente.



El mundo está formado por tonos de gris, por lo que estas decisiones de diseño deben profundizarse con cuidado y la mentalidad correcta. De lo contrario, puede ir demasiado lejos y comenzar a crear abstracciones donde no sean necesarias. Sin embargo, si el desarrollador es consciente de los conceptos que modelan estas abstracciones, DRY es una herramienta poderosa para dar forma a las decisiones arquitectónicas. En mi opinión, DRY es el concepto principal para mantener su código limpio y denso.



Después de todo, uno de los beneficios clave del código es su capacidad para realizar tareas repetitivas, entonces ¿por qué no cambiar la repetición a funciones y clases bien diseñadas?



Uso completo del lenguaje y la biblioteca.



DRY, en mi opinión, es un concepto tan importante y generalizado que este punto es realmente solo una continuación de la conversación DRY.



Si su idioma admite algo, entonces generalmente debe usar la implementación en línea, a menos que tenga una buena razón para optar por no participar. Y C ++ tiene muchas cosas integradas .



La programación es una habilidad y hay una gran diferencia en los niveles de habilidad. Solo pude vislumbrar cuán alta es la montaña de esta habilidad, y en general encuentro que las personas que crean estándares son mejores para implementar patrones comunes que yo.



Se puede hacer un argumento similar para la funcionalidad de las bibliotecas (aunque tal vez no sea tan categóricamente). Alguien más ya ha hecho lo mismo, y probablemente a un buen nivel, por lo que no hay razón para reinventar la rueda.



Sin embargo, este, como muchos otros, este párrafo es una recomendación, y no una regla rígida y urgente para aplicar. Si bien no vale la pena reinventar la rueda, y aunque las implementaciones estándar son generalmente muy buenas, no tiene sentido tratar de exprimir una pieza cuadrada en un agujero redondo. Piensa con la cabeza.



Código legible



El último concepto que me ayudó a mejorar mi habilidad de programación fue que la programación no se trata tanto de escribir código como de comunicación. Si no es comunicación con otros desarrolladores, comunícate contigo mismo desde el futuro. Por supuesto, debe pensar en la memoria, las matemáticas y la complejidad de Big O, pero una vez que lo haga, debe comenzar a pensar en la intención, la semántica y la claridad.



Hay un libro muy famoso y ampliamente recomendado sobre este tema, Clean Code , por lo que no puedo agregar mucho sobre este tema. Aquí hay una lista de parte de la información general a la que me refiero cuando escribo código y hago revisiones de código:



  1. Intenta mantener tus clases claras y enfocadas:

    • Minimiza enganches
    • ()



      • const, noexcept? ? (, )




    • , (, , ).
    • (, )
    • .
  2. -



    • «», , .
    • (, ).
    • ( ) ().
  3. ? ()



    • , ().
    • , , , (, ).


Otro gran recurso que aborda este tipo de problema son las Directrices básicas de ISO C ++ .



Reiteraré que ninguno de estos principios es revolucionario, nuevo o único, pero si la redacción de los principios tiene valor (o alguien dirá "aha" al leer ), entonces no desperdicié bits y tráfico para escribir esta publicación. ...



Mirando hacia atrás



Estas fueron algunas de las herramientas, principios y procesos que utilizamos para desarrollar e implementar el algoritmo de localización NDT, así como cuando trabajamos en el controlador MPC. Se hizo mucho trabajo, fue divertido, no es tan interesante hablar de ello.



En general, hicimos un gran uso de las herramientas y prácticas que mencioné, pero no éramos perfectos.



Entonces, por ejemplo, cuando trabajamos en el END, no seguimos los modismos del desarrollo basado en pruebas (¡aunque tenemos todo perfectamente probado!). A su vez, seguí técnicas de desarrollo basadas en pruebas en MPC, pero este proyecto no se benefició del CI más potente integrado en Autoware.Auto. Además, el proyecto MPC no era público y, por lo tanto, no recibió los beneficios de una revisión del código.



Ambos proyectos podrían beneficiarse de la introducción de análisis estático, pruebas más detalladas y más comentarios. Sin embargo, estamos hablando de proyectos creados por una persona, por lo que creo que las pruebas realizadas y los comentarios recibidos son suficientes. Cuando se trata de análisis estático, las formas mejores y más cercanas generalmente caen en el ámbito de los intereses de desarrollo de productos y se alejan de la comunidad de desarrolladores de código abierto (aunque pueden aparecer ideas interesantes en el horizonte ).



No tengo nada que decir sobre el desarrollo simultáneo de dos algoritmos: trabajamos lo mejor que pudimos, cumpliendo con los principios que describí anteriormente.



Creo que hemos hecho un excelente trabajo descomponiendo grandes problemas en piezas más pequeñas (aunque el componente MR en el algoritmo NDT podría ser más pequeño), y hemos realizado pruebas exhaustivas. Creo que los resultados preliminares hablan por sí mismos.



Movimiento hacia adelante



Después de la implementación, es hora de la integración. Es necesario conectarse a un sistema más grande con sus propios componentes complejos. Este sistema tomará su entrada, la asimilará y producirá los resultados de su algoritmo. La integración es quizás la parte más difícil del desarrollo de un algoritmo, ya que necesita realizar un seguimiento del plan general del sistema y solucionar problemas de bajo nivel. Cualquier error en cualquiera de sus muchas líneas de código puede evitar que su algoritmo se integre.



Cubriré esto en la tercera y última publicación de esta serie.



Como vista previa, diré que durante el proceso de desarrollo, no se encontró un solo gran error durante el uso y la integración del controlador mpc. Es cierto que hubo algunos problemas al escribir guiones , ensamblar,pruebas , se omitió la validación de datos de entrada y también hubo problemas con la incompatibilidad de la configuración de QoS , pero no había nada terrible en el código.



De hecho, fue capaz de ejecutarse (omitiendo las incompatibilidades de QoS y configurando opciones) casi desde el primer momento .



Lo mismo se aplica al algoritmo NDT, que se encontró con una serie de problemas menores, como la inestabilidad de la covarianza , el error al buscar cadenas en el código existente y los mapas alineados incorrectamente. De todos modos, también fue capaz de trabajar fuera de la caja .



No está mal para productos diseñados para que todos los vean.



Suscríbase a los canales:

@TeslaHackers — Tesla-, Tesla

@AutomotiveRu — ,







imagen



- automotive . 2500 , 650 .



, , . ( 30, ), -, -, - (DSP-) .



, . , , , . , automotive. , , .


:






All Articles